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