authorgravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2026-07-18 13:34:34+02:00
committergravatar for 124872+jedisct1@users.noreply.github.comFrank Denis <124872+jedisct1@users.noreply.github.com> 2026-07-18 13:34:34+02:00
logd5181a9c9bacc1c11930bc3581f9a44c49c27e01
tree417fc2c9fc612e9cf80692de6c2544d66a42f6cf
parent873b762f4513a1e6bb72a6902c8a0f7e217e6da1
parent6c7a5da5a65b02cb7cebac7453c64c8f2d7a8afd

Merge pull request 'std.crypto.Blake3: fix hashParallel digest for non-aligned inputs' (#36107) from jedisct1/zig:blake3fix into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/36107

1 files changed, 44 insertions(+), 10 deletions(-)

lib/std/crypto/blake3.zig+44-10
...@@ -1004,7 +1004,10 @@ pub const Blake3 = struct {...@@ -1004,7 +1004,10 @@ pub const Blake3 = struct {
1004 return hash(b, out, options);1004 return hash(b, out, options);
1005 }1005 }
10061006
1007 const cvs = try allocator.alloc([8]u32, num_full_chunks);1007 const remaining_bytes = b.len % chunk_length;
1008 const num_leaves = @divCeil(b.len, chunk_length);
1009
1010 const cvs = try allocator.alloc([8]u32, num_leaves);
1008 defer allocator.free(cvs);1011 defer allocator.free(cvs);
10091012
1010 // Process chunks in parallel1013 // Process chunks in parallel
...@@ -1028,8 +1031,16 @@ pub const Blake3 = struct {...@@ -1028,8 +1031,16 @@ pub const Blake3 = struct {
1028 }1031 }
1029 try group.await(io);1032 try group.await(io);
10301033
1034 if (remaining_bytes > 0) {
1035 var chunk_state = ChunkState.init(key_words, flags);
1036 chunk_state.chunk_counter = num_full_chunks;
1037 chunk_state.update(b[num_full_chunks * chunk_length ..]);
1038 const output = chunk_state.output();
1039 cvs[num_full_chunks] = output.chainingValue();
1040 }
1041
1031 // Build Merkle tree in parallel layers using ping-pong buffers1042 // Build Merkle tree in parallel layers using ping-pong buffers
1032 const max_intermediate_size = (num_full_chunks + 1) / 2;1043 const max_intermediate_size = @divCeil(num_leaves, 2);
1033 const buffer0 = try allocator.alloc([8]u32, max_intermediate_size);1044 const buffer0 = try allocator.alloc([8]u32, max_intermediate_size);
1034 defer allocator.free(buffer0);1045 defer allocator.free(buffer0);
1035 const buffer1 = try allocator.alloc([8]u32, max_intermediate_size);1046 const buffer1 = try allocator.alloc([8]u32, max_intermediate_size);
...@@ -1064,14 +1075,6 @@ pub const Blake3 = struct {...@@ -1064,14 +1075,6 @@ pub const Blake3 = struct {
1064 // Finalize remaining small tree sequentially1075 // Finalize remaining small tree sequentially
1065 var hasher = init_internal(key_words, flags);1076 var hasher = init_internal(key_words, flags);
1066 for (current_level, 0..) |cv, i| hasher.pushCv(cv, i);1077 for (current_level, 0..) |cv, i| hasher.pushCv(cv, i);
1067
1068 hasher.chunk.chunk_counter = num_full_chunks;
1069 const remaining_bytes = b.len % chunk_length;
1070 if (remaining_bytes > 0) {
1071 hasher.chunk.update(b[num_full_chunks * chunk_length ..]);
1072 hasher.mergeCvStack(hasher.chunk.chunk_counter);
1073 }
1074
1075 hasher.final(out);1078 hasher.final(out);
1076 }1079 }
10771080
...@@ -1453,3 +1456,34 @@ test "BLAKE3 parallel vs sequential" {...@@ -1453,3 +1456,34 @@ test "BLAKE3 parallel vs sequential" {
1453 try std.testing.expectEqualSlices(u8, &expected_keyed, &actual_keyed);1456 try std.testing.expectEqualSlices(u8, &expected_keyed, &actual_keyed);
1454 }1457 }
1455}1458}
1459
1460test "BLAKE3 parallel with partial trailing chunk" {
1461 const allocator = std.testing.allocator;
1462 const io = std.testing.io;
1463
1464 const test_sizes = [_]usize{
1465 3072 * 1024,
1466 3072 * 1024 + 1,
1467 3073 * 1024 + 1,
1468 3074 * 1024 + 1,
1469 3075 * 1024,
1470 3075 * 1024 + 1,
1471 3075 * 1024 + 1023,
1472 3077 * 1024 + 1,
1473 4095 * 1024 + 1,
1474 };
1475
1476 for (test_sizes) |size| {
1477 const input = try allocator.alloc(u8, size);
1478 defer allocator.free(input);
1479 for (input, 0..) |*byte, i| byte.* = @truncate(i);
1480
1481 var expected: [32]u8 = undefined;
1482 Blake3.hash(input, &expected, .{});
1483
1484 var actual: [32]u8 = undefined;
1485 try Blake3.hashParallel(input, &actual, .{}, allocator, io);
1486
1487 try std.testing.expectEqualSlices(u8, &expected, &actual);
1488 }
1489}