aboutsummaryrefslogtreecommitdiffstats
path: root/keys_test.go
diff options
context:
space:
mode:
authorClawd <ai@clawd.bot>2026-02-19 21:08:14 -0800
committerClawd <ai@clawd.bot>2026-02-19 21:08:14 -0800
commite5fa7c1a85e9dd44ee92cb5da1797c82a0268fdb (patch)
treefbe9d6c45112bb2ac068aed0d695797e0d4e24b8 /keys_test.go
parent3a9decc7abdb5fdc10c025747c2b2b8b10210ffd (diff)
Add key generation and serialization
Diffstat (limited to 'keys_test.go')
-rw-r--r--keys_test.go221
1 files changed, 221 insertions, 0 deletions
diff --git a/keys_test.go b/keys_test.go
new file mode 100644
index 0000000..e17ac98
--- /dev/null
+++ b/keys_test.go
@@ -0,0 +1,221 @@
1package secp256k1
2
3import (
4 "bytes"
5 "math/big"
6 "testing"
7)
8
9func TestGeneratePrivateKey(t *testing.T) {
10 priv, err := GeneratePrivateKey()
11 if err != nil {
12 t.Fatalf("failed to generate key: %v", err)
13 }
14
15 // Should be in valid range [1, N-1]
16 if priv.D.Sign() <= 0 {
17 t.Error("private key should be positive")
18 }
19 if priv.D.Cmp(N) >= 0 {
20 t.Error("private key should be less than N")
21 }
22}
23
24func TestGeneratePrivateKeyUnique(t *testing.T) {
25 // Generate two keys, they should be different
26 priv1, _ := GeneratePrivateKey()
27 priv2, _ := GeneratePrivateKey()
28
29 if priv1.D.Cmp(priv2.D) == 0 {
30 t.Error("two generated keys should not be identical")
31 }
32}
33
34func TestPrivateKeyFromBytes(t *testing.T) {
35 // 32 bytes of 0x01
36 b := make([]byte, 32)
37 b[31] = 0x01 // value = 1
38
39 priv, err := NewPrivateKeyFromBytes(b)
40 if err != nil {
41 t.Fatalf("failed to create key: %v", err)
42 }
43
44 if priv.D.Cmp(big.NewInt(1)) != 0 {
45 t.Errorf("expected D=1, got %s", priv.D.String())
46 }
47}
48
49func TestPrivateKeyFromBytesInvalidLength(t *testing.T) {
50 b := make([]byte, 31) // wrong length
51 _, err := NewPrivateKeyFromBytes(b)
52 if err == nil {
53 t.Error("should reject non-32-byte input")
54 }
55}
56
57func TestPrivateKeyFromBytesZero(t *testing.T) {
58 b := make([]byte, 32) // all zeros
59 _, err := NewPrivateKeyFromBytes(b)
60 if err == nil {
61 t.Error("should reject zero private key")
62 }
63}
64
65func TestPrivateKeyFromHex(t *testing.T) {
66 hex := "0000000000000000000000000000000000000000000000000000000000000001"
67 priv, err := NewPrivateKeyFromHex(hex)
68 if err != nil {
69 t.Fatalf("failed to create key: %v", err)
70 }
71
72 if priv.D.Cmp(big.NewInt(1)) != 0 {
73 t.Errorf("expected D=1, got %s", priv.D.String())
74 }
75}
76
77func TestPrivateKeyFromHexInvalid(t *testing.T) {
78 _, err := NewPrivateKeyFromHex("not-hex")
79 if err == nil {
80 t.Error("should reject invalid hex")
81 }
82}
83
84func TestPublicKeyDerivation(t *testing.T) {
85 // Private key = 1, public key should be G
86 priv, _ := NewPrivateKeyFromHex("0000000000000000000000000000000000000000000000000000000000000001")
87 pub := priv.PublicKey()
88
89 if !pub.Point.Equal(G) {
90 t.Error("1 * G should equal G")
91 }
92}
93
94func TestPublicKeyDerivation2(t *testing.T) {
95 // Private key = 2, public key should be 2G
96 priv, _ := NewPrivateKeyFromHex("0000000000000000000000000000000000000000000000000000000000000002")
97 pub := priv.PublicKey()
98
99 expected := G.Double()
100 if !pub.Point.Equal(expected) {
101 t.Error("2 * G should equal 2G")
102 }
103}
104
105func TestPublicKeyOnCurve(t *testing.T) {
106 priv, _ := GeneratePrivateKey()
107 pub := priv.PublicKey()
108
109 if !pub.Point.IsOnCurve() {
110 t.Error("derived public key should be on curve")
111 }
112}
113
114func TestPrivateKeyBytes(t *testing.T) {
115 priv, _ := NewPrivateKeyFromHex("0000000000000000000000000000000000000000000000000000000000000001")
116 b := priv.Bytes()
117
118 if len(b) != 32 {
119 t.Errorf("expected 32 bytes, got %d", len(b))
120 }
121 if b[31] != 0x01 {
122 t.Errorf("expected last byte to be 0x01, got 0x%02x", b[31])
123 }
124}
125
126func TestPrivateKeyRoundTrip(t *testing.T) {
127 priv1, _ := GeneratePrivateKey()
128 b := priv1.Bytes()
129 priv2, _ := NewPrivateKeyFromBytes(b)
130
131 if priv1.D.Cmp(priv2.D) != 0 {
132 t.Error("private key should survive bytes round-trip")
133 }
134}
135
136func TestPublicKeyBytesUncompressed(t *testing.T) {
137 priv, _ := NewPrivateKeyFromHex("0000000000000000000000000000000000000000000000000000000000000001")
138 pub := priv.PublicKey()
139 b := pub.Bytes()
140
141 if len(b) != 65 {
142 t.Errorf("uncompressed pubkey should be 65 bytes, got %d", len(b))
143 }
144 if b[0] != 0x04 {
145 t.Errorf("uncompressed prefix should be 0x04, got 0x%02x", b[0])
146 }
147}
148
149func TestPublicKeyBytesCompressed(t *testing.T) {
150 priv, _ := NewPrivateKeyFromHex("0000000000000000000000000000000000000000000000000000000000000001")
151 pub := priv.PublicKey()
152 b := pub.BytesCompressed()
153
154 if len(b) != 33 {
155 t.Errorf("compressed pubkey should be 33 bytes, got %d", len(b))
156 }
157 // G has odd y, so prefix should be 0x03
158 if b[0] != 0x02 && b[0] != 0x03 {
159 t.Errorf("compressed prefix should be 0x02 or 0x03, got 0x%02x", b[0])
160 }
161}
162
163func TestPublicKeyHex(t *testing.T) {
164 priv, _ := NewPrivateKeyFromHex("0000000000000000000000000000000000000000000000000000000000000001")
165 pub := priv.PublicKey()
166
167 hex := pub.Hex()
168 if len(hex) != 130 { // 65 bytes * 2
169 t.Errorf("uncompressed hex should be 130 chars, got %d", len(hex))
170 }
171
172 hexComp := pub.HexCompressed()
173 if len(hexComp) != 66 { // 33 bytes * 2
174 t.Errorf("compressed hex should be 66 chars, got %d", len(hexComp))
175 }
176}
177
178func TestPublicKeyEqual(t *testing.T) {
179 priv1, _ := NewPrivateKeyFromHex("0000000000000000000000000000000000000000000000000000000000000001")
180 priv2, _ := NewPrivateKeyFromHex("0000000000000000000000000000000000000000000000000000000000000001")
181 priv3, _ := NewPrivateKeyFromHex("0000000000000000000000000000000000000000000000000000000000000002")
182
183 pub1 := priv1.PublicKey()
184 pub2 := priv2.PublicKey()
185 pub3 := priv3.PublicKey()
186
187 if !pub1.Equal(pub2) {
188 t.Error("same private key should produce equal public keys")
189 }
190 if pub1.Equal(pub3) {
191 t.Error("different private keys should produce different public keys")
192 }
193}
194
195// Known test vector from Bitcoin wiki
196func TestKnownKeyVector(t *testing.T) {
197 // Private key = 1
198 priv, _ := NewPrivateKeyFromHex("0000000000000000000000000000000000000000000000000000000000000001")
199 pub := priv.PublicKey()
200
201 // Public key should be G
202 expectedX := Gx
203 expectedY := Gy
204
205 if pub.Point.x.value.Cmp(expectedX) != 0 {
206 t.Error("public key x doesn't match G.x")
207 }
208 if pub.Point.y.value.Cmp(expectedY) != 0 {
209 t.Error("public key y doesn't match G.y")
210 }
211
212 // Check compressed format starts with correct x
213 compressed := pub.BytesCompressed()
214 xFromCompressed := compressed[1:33]
215 expectedXBytes := make([]byte, 32)
216 copy(expectedXBytes[32-len(expectedX.Bytes()):], expectedX.Bytes())
217
218 if !bytes.Equal(xFromCompressed, expectedXBytes) {
219 t.Error("compressed pubkey x doesn't match")
220 }
221}