1const std = @import("std");
2const fmt = std.fmt;
3const testing = std.testing;
4
5const P256 = @import("../p256.zig").P256;
6
7test "p256 ECDH key exchange" {
8 const io = testing.io;
9 const dha = P256.scalar.random(io, .little);
10 const dhb = P256.scalar.random(io, .little);
11 const dhA = try P256.basePoint.mul(dha, .little);
12 const dhB = try P256.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 "p256 point from affine coordinates" {
19 const xh = "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296";
20 const yh = "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5";
21 var xs: [32]u8 = undefined;
22 _ = try fmt.hexToBytes(&xs, xh);
23 var ys: [32]u8 = undefined;
24 _ = try fmt.hexToBytes(&ys, yh);
25 var p = try P256.fromSerializedAffineCoordinates(xs, ys, .big);
26 try testing.expect(p.equivalent(P256.basePoint));
27}
28
29test "p256 test vectors" {
30 const expected = [_][]const u8{
31 "0000000000000000000000000000000000000000000000000000000000000000",
32 "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
33 "7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978",
34 "5ecbe4d1a6330a44c8f7ef951d4bf165e6c6b721efada985fb41661bc6e7fd6c",
35 "e2534a3532d08fbba02dde659ee62bd0031fe2db785596ef509302446b030852",
36 "51590b7a515140d2d784c85608668fdfef8c82fd1f5be52421554a0dc3d033ed",
37 "b01a172a76a4602c92d3242cb897dde3024c740debb215b4c6b0aae93c2291a9",
38 "8e533b6fa0bf7b4625bb30667c01fb607ef9f8b8a80fef5b300628703187b2a3",
39 "62d9779dbee9b0534042742d3ab54cadc1d238980fce97dbb4dd9dc1db6fb393",
40 "ea68d7b6fedf0b71878938d51d71f8729e0acb8c2c6df8b3d79e8a4b90949ee0",
41 };
42 var p = P256.identityElement;
43 for (expected) |xh| {
44 const x = p.affineCoordinates().x;
45 p = p.add(P256.basePoint);
46 var xs: [32]u8 = undefined;
47 _ = try fmt.hexToBytes(&xs, xh);
48 try testing.expectEqualSlices(u8, &x.toBytes(.big), &xs);
49 }
50}
51
52test "p256 test vectors - doubling" {
53 const expected = [_][]const u8{
54 "6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
55 "7cf27b188d034f7e8a52380304b51ac3c08969e277f21b35a60b48fc47669978",
56 "e2534a3532d08fbba02dde659ee62bd0031fe2db785596ef509302446b030852",
57 "62d9779dbee9b0534042742d3ab54cadc1d238980fce97dbb4dd9dc1db6fb393",
58 };
59 var p = P256.basePoint;
60 for (expected) |xh| {
61 const x = p.affineCoordinates().x;
62 p = p.dbl();
63 var xs: [32]u8 = undefined;
64 _ = try fmt.hexToBytes(&xs, xh);
65 try testing.expectEqualSlices(u8, &x.toBytes(.big), &xs);
66 }
67}
68
69test "p256 compressed sec1 encoding/decoding" {
70 const io = testing.io;
71 const p = P256.random(io);
72 const s = p.toCompressedSec1();
73 const q = try P256.fromSec1(&s);
74 try testing.expect(p.equivalent(q));
75}
76
77test "p256 uncompressed sec1 encoding/decoding" {
78 const io = testing.io;
79 const p = P256.random(io);
80 const s = p.toUncompressedSec1();
81 const q = try P256.fromSec1(&s);
82 try testing.expect(p.equivalent(q));
83}
84
85test "p256 public key is the neutral element" {
86 const io = testing.io;
87 const n = P256.scalar.Scalar.zero.toBytes(.little);
88 const p = P256.random(io);
89 try testing.expectError(error.IdentityElement, p.mul(n, .little));
90}
91
92test "p256 public key is the neutral element (public verification)" {
93 const io = testing.io;
94 const n = P256.scalar.Scalar.zero.toBytes(.little);
95 const p = P256.random(io);
96 try testing.expectError(error.IdentityElement, p.mulPublic(n, .little));
97}
98
99test "p256 field element non-canonical encoding" {
100 const s: [32]u8 = @splat(0xff);
101 try testing.expectError(error.NonCanonical, P256.Fe.fromBytes(s, .little));
102}
103
104test "p256 neutral element decoding" {
105 try testing.expectError(error.InvalidEncoding, P256.fromAffineCoordinates(.{ .x = P256.Fe.zero, .y = P256.Fe.zero }));
106 try testing.expectError(error.InvalidEncoding, P256.fromAffineCoordinates(.{ .x = P256.Fe.zero, .y = P256.Fe.one }));
107 try testing.expectError(error.IdentityElement, P256.identityElement.rejectIdentity());
108}
109
110test "p256 double base multiplication" {
111 const p1 = P256.basePoint;
112 const p2 = P256.basePoint.dbl();
113 const s1: [32]u8 = @splat(0x01);
114 const s2: [32]u8 = @splat(0x02);
115 const pr1 = try P256.mulDoubleBasePublic(p1, s1, p2, s2, .little);
116 const pr2 = (try p1.mul(s1, .little)).add(try p2.mul(s2, .little));
117 try testing.expect(pr1.equivalent(pr2));
118}
119
120test "p256 double base multiplication with large scalars" {
121 const p1 = P256.basePoint;
122 const p2 = P256.basePoint.dbl();
123 const s1: [32]u8 = @splat(0xee);
124 const s2: [32]u8 = @splat(0xdd);
125 const pr1 = try P256.mulDoubleBasePublic(p1, s1, p2, s2, .little);
126 const pr2 = (try p1.mul(s1, .little)).add(try p2.mul(s2, .little));
127 try testing.expect(pr1.equivalent(pr2));
128}
129
130test "p256 scalar inverse" {
131 const expected = "3b549196a13c898a6f6e84dfb3a22c40a8b9b17fb88e408ea674e451cd01d0a6";
132 var out: [32]u8 = undefined;
133 _ = try std.fmt.hexToBytes(&out, expected);
134
135 const scalar = try P256.scalar.Scalar.fromBytes(.{
136 0x94, 0xa1, 0xbb, 0xb1, 0x4b, 0x90, 0x6a, 0x61, 0xa2, 0x80, 0xf2, 0x45, 0xf9, 0xe9, 0x3c, 0x7f,
137 0x3b, 0x4a, 0x62, 0x47, 0x82, 0x4f, 0x5d, 0x33, 0xb9, 0x67, 0x07, 0x87, 0x64, 0x2a, 0x68, 0xde,
138 }, .big);
139 const inverse = scalar.invert();
140 try std.testing.expectEqualSlices(u8, &out, &inverse.toBytes(.big));
141}
142
143test "p256 scalar parity" {
144 try std.testing.expect(P256.scalar.Scalar.zero.isOdd() == false);
145 try std.testing.expect(P256.scalar.Scalar.one.isOdd());
146 try std.testing.expect(P256.scalar.Scalar.one.dbl().isOdd() == false);
147}