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