| author | |
| committer | |
| log | 4b593a6c24797484e68a668818736b0f6a8d81a2 |
| tree | d140c424346e4dd46688c00023d9a3b39ee99a1f |
| parent | 2e8f8afc832112ad03125a403f66d7d9058eeac8 |
| signature |
It was not obvious that the KT128/KT256 customization string can be
used to set a key, or what it was designed to be used for at all.
Also properly use key_length and not digest_length for the BLAKE3
key length (no practical changes as they are both 32, but that was
confusing).
Remove unneeded simd_degree copies by the way, and that doesn't need
to be in the public interface.2 files changed, 45 insertions(+), 15 deletions(-)
lib/std/crypto/blake3.zig+7-9| ... | @@ -12,8 +12,8 @@ const Vec16 = @Vector(16, u32); | ... | @@ -12,8 +12,8 @@ const Vec16 = @Vector(16, u32); |
| 12 | const chunk_length = 1024; | 12 | const chunk_length = 1024; |
| 13 | const max_depth = 54; | 13 | const max_depth = 54; |
| 14 | 14 | ||
| 15 | pub const simd_degree = std.simd.suggestVectorLength(u32) orelse 1; | 15 | const simd_degree = std.simd.suggestVectorLength(u32) orelse 1; |
| 16 | pub const max_simd_degree = simd_degree; | 16 | const max_simd_degree = simd_degree; |
| 17 | const max_simd_degree_or_2 = if (max_simd_degree > 2) max_simd_degree else 2; | 17 | const max_simd_degree_or_2 = if (max_simd_degree > 2) max_simd_degree else 2; |
| 18 | 18 | ||
| 19 | /// Threshold for switching to parallel processing. | 19 | /// Threshold for switching to parallel processing. |
| ... | @@ -502,9 +502,7 @@ fn hashManySimd( | ... | @@ -502,9 +502,7 @@ fn hashManySimd( |
| 502 | var out_ptr = out.ptr; | 502 | var out_ptr = out.ptr; |
| 503 | var cnt = counter; | 503 | var cnt = counter; |
| 504 | 504 | ||
| 505 | const simd_deg = comptime simd_degree; | 505 | if (simd_degree >= 16) { |
| 506 | |||
| 507 | if (comptime simd_deg >= 16) { | ||
| 508 | while (remaining >= 16) { | 506 | while (remaining >= 16) { |
| 509 | const sixteen_inputs = [16][*]const u8{ | 507 | const sixteen_inputs = [16][*]const u8{ |
| 510 | inp[0], inp[1], inp[2], inp[3], | 508 | inp[0], inp[1], inp[2], inp[3], |
| ... | @@ -525,7 +523,7 @@ fn hashManySimd( | ... | @@ -525,7 +523,7 @@ fn hashManySimd( |
| 525 | } | 523 | } |
| 526 | } | 524 | } |
| 527 | 525 | ||
| 528 | if (comptime simd_deg >= 8) { | 526 | if (simd_degree >= 8) { |
| 529 | while (remaining >= 8) { | 527 | while (remaining >= 8) { |
| 530 | const eight_inputs = [8][*]const u8{ | 528 | const eight_inputs = [8][*]const u8{ |
| 531 | inp[0], inp[1], inp[2], inp[3], | 529 | inp[0], inp[1], inp[2], inp[3], |
| ... | @@ -544,7 +542,7 @@ fn hashManySimd( | ... | @@ -544,7 +542,7 @@ fn hashManySimd( |
| 544 | } | 542 | } |
| 545 | } | 543 | } |
| 546 | 544 | ||
| 547 | if (comptime simd_deg >= 4) { | 545 | if (simd_degree >= 4) { |
| 548 | while (remaining >= 4) { | 546 | while (remaining >= 4) { |
| 549 | const four_inputs = [4][*]const u8{ | 547 | const four_inputs = [4][*]const u8{ |
| 550 | inp[0], | 548 | inp[0], |
| ... | @@ -571,7 +569,7 @@ fn hashManySimd( | ... | @@ -571,7 +569,7 @@ fn hashManySimd( |
| 571 | } | 569 | } |
| 572 | 570 | ||
| 573 | fn hashMany(inputs: [][*]const u8, num_inputs: usize, blocks: usize, key: [8]u32, counter: u64, increment_counter: bool, flags: Flags, flags_start: Flags, flags_end: Flags, out: []u8) void { | 571 | fn hashMany(inputs: [][*]const u8, num_inputs: usize, blocks: usize, key: [8]u32, counter: u64, increment_counter: bool, flags: Flags, flags_start: Flags, flags_end: Flags, out: []u8) void { |
| 574 | if (comptime max_simd_degree >= 4) { | 572 | if (max_simd_degree >= 4) { |
| 575 | hashManySimd(inputs, num_inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); | 573 | hashManySimd(inputs, num_inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); |
| 576 | } else { | 574 | } else { |
| 577 | hashManyPortable(inputs, num_inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); | 575 | hashManyPortable(inputs, num_inputs, blocks, key, counter, increment_counter, flags, flags_start, flags_end, out); |
| ... | @@ -909,7 +907,7 @@ pub const Blake3 = struct { | ... | @@ -909,7 +907,7 @@ pub const Blake3 = struct { |
| 909 | pub const digest_length = 32; | 907 | pub const digest_length = 32; |
| 910 | pub const key_length = 32; | 908 | pub const key_length = 32; |
| 911 | 909 | ||
| 912 | pub const Options = struct { key: ?[digest_length]u8 = null }; | 910 | pub const Options = struct { key: ?[key_length]u8 = null }; |
| 913 | pub const KdfOptions = struct {}; | 911 | pub const KdfOptions = struct {}; |
| 914 | 912 | ||
| 915 | key: [8]u32, | 913 | key: [8]u32, |
lib/std/crypto/kangarootwelve.zig+38-6| ... | @@ -840,7 +840,21 @@ fn KTHash( | ... | @@ -840,7 +840,21 @@ fn KTHash( |
| 840 | /// The block length, or rate, in bytes. | 840 | /// The block length, or rate, in bytes. |
| 841 | pub const block_length = Variant.rate; | 841 | pub const block_length = Variant.rate; |
| 842 | 842 | ||
| 843 | /// Options for KangarooTwelve can include a customization string for domain separation. | 843 | /// Configuration options for KangarooTwelve hashing. |
| 844 | /// | ||
| 845 | /// Options include an optional customization string that provides domain separation, | ||
| 846 | /// ensuring that identical inputs with different customization strings | ||
| 847 | /// produce completely distinct hash outputs. | ||
| 848 | /// | ||
| 849 | /// This prevents hash collisions when the same data is hashed in different contexts. | ||
| 850 | /// | ||
| 851 | /// Customization strings can be of any length. | ||
| 852 | /// | ||
| 853 | /// Common options for customization:: | ||
| 854 | /// | ||
| 855 | /// - Key derivation or MAC: 16-byte secret for KT128, 32-byte secret for KT256 | ||
| 856 | /// - Context Separation: domain-specific strings (e.g., "email", "password", "session") | ||
| 857 | /// - Composite Keys: concatenation of secret key + context string | ||
| 844 | pub const Options = struct { | 858 | pub const Options = struct { |
| 845 | customization: ?[]const u8 = null, | 859 | customization: ?[]const u8 = null, |
| 846 | }; | 860 | }; |
| ... | @@ -864,7 +878,20 @@ fn KTHash( | ... | @@ -864,7 +878,20 @@ fn KTHash( |
| 864 | pending_count: usize, // Number of complete chunks in pending_chunks | 878 | pending_count: usize, // Number of complete chunks in pending_chunks |
| 865 | 879 | ||
| 866 | /// Initialize a KangarooTwelve hashing context. | 880 | /// Initialize a KangarooTwelve hashing context. |
| 867 | /// The customization string is optional and used for domain separation. | 881 | /// |
| 882 | /// Options include an optional customization string that provides domain separation, | ||
| 883 | /// ensuring that identical inputs with different customization strings | ||
| 884 | /// produce completely distinct hash outputs. | ||
| 885 | /// | ||
| 886 | /// This prevents hash collisions when the same data is hashed in different contexts. | ||
| 887 | /// | ||
| 888 | /// Customization strings can be of any length. | ||
| 889 | /// | ||
| 890 | /// Common options for customization:: | ||
| 891 | /// | ||
| 892 | /// - Key derivation or MAC: 16-byte secret for KT128, 32-byte secret for KT256 | ||
| 893 | /// - Context Separation: domain-specific strings (e.g., "email", "password", "session") | ||
| 894 | /// - Composite Keys: concatenation of secret key + context string | ||
| 868 | pub fn init(options: Options) Self { | 895 | pub fn init(options: Options) Self { |
| 869 | const custom = options.customization orelse &[_]u8{}; | 896 | const custom = options.customization orelse &[_]u8{}; |
| 870 | return .{ | 897 | return .{ |
| ... | @@ -971,7 +998,13 @@ fn KTHash( | ... | @@ -971,7 +998,13 @@ fn KTHash( |
| 971 | } | 998 | } |
| 972 | 999 | ||
| 973 | /// Finalize the hash and produce output. | 1000 | /// Finalize the hash and produce output. |
| 974 | /// After calling this, the context should not be reused. | 1001 | /// |
| 1002 | /// Unlike traditional hash functions, the output can be of any length. | ||
| 1003 | /// | ||
| 1004 | /// When using as a regular hash function, use the recommended `digest_length` value (32 bytes for KT128, 64 bytes for KT256). | ||
| 1005 | /// | ||
| 1006 | /// After calling this method, the context should not be reused. However, the structure can be cloned before finalizing | ||
| 1007 | /// to compute multiple hashes with the same prefix. | ||
| 975 | pub fn final(self: *Self, out: []u8) void { | 1008 | pub fn final(self: *Self, out: []u8) void { |
| 976 | const cv_size = Variant.cv_size; | 1009 | const cv_size = Variant.cv_size; |
| 977 | 1010 | ||
| ... | @@ -1063,12 +1096,11 @@ fn KTHash( | ... | @@ -1063,12 +1096,11 @@ fn KTHash( |
| 1063 | } | 1096 | } |
| 1064 | 1097 | ||
| 1065 | /// Hash a message using sequential processing with SIMD acceleration. | 1098 | /// Hash a message using sequential processing with SIMD acceleration. |
| 1066 | /// Best performance for inputs under 10MB. Never allocates memory. | ||
| 1067 | /// | 1099 | /// |
| 1068 | /// Parameters: | 1100 | /// Parameters: |
| 1069 | /// - message: Input data to hash (any length) | 1101 | /// - message: Input data to hash (any length) |
| 1070 | /// - out: Output buffer (any length, arbitrary output sizes supported) | 1102 | /// - out: Output buffer (any length, arbitrary output sizes supported, `digest_length` recommended for standard use) |
| 1071 | /// - options: Optional settings including customization string for domain separation | 1103 | /// - options: Optional settings to include a secret key or a context separation string |
| 1072 | pub fn hash(message: []const u8, out: []u8, options: Options) !void { | 1104 | pub fn hash(message: []const u8, out: []u8, options: Options) !void { |
| 1073 | const custom = options.customization orelse &[_]u8{}; | 1105 | const custom = options.customization orelse &[_]u8{}; |
| 1074 | 1106 |