#include <openssl/evp.h>
#include <openssl/objects.h>
#include <openssl/err.h>
#include <stdio.h>
#include <stdlib.h>

void handleErrors(void)
{
    ERR_print_errors_fp(stderr);
    abort();
}

void sm3_file_hash(const char *file_path, unsigned char *output)
{
    FILE *file = fopen(file_path, "rb");
    if (file == NULL)
    {
        perror("Error opening file");
        handleErrors();
    }

    EVP_MD_CTX *mdctx;
    const EVP_MD *md;
    unsigned int md_len;
    unsigned char buffer[1024];

    md = EVP_sm3(); // 使用 SM3 算法
    mdctx = EVP_MD_CTX_new();
    if (mdctx == NULL)
        handleErrors();

    if (1 != EVP_DigestInit_ex(mdctx, md, NULL))
        handleErrors();

    size_t bytes;
    while ((bytes = fread(buffer, 1, sizeof(buffer), file)) != 0)
    {
        if (1 != EVP_DigestUpdate(mdctx, buffer, bytes))
            handleErrors();
    }

    if (1 != EVP_DigestFinal_ex(mdctx, output, &md_len))
        handleErrors();

    fclose(file);
    EVP_MD_CTX_free(mdctx);
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        fprintf(stderr, "Usage: %s <file_path>\n", argv[0]);
        return 1;
    }

    const char *file_path = argv[1];
    unsigned char hash_value[EVP_MAX_MD_SIZE];
    int i;

    sm3_file_hash(file_path, hash_value);

    printf("SM3 Hash Value: ");
    for (i = 0; i < EVP_MD_size(EVP_sm3()); i++)
        printf("%02x", hash_value[i]);
    printf("\n");

    return 0;
}
