How can I print result of Hash as Hex?

I have this code

test "hash" {
    const print = @import("std").debug.print;
    const Sha256 = std.crypto.hash.sha2.Sha256;
    var sha256 = Sha256.init(.{});
    sha256.update("Hello Zig");

    const result = sha256.finalResult();
    print("hash = {any}\n", .{result});
    try std.testing.expect(true);
}

And this prints out

1/1 main.test.hash...hash = { 183, 1, 163, 9, 115, 145, 245, 17, 24, 123, 13, 198, 11, 35, 242, 192, 5, 58, 186, 238, 166, 209, 248, 225, 225, 150, 206, 39, 172, 180, 55, 45 }
OK
All 1 tests passed.

How do I get this binary array as hex string?

When I run the hash via the terminal I get the following

echo -n "Hello Zig" | shasum -a 256
b701a3097391f511187b0dc60b23f2c0053abaeea6d1f8e1e196ce27acb4372d  -

I tried formatting with X, but this is what I got instead

main.test.hash...hash = { B7, 1, A3, 9, 73, 91, F5, 11, 18, 7B, D, C6, B, 23, F2, C0, 5, 3A, BA, EE, A6, D1, F8, E1, E1, 96, CE, 27, AC, B4, 37, 2D }
OK
All 1 tests passed.

Which is basically what I want, only that I am not sure how to get the result formatted as a string instead

2 Likes

Looking at the source in the standard library we can see that print calls to std.fmt.formatInt for its hexadecimal formatting. We can call this directly to create our own hex-print functionality.

pub fn main() !void {
    const str = "Hello world!";
    const writer = std.io.getStdErr().writer();

    for (str) |char| {
        try std.fmt.formatInt(char, 16, .lower, .{}, writer);
    }
}

Outputs:

48656c6c6f20776f726c6421
1 Like

You can use std.fmt.bytesToHex.

test "hash" {
    const print = @import("std").debug.print;
    const Sha256 = std.crypto.hash.sha2.Sha256;
    var sha256 = Sha256.init(.{});
    sha256.update("Hello Zig");

    const result = sha256.finalResult();
    const hex = std.fmt.bytesToHex(result, .upper);
    print("hash = {s}\n", .{hex});
    try std.testing.expect(true);
}

And welcome to ziggit :slight_smile:

8 Likes

Hi dimdin

Your code did not compile on zig 13 (It’s become the latest stable, quite recently). What version did you use?

I got the following error

error: use of undeclared identifier 'std'
  const Sha256 = std.crypto.hash.sha2.Sha256;

Looks like

const print = @import("std").debug.print;

is a no no and has to be

const std = @import("std");
const print = std.debug.print;

A part from, that nice job. :slight_smile:

//echo -n "Hello Zig" | shasum -a 256
//b701a3097391f511187b0dc60b23f2c0053abaeea6d1f8e1e196ce27acb4372d 

test "hash" {
    //const print = @import("std").debug.print;
    const std = @import("std");
    const print = std.debug.print;

    const Sha256 = std.crypto.hash.sha2.Sha256;
    var sha256 = Sha256.init(.{});
    sha256.update("Hello Zig");

    const result = sha256.finalResult();
    const hex = std.fmt.bytesToHex(result, .lower);
    print("hash from the code = {s}\n", .{hex});

    print("hash from shasum   = b701a3097391f511187b0dc60b23f2c0053abaeea6d1f8e1e196ce27acb4372d \n", .{});

    try std.testing.expect(true);
}
zig test try_013_hash_01_simple.zig
hash from the code = b701a3097391f511187b0dc60b23f2c0053abaeea6d1f8e1e196ce27acb4372d
hash from shasum   = b701a3097391f511187b0dc60b23f2c0053abaeea6d1f8e1e196ce27acb4372d
All 1 tests passed.

All the best

2 Likes

Another function that can be helpful here is std.fmt.fmtSliceHexLower (or Upper, as desired), which returns a formatter that formats into the same lowercase hex representation:

const std = @import("std");

test "hash" {
    const print = @import("std").debug.print;
    const Sha256 = std.crypto.hash.sha2.Sha256;
    var sha256 = Sha256.init(.{});
    sha256.update("Hello Zig");

    const result = sha256.finalResult();
    print("hash = {}\n", .{std.fmt.fmtSliceHexLower(&result)});
    try std.testing.expect(true);
}

One nice thing about this function is it accepts a slice rather than an array, so you can use it even if the length of your input isn’t known at comptime. However, it’s also limited to use with std.fmt.

2 Likes