| ... | ... | @@ -1721,53 +1721,55 @@ test "Test happy flow" { |
| 1721 | 1721 | |
| 1722 | 1722 | // Code to test NIST Known Answer Tests (KAT), see PQCgenKAT.c. |
| 1723 | 1723 | |
| 1724 | | const sha2 = crypto.hash.sha2; |
| 1725 | | |
| 1726 | | test "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 | | } |
| 1724 | test "NIST KAT test d00.Kyber512" { |
| 1725 | try testNistKat(d00.Kyber512, "e9c2bd37133fcb40772f81559f14b1f58dccd1c816701be9ba6214d43baf4547"); |
| 1726 | } |
| 1764 | 1727 | |
| 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].*); |
| 1728 | test "NIST KAT test d00.Kyber1024" { |
| 1729 | try testNistKat(d00.Kyber1024, "89248f2f33f7f4f7051729111f3049c409a933ec904aedadf035f30fa5646cd5"); |
| 1730 | } |
| 1731 | |
| 1732 | test "NIST KAT test d00.Kyber768" { |
| 1733 | try testNistKat(d00.Kyber768, "a1e122cad3c24bc51622e4c242d8b8acbcd3f618fee4220400605ca8f9ea02c2"); |
| 1734 | } |
| 1735 | |
| 1736 | fn 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)); |
| 1770 | 1740 | } |
| 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); |
| 1771 | 1773 | } |
| 1772 | 1774 | |
| 1773 | 1775 | const NistDRBG = struct { |