zig icon indicating copy to clipboard operation
zig copied to clipboard

stage1: Incorrect SHA-256 hash value computed at comptime

Open topolarity opened this issue 3 years ago • 1 comments

Zig Version

0.10.0-dev.4622+f28e4e03e

Steps to Reproduce and Observed Behavior

const std = @import("std");
const Hasher = std.crypto.hash.sha2.Sha256;
const testfile = @embedFile("testfile");
test {
    comptime
    {
        @setEvalBranchQuota(100_000_000);
        var digest: [Hasher.digest_length]u8 = undefined;
        _ = Hasher.hash(testfile, &digest, .{});
        //std.log.err("digest: {}", .{std.fmt.fmtSliceHexLower(digest[0..])});
        @compileLog(digest);
    }
}

"testfile" is a 1KB file of random bytes generated using dd if=/dev/urandom of=testfile bs=1K count=1

Computes a hash of all zeros:

./build/stage3/bin/zig test testct.zig --zig-lib-dir lib  -fstage1
Semantic Analysis [66/90] | [32]u8{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
./testct.zig:11:9: error: found compile log statement
        @compileLog(digest);
        ^

Expected Behavior

Should compute the same hash as at runtime: (74b7d714d7c401efbb6a4c276101f8e1e93e74962310744c180bc9352fded2d7 for my testfile)

topolarity avatar Oct 28 '22 16:10 topolarity

This:

for (rr) |s, j| {
    mem.writeIntBig(u32, out[4 * j ..][0..4], s);
}

or its equivalent:

for (rr) |s, j| {
     @ptrCast(*align(1) u32, out[4 * j ..]).* = mem.nativeToBig(u32, s);
}

doesn't properly fill the output buffer when using comptime.

It can be worked around by using a temporary buffer:

--- lib/std/crypto/sha2.zig	2022-10-29 17:11:12
+++ /opt/zig/lib/zig/std/crypto/sha2.zig	2022-11-01 11:00:16
@@ -171,7 +171,9 @@
             const rr = d.s[0 .. params.digest_bits / 32];
 
             for (rr) |s, j| {
-                mem.writeIntBig(u32, out[4 * j ..][0..4], s);
+                var t: [4]u8 = undefined;
+                mem.writeIntBig(u32, &t, s);
+                mem.copy(u8, out[4 * j ..], &t);
             }
         }
 
@@ -650,7 +652,9 @@
             const rr = d.s[0 .. params.digest_bits / 64];
 
             for (rr) |s, j| {
-                mem.writeIntBig(u64, out[8 * j ..][0..8], s);
+                var t: [8]u8 = undefined;
+                mem.writeIntBig(u64, &t, s);
+                mem.copy(u8, out[8 * j ..], &t);
             }
         }
 

But this is certainly not a proper fix, and it probably affects other things as well.

jedisct1 avatar Nov 01 '22 10:11 jedisct1