package secp256k1 import ( "crypto/rand" "encoding/csv" "encoding/hex" "os" "strings" "testing" ) func hexToArray(t *testing.T, s string, n int) []byte { t.Helper() b, err := hex.DecodeString(strings.ToLower(s)) if err != nil { t.Fatalf("bad hex %q: %v", s, err) } if len(b) != n { t.Fatalf("wanted %d bytes, got %d from %q", n, len(b), s) } return b } func TestBIP340Vectors(t *testing.T) { f, err := os.Open("testdata/bip340.csv") if err != nil { t.Fatal(err) } defer f.Close() rows, err := csv.NewReader(f).ReadAll() if err != nil { t.Fatal(err) } if len(rows) < 2 { t.Fatal("no vectors") } for _, row := range rows[1:] { if len(row) < 7 { continue } name := row[0] var sk, aux, pub [32]byte var sig [64]byte pubB := hexToArray(t, row[2], 32) msgB, err := hex.DecodeString(strings.ToLower(row[4])) if err != nil { t.Fatalf("vector %s: bad message hex: %v", name, err) } sigB := hexToArray(t, row[5], 64) copy(pub[:], pubB) copy(sig[:], sigB) want := strings.EqualFold(row[6], "TRUE") got := VerifyMsg(pub, msgB, sig) if got != want { t.Errorf("vector %s: Verify = %v, want %v", name, got, want) } if !want { continue } // Vectors with a secret key also pin the exact signature when the // aux_rand is used, which tests the signing path end to end. if row[1] == "" { continue } skB := hexToArray(t, row[1], 32) copy(sk[:], skB) auxB := hexToArray(t, row[3], 32) copy(aux[:], auxB) gotPub, ok := PubKey(sk) if !ok || gotPub != pub { t.Errorf("vector %s: PubKey mismatch", name) } gotSig, ok := SignAuxMsg(sk, msgB, aux) if !ok { t.Errorf("vector %s: SignAux failed", name) } if gotSig != sig { t.Errorf("vector %s: signature mismatch\n got %x\nwant %x", name, gotSig, sig) } } } func TestSignVerifyRoundTrip(t *testing.T) { for i := 0; i < 16; i++ { var sk [32]byte var msg [32]byte if _, err := rand.Read(sk[:]); err != nil { t.Fatal(err) } if _, err := rand.Read(msg[:]); err != nil { t.Fatal(err) } pub, ok := PubKey(sk) if !ok { t.Fatalf("PubKey failed for key %d", i) } sig, ok := Sign(sk, msg) if !ok { t.Fatalf("Sign failed for key %d", i) } if !Verify(pub, msg, sig) { t.Fatalf("fresh signature did not verify for key %d", i) } // A single-bit change must invalidate the signature. sig[0] ^= 1 if Verify(pub, msg, sig) { t.Fatalf("corrupted signature verified for key %d", i) } } } // TestFastAndSlowAgree cross-checks the btcec fast path against the math/big // reference in both directions. Signatures are deterministic given aux_rand, // so the two signers must produce identical bytes. func TestFastAndSlowAgree(t *testing.T) { for i := 0; i < 8; i++ { var sk, msg, aux [32]byte if _, err := rand.Read(sk[:]); err != nil { t.Fatal(err) } if _, err := rand.Read(msg[:]); err != nil { t.Fatal(err) } if _, err := rand.Read(aux[:]); err != nil { t.Fatal(err) } pub, ok := PubKey(sk) if !ok { t.Fatal("PubKey failed") } fast, ok := signFastWithAux(sk, msg, aux) if !ok { t.Fatal("fast sign failed") } if !verifySlowMsg(pub, msg[:], fast) { t.Fatal("slow verifier rejected the fast signature") } slow, ok := signSlowAuxMsg(sk, msg[:], aux) if !ok { t.Fatal("slow sign failed") } if slow != fast { t.Fatalf("signers disagree\n fast %x\n slow %x", fast, slow) } if !verifyFast(pub, msg, slow) { t.Fatal("fast verifier rejected the slow signature") } fast[0] ^= 1 if verifySlowMsg(pub, msg[:], fast) || verifyFast(pub, msg, fast) { t.Fatal("tampered signature accepted") } } }