1const std = @import("std");
2const fmt = std.fmt;
3const testing = std.testing;
4
5const P384 = @import("../p384.zig").P384;
6
7test "p384 ECDH key exchange" {
8 const io = testing.io;
9 const dha = P384.scalar.random(io, .little);
10 const dhb = P384.scalar.random(io, .little);
11 const dhA = try P384.basePoint.mul(dha, .little);
12 const dhB = try P384.basePoint.mul(dhb, .little);
13 const shareda = try dhA.mul(dhb, .little);
14 const sharedb = try dhB.mul(dha, .little);
15 try testing.expect(shareda.equivalent(sharedb));
16}
17
18test "p384 point from affine coordinates" {
19 const xh = "aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7";
20 const yh = "3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f";
21 var xs: [48]u8 = undefined;
22 _ = try fmt.hexToBytes(&xs, xh);
23 var ys: [48]u8 = undefined;
24 _ = try fmt.hexToBytes(&ys, yh);
25 var p = try P384.fromSerializedAffineCoordinates(xs, ys, .big);
26 try testing.expect(p.equivalent(P384.basePoint));
27}
28
29test "p384 test vectors" {
30 const expected = [_][]const u8{
31 "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
32 "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7",
33 "08D999057BA3D2D969260045C55B97F089025959A6F434D651D207D19FB96E9E4FE0E86EBE0E64F85B96A9C75295DF61",
34 "077A41D4606FFA1464793C7E5FDC7D98CB9D3910202DCD06BEA4F240D3566DA6B408BBAE5026580D02D7E5C70500C831",
35 "138251CD52AC9298C1C8AAD977321DEB97E709BD0B4CA0ACA55DC8AD51DCFC9D1589A1597E3A5120E1EFD631C63E1835",
36 "11DE24A2C251C777573CAC5EA025E467F208E51DBFF98FC54F6661CBE56583B037882F4A1CA297E60ABCDBC3836D84BC",
37 "627BE1ACD064D2B2226FE0D26F2D15D3C33EBCBB7F0F5DA51CBD41F26257383021317D7202FF30E50937F0854E35C5DF",
38 "283C1D7365CE4788F29F8EBF234EDFFEAD6FE997FBEA5FFA2D58CC9DFA7B1C508B05526F55B9EBB2040F05B48FB6D0E1",
39 "1692778EA596E0BE75114297A6FA383445BF227FBE58190A900C3C73256F11FB5A3258D6F403D5ECE6E9B269D822C87D",
40 "8F0A39A4049BCB3EF1BF29B8B025B78F2216F7291E6FD3BAC6CB1EE285FB6E21C388528BFEE2B9535C55E4461079118B",
41 "A669C5563BD67EEC678D29D6EF4FDE864F372D90B79B9E88931D5C29291238CCED8E85AB507BF91AA9CB2D13186658FB",
42 };
43 var p = P384.identityElement;
44 for (expected) |xh| {
45 const x = p.affineCoordinates().x;
46 p = p.add(P384.basePoint);
47 var xs: [48]u8 = undefined;
48 _ = try fmt.hexToBytes(&xs, xh);
49 try testing.expectEqualSlices(u8, &x.toBytes(.big), &xs);
50 }
51}
52
53test "p384 test vectors - doubling" {
54 const expected = [_][]const u8{
55 "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7",
56 "08D999057BA3D2D969260045C55B97F089025959A6F434D651D207D19FB96E9E4FE0E86EBE0E64F85B96A9C75295DF61",
57 "138251CD52AC9298C1C8AAD977321DEB97E709BD0B4CA0ACA55DC8AD51DCFC9D1589A1597E3A5120E1EFD631C63E1835",
58 "1692778EA596E0BE75114297A6FA383445BF227FBE58190A900C3C73256F11FB5A3258D6F403D5ECE6E9B269D822C87D",
59 };
60 var p = P384.basePoint;
61 for (expected) |xh| {
62 const x = p.affineCoordinates().x;
63 p = p.dbl();
64 var xs: [48]u8 = undefined;
65 _ = try fmt.hexToBytes(&xs, xh);
66 try testing.expectEqualSlices(u8, &x.toBytes(.big), &xs);
67 }
68}
69
70test "p384 compressed sec1 encoding/decoding" {
71 const io = testing.io;
72 const p = P384.random(io);
73 const s0 = p.toUncompressedSec1();
74 const s = p.toCompressedSec1();
75 try testing.expectEqualSlices(u8, s0[1..49], s[1..49]);
76 const q = try P384.fromSec1(&s);
77 try testing.expect(p.equivalent(q));
78}
79
80test "p384 uncompressed sec1 encoding/decoding" {
81 const io = testing.io;
82 const p = P384.random(io);
83 const s = p.toUncompressedSec1();
84 const q = try P384.fromSec1(&s);
85 try testing.expect(p.equivalent(q));
86}
87
88test "p384 public key is the neutral element" {
89 const io = testing.io;
90 const n = P384.scalar.Scalar.zero.toBytes(.little);
91 const p = P384.random(io);
92 try testing.expectError(error.IdentityElement, p.mul(n, .little));
93}
94
95test "p384 public key is the neutral element (public verification)" {
96 const io = testing.io;
97 const n = P384.scalar.Scalar.zero.toBytes(.little);
98 const p = P384.random(io);
99 try testing.expectError(error.IdentityElement, p.mulPublic(n, .little));
100}
101
102test "p384 field element non-canonical encoding" {
103 const s: [48]u8 = @splat(0xff);
104 try testing.expectError(error.NonCanonical, P384.Fe.fromBytes(s, .little));
105}
106
107test "p384 neutral element decoding" {
108 try testing.expectError(error.InvalidEncoding, P384.fromAffineCoordinates(.{ .x = P384.Fe.zero, .y = P384.Fe.zero }));
109 try testing.expectError(error.InvalidEncoding, P384.fromAffineCoordinates(.{ .x = P384.Fe.zero, .y = P384.Fe.one }));
110 try testing.expectError(error.IdentityElement, P384.identityElement.rejectIdentity());
111}
112
113test "p384 double base multiplication" {
114 const p1 = P384.basePoint;
115 const p2 = P384.basePoint.dbl();
116 const s1: [48]u8 = @splat(0x01);
117 const s2: [48]u8 = @splat(0x02);
118 const pr1 = try P384.mulDoubleBasePublic(p1, s1, p2, s2, .little);
119 const pr2 = (try p1.mul(s1, .little)).add(try p2.mul(s2, .little));
120 try testing.expect(pr1.equivalent(pr2));
121}
122
123test "p384 double base multiplication with large scalars" {
124 const p1 = P384.basePoint;
125 const p2 = P384.basePoint.dbl();
126 const s1: [48]u8 = @splat(0xee);
127 const s2: [48]u8 = @splat(0xdd);
128 const pr1 = try P384.mulDoubleBasePublic(p1, s1, p2, s2, .little);
129 const pr2 = (try p1.mul(s1, .little)).add(try p2.mul(s2, .little));
130 try testing.expect(pr1.equivalent(pr2));
131}
132
133test "p384 scalar inverse" {
134 const expected = "a3cc705f33b5679a66e76ce66e68055c927c5dba531b2837b18fe86119511091b54d733f26b2e7a0f6fa2e7ea21ca806";
135 var out: [48]u8 = undefined;
136 _ = try std.fmt.hexToBytes(&out, expected);
137
138 const scalar = try P384.scalar.Scalar.fromBytes(.{
139 0x94, 0xa1, 0xbb, 0xb1, 0x4b, 0x90, 0x6a, 0x61, 0xa2, 0x80, 0xf2, 0x45, 0xf9, 0xe9, 0x3c, 0x7f,
140 0x3b, 0x4a, 0x62, 0x47, 0x82, 0x4f, 0x5d, 0x33, 0xb9, 0x67, 0x07, 0x87, 0x64, 0x2a, 0x68, 0xde,
141 0x38, 0x36, 0xe8, 0x0f, 0xa2, 0x84, 0x6b, 0x4e, 0xf3, 0x9a, 0x02, 0x31, 0x24, 0x41, 0x22, 0xca,
142 }, .big);
143 const inverse = scalar.invert();
144 const inverse2 = inverse.invert();
145 try testing.expectEqualSlices(u8, &out, &inverse.toBytes(.big));
146 try testing.expect(inverse2.equivalent(scalar));
147
148 const sq = scalar.sq();
149 const sqr = try sq.sqrt();
150 try testing.expect(sqr.equivalent(scalar));
151}
152
153test "p384 scalar parity" {
154 try std.testing.expect(P384.scalar.Scalar.zero.isOdd() == false);
155 try std.testing.expect(P384.scalar.Scalar.one.isOdd());
156 try std.testing.expect(P384.scalar.Scalar.one.dbl().isOdd() == false);
157}