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