bip340_test.go raw
1 package secp256k1
2
3 import (
4 "crypto/rand"
5 "encoding/csv"
6 "encoding/hex"
7 "os"
8 "strings"
9 "testing"
10 )
11
12 func hexToArray(t *testing.T, s string, n int) []byte {
13 t.Helper()
14 b, err := hex.DecodeString(strings.ToLower(s))
15 if err != nil {
16 t.Fatalf("bad hex %q: %v", s, err)
17 }
18 if len(b) != n {
19 t.Fatalf("wanted %d bytes, got %d from %q", n, len(b), s)
20 }
21 return b
22 }
23
24 func TestBIP340Vectors(t *testing.T) {
25 f, err := os.Open("testdata/bip340.csv")
26 if err != nil {
27 t.Fatal(err)
28 }
29 defer f.Close()
30 rows, err := csv.NewReader(f).ReadAll()
31 if err != nil {
32 t.Fatal(err)
33 }
34 if len(rows) < 2 {
35 t.Fatal("no vectors")
36 }
37 for _, row := range rows[1:] {
38 if len(row) < 7 {
39 continue
40 }
41 name := row[0]
42 var sk, aux, pub [32]byte
43 var sig [64]byte
44 pubB := hexToArray(t, row[2], 32)
45 msgB, err := hex.DecodeString(strings.ToLower(row[4]))
46 if err != nil {
47 t.Fatalf("vector %s: bad message hex: %v", name, err)
48 }
49 sigB := hexToArray(t, row[5], 64)
50 copy(pub[:], pubB)
51 copy(sig[:], sigB)
52 want := strings.EqualFold(row[6], "TRUE")
53
54 got := VerifyMsg(pub, msgB, sig)
55 if got != want {
56 t.Errorf("vector %s: Verify = %v, want %v", name, got, want)
57 }
58 if !want {
59 continue
60 }
61
62 // Vectors with a secret key also pin the exact signature when the
63 // aux_rand is used, which tests the signing path end to end.
64 if row[1] == "" {
65 continue
66 }
67 skB := hexToArray(t, row[1], 32)
68 copy(sk[:], skB)
69 auxB := hexToArray(t, row[3], 32)
70 copy(aux[:], auxB)
71
72 gotPub, ok := PubKey(sk)
73 if !ok || gotPub != pub {
74 t.Errorf("vector %s: PubKey mismatch", name)
75 }
76 gotSig, ok := SignAuxMsg(sk, msgB, aux)
77 if !ok {
78 t.Errorf("vector %s: SignAux failed", name)
79 }
80 if gotSig != sig {
81 t.Errorf("vector %s: signature mismatch\n got %x\nwant %x", name, gotSig, sig)
82 }
83 }
84 }
85
86 func TestSignVerifyRoundTrip(t *testing.T) {
87 for i := 0; i < 16; i++ {
88 var sk [32]byte
89 var msg [32]byte
90 if _, err := rand.Read(sk[:]); err != nil {
91 t.Fatal(err)
92 }
93 if _, err := rand.Read(msg[:]); err != nil {
94 t.Fatal(err)
95 }
96 pub, ok := PubKey(sk)
97 if !ok {
98 t.Fatalf("PubKey failed for key %d", i)
99 }
100 sig, ok := Sign(sk, msg)
101 if !ok {
102 t.Fatalf("Sign failed for key %d", i)
103 }
104 if !Verify(pub, msg, sig) {
105 t.Fatalf("fresh signature did not verify for key %d", i)
106 }
107 // A single-bit change must invalidate the signature.
108 sig[0] ^= 1
109 if Verify(pub, msg, sig) {
110 t.Fatalf("corrupted signature verified for key %d", i)
111 }
112 }
113 }
114
115 // TestFastAndSlowAgree cross-checks the btcec fast path against the math/big
116 // reference in both directions. Signatures are deterministic given aux_rand,
117 // so the two signers must produce identical bytes.
118 func TestFastAndSlowAgree(t *testing.T) {
119 for i := 0; i < 8; i++ {
120 var sk, msg, aux [32]byte
121 if _, err := rand.Read(sk[:]); err != nil {
122 t.Fatal(err)
123 }
124 if _, err := rand.Read(msg[:]); err != nil {
125 t.Fatal(err)
126 }
127 if _, err := rand.Read(aux[:]); err != nil {
128 t.Fatal(err)
129 }
130 pub, ok := PubKey(sk)
131 if !ok {
132 t.Fatal("PubKey failed")
133 }
134
135 fast, ok := signFastWithAux(sk, msg, aux)
136 if !ok {
137 t.Fatal("fast sign failed")
138 }
139 if !verifySlowMsg(pub, msg[:], fast) {
140 t.Fatal("slow verifier rejected the fast signature")
141 }
142 slow, ok := signSlowAuxMsg(sk, msg[:], aux)
143 if !ok {
144 t.Fatal("slow sign failed")
145 }
146 if slow != fast {
147 t.Fatalf("signers disagree\n fast %x\n slow %x", fast, slow)
148 }
149 if !verifyFast(pub, msg, slow) {
150 t.Fatal("fast verifier rejected the slow signature")
151 }
152 fast[0] ^= 1
153 if verifySlowMsg(pub, msg[:], fast) || verifyFast(pub, msg, fast) {
154 t.Fatal("tampered signature accepted")
155 }
156 }
157 }
158