Task: SHA-256 Merkle tree

C: #include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

guchar* sha256_merkle_tree(FILE* in, size_t block_size) {
    gchar* buffer = g_malloc(block_size);
    GPtrArray* hashes = g_ptr_array_new_with_free_func(g_free);
    gssize digest_length = g_checksum_type_get_length(G_CHECKSUM_SHA256);
    GChecksum* checksum = g_checksum_new(G_CHECKSUM_SHA256);
    size_t bytes;
    while ((bytes = fread(buffer, 1, block_size, in)) > 0) {
        g_checksum_reset(checksum);
        g_checksum_update(checksum, (guchar*)buffer, bytes);
        gsize len = digest_length;
        guchar* digest = g_malloc(len);
        g_checksum_get_digest(checksum, digest, &len);
        g_ptr_array_add(hashes, digest);
    }
    g_free(buffer);
    guint hashes_length = hashes->len;
    if (hashes_length == 0) {
        g_ptr_array_free(hashes, TRUE);
        g_checksum_free(checksum);
        return NULL;
    }
    while (hashes_length > 1) {
        guint j = 0;
        for (guint i = 0; i < hashes_length; i += 2, ++j) {
            guchar* digest1 = g_ptr_array_index(hashes, i);
            guchar* digest_out = g_ptr_array_index(hashes, j);
            if (i + 1 < hashes_length) {
                guchar* digest2 = g_ptr_array_index(hashes, i + 1);
                g_checksum_reset(checksum);
                g_checksum_update(checksum, digest1, digest_length);
                g_checksum_update(checksum, digest2, digest_length);
                gsize len = digest_length;
                g_checksum_get_digest(checksum, digest_out, &len);
            } else {
                memcpy(digest_out, digest1, digest_length);
            }
        }
        hashes_length = j;
    }
    guchar* result = g_ptr_array_steal_index(hashes, 0);
    g_ptr_array_free(hashes, TRUE);
    g_checksum_free(checksum);
    return result;
}

int main(int argc, char** argv) {
    if (argc != 2) {
        fprintf(stderr, "usage: %s filename\n", argv[0]);
        return EXIT_FAILURE;
    }
    FILE* in = fopen(argv[1], "rb");
    if (in) {
        guchar* digest = sha256_merkle_tree(in, 1024);
        fclose(in);
        if (digest) {
            gssize length = g_checksum_type_get_length(G_CHECKSUM_SHA256);
            for (gssize i = 0; i < length; ++i)
                printf("%02x", digest[i]);
            printf("\n");
            g_free(digest);
        }
    } else {
        perror(argv[1]);
        return EXIT_FAILURE;
    }
    return EXIT_SUCCESS;
}





Java: import java.io.*;
import java.security.*;
import java.util.*;

public class SHA256MerkleTree {
    public static void main(String[] args) {
        if (args.length != 1) {
            System.err.println("missing file argument");
            System.exit(1);
        }
        try (InputStream in = new BufferedInputStream(new FileInputStream(args[0]))) {
            byte[] digest = sha256MerkleTree(in, 1024);
            if (digest != null)
                System.out.println(digestToString(digest));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static String digestToString(byte[] digest) {
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < digest.length; ++i)
            result.append(String.format("%02x", digest[i]));
        return result.toString();
    }

    private static byte[] sha256MerkleTree(InputStream in, int blockSize) throws Exception {
        byte[] buffer = new byte[blockSize];
        int bytes;
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        List<byte[]> digests = new ArrayList<>();
        while ((bytes = in.read(buffer)) > 0) {
            md.reset();
            md.update(buffer, 0, bytes);
            digests.add(md.digest());
        }
        int length = digests.size();
        if (length == 0)
            return null;
        while (length > 1) {
            int j = 0;
            for (int i = 0; i < length; i += 2, ++j) {
                byte[] digest1 = digests.get(i);
                if (i + 1 < length) {
                    byte[] digest2 = digests.get(i + 1);
                    md.reset();
                    md.update(digest1);
                    md.update(digest2);
                    digests.set(j, md.digest());
                } else {
                    digests.set(j, digest1);
                }
            }
            length = j;
        }
        return digests.get(0);
    }
}