authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-08-26 23:53:17-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-08-28 18:30:57-07:00
log888f00e856998841f5da7b75c6891fab8e31703c
treee300068f0f58411fef2b927a6dcc278545055cab
parente9a271cba3c79358cc8d24a3892fbbefc4e12d9d

std.crypto.ml_kem: update to not use GenericWriter


1 files changed, 47 insertions(+), 45 deletions(-)

lib/std/crypto/ml_kem.zig+47-45
......@@ -1721,53 +1721,55 @@ test "Test happy flow" {
17211721
17221722// Code to test NIST Known Answer Tests (KAT), see PQCgenKAT.c.
17231723
1724const sha2 = crypto.hash.sha2;
1725
1726test "NIST KAT test" {
1727 inline for (.{
1728 .{ d00.Kyber512, "e9c2bd37133fcb40772f81559f14b1f58dccd1c816701be9ba6214d43baf4547" },
1729 .{ d00.Kyber1024, "89248f2f33f7f4f7051729111f3049c409a933ec904aedadf035f30fa5646cd5" },
1730 .{ d00.Kyber768, "a1e122cad3c24bc51622e4c242d8b8acbcd3f618fee4220400605ca8f9ea02c2" },
1731 }) |modeHash| {
1732 const mode = modeHash[0];
1733 var seed: [48]u8 = undefined;
1734 for (&seed, 0..) |*s, i| {
1735 s.* = @as(u8, @intCast(i));
1736 }
1737 var f = sha2.Sha256.init(.{});
1738 const fw = f.writer();
1739 var g = NistDRBG.init(seed);
1740 try std.fmt.format(fw, "# {s}\n\n", .{mode.name});
1741 for (0..100) |i| {
1742 g.fill(&seed);
1743 try std.fmt.format(fw, "count = {}\n", .{i});
1744 try std.fmt.format(fw, "seed = {X}\n", .{&seed});
1745 var g2 = NistDRBG.init(seed);
1746
1747 // This is not equivalent to g2.fill(kseed[:]). As the reference
1748 // implementation calls randombytes twice generating the keypair,
1749 // we have to do that as well.
1750 var kseed: [64]u8 = undefined;
1751 var eseed: [32]u8 = undefined;
1752 g2.fill(kseed[0..32]);
1753 g2.fill(kseed[32..64]);
1754 g2.fill(&eseed);
1755 const kp = try mode.KeyPair.generateDeterministic(kseed);
1756 const e = kp.public_key.encaps(eseed);
1757 const ss2 = try kp.secret_key.decaps(&e.ciphertext);
1758 try testing.expectEqual(ss2, e.shared_secret);
1759 try std.fmt.format(fw, "pk = {X}\n", .{&kp.public_key.toBytes()});
1760 try std.fmt.format(fw, "sk = {X}\n", .{&kp.secret_key.toBytes()});
1761 try std.fmt.format(fw, "ct = {X}\n", .{&e.ciphertext});
1762 try std.fmt.format(fw, "ss = {X}\n\n", .{&e.shared_secret});
1763 }
1724test "NIST KAT test d00.Kyber512" {
1725 try testNistKat(d00.Kyber512, "e9c2bd37133fcb40772f81559f14b1f58dccd1c816701be9ba6214d43baf4547");
1726}
17641727
1765 var out: [32]u8 = undefined;
1766 f.final(&out);
1767 var outHex: [64]u8 = undefined;
1768 _ = try std.fmt.bufPrint(&outHex, "{x}", .{&out});
1769 try testing.expectEqual(outHex, modeHash[1].*);
1728test "NIST KAT test d00.Kyber1024" {
1729 try testNistKat(d00.Kyber1024, "89248f2f33f7f4f7051729111f3049c409a933ec904aedadf035f30fa5646cd5");
1730}
1731
1732test "NIST KAT test d00.Kyber768" {
1733 try testNistKat(d00.Kyber768, "a1e122cad3c24bc51622e4c242d8b8acbcd3f618fee4220400605ca8f9ea02c2");
1734}
1735
1736fn testNistKat(mode: type, hash: []const u8) !void {
1737 var seed: [48]u8 = undefined;
1738 for (&seed, 0..) |*s, i| {
1739 s.* = @as(u8, @intCast(i));
17701740 }
1741 var fw: std.Io.Writer.Hashing(crypto.hash.sha2.Sha256) = .init(&.{});
1742 var g = NistDRBG.init(seed);
1743 try fw.writer.print("# {s}\n\n", .{mode.name});
1744 for (0..100) |i| {
1745 g.fill(&seed);
1746 try fw.writer.print("count = {}\n", .{i});
1747 try fw.writer.print("seed = {X}\n", .{&seed});
1748 var g2 = NistDRBG.init(seed);
1749
1750 // This is not equivalent to g2.fill(kseed[:]). As the reference
1751 // implementation calls randombytes twice generating the keypair,
1752 // we have to do that as well.
1753 var kseed: [64]u8 = undefined;
1754 var eseed: [32]u8 = undefined;
1755 g2.fill(kseed[0..32]);
1756 g2.fill(kseed[32..64]);
1757 g2.fill(&eseed);
1758 const kp = try mode.KeyPair.generateDeterministic(kseed);
1759 const e = kp.public_key.encaps(eseed);
1760 const ss2 = try kp.secret_key.decaps(&e.ciphertext);
1761 try testing.expectEqual(ss2, e.shared_secret);
1762 try fw.writer.print("pk = {X}\n", .{&kp.public_key.toBytes()});
1763 try fw.writer.print("sk = {X}\n", .{&kp.secret_key.toBytes()});
1764 try fw.writer.print("ct = {X}\n", .{&e.ciphertext});
1765 try fw.writer.print("ss = {X}\n\n", .{&e.shared_secret});
1766 }
1767
1768 var out: [32]u8 = undefined;
1769 fw.hasher.final(&out);
1770 var outHex: [64]u8 = undefined;
1771 _ = try std.fmt.bufPrint(&outHex, "{x}", .{&out});
1772 try testing.expectEqualStrings(&outHex, hash);
17711773}
17721774
17731775const NistDRBG = struct {