github.com/luckypickle/go-ethereum-vet@v1.14.2/crypto/secp256k1/secp256_test.go (about) 1 // Copyright 2015 Jeffrey Wilcke, Felix Lange, Gustav Simonsson. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 //go:build !gofuzz && cgo 6 // +build !gofuzz,cgo 7 8 package secp256k1 9 10 import ( 11 "bytes" 12 "crypto/ecdsa" 13 "crypto/elliptic" 14 "crypto/rand" 15 "encoding/hex" 16 "io" 17 "testing" 18 ) 19 20 const TestCount = 1000 21 22 func generateKeyPair() (pubkey, privkey []byte) { 23 key, err := ecdsa.GenerateKey(S256(), rand.Reader) 24 if err != nil { 25 panic(err) 26 } 27 pubkey = elliptic.Marshal(S256(), key.X, key.Y) 28 29 privkey = make([]byte, 32) 30 blob := key.D.Bytes() 31 copy(privkey[32-len(blob):], blob) 32 33 return pubkey, privkey 34 } 35 36 func csprngEntropy(n int) []byte { 37 buf := make([]byte, n) 38 if _, err := io.ReadFull(rand.Reader, buf); err != nil { 39 panic("reading from crypto/rand failed: " + err.Error()) 40 } 41 return buf 42 } 43 44 func randSig() []byte { 45 sig := csprngEntropy(65) 46 sig[32] &= 0x70 47 sig[64] %= 4 48 return sig 49 } 50 51 // tests for malleability 52 // highest bit of signature ECDSA s value must be 0, in the 33th byte 53 func compactSigCheck(t *testing.T, sig []byte) { 54 var b = int(sig[32]) 55 if b < 0 { 56 t.Errorf("highest bit is negative: %d", b) 57 } 58 if ((b >> 7) == 1) != ((b & 0x80) == 0x80) { 59 t.Errorf("highest bit: %d bit >> 7: %d", b, b>>7) 60 } 61 if (b & 0x80) == 0x80 { 62 t.Errorf("highest bit: %d bit & 0x80: %d", b, b&0x80) 63 } 64 } 65 66 func TestSignatureValidity(t *testing.T) { 67 pubkey, seckey := generateKeyPair() 68 msg := csprngEntropy(32) 69 sig, err := Sign(msg, seckey) 70 if err != nil { 71 t.Errorf("signature error: %s", err) 72 } 73 compactSigCheck(t, sig) 74 if len(pubkey) != 65 { 75 t.Errorf("pubkey length mismatch: want: 65 have: %d", len(pubkey)) 76 } 77 if len(seckey) != 32 { 78 t.Errorf("seckey length mismatch: want: 32 have: %d", len(seckey)) 79 } 80 if len(sig) != 65 { 81 t.Errorf("sig length mismatch: want: 65 have: %d", len(sig)) 82 } 83 recid := int(sig[64]) 84 if recid > 4 || recid < 0 { 85 t.Errorf("sig recid mismatch: want: within 0 to 4 have: %d", int(sig[64])) 86 } 87 } 88 89 func TestInvalidRecoveryID(t *testing.T) { 90 _, seckey := generateKeyPair() 91 msg := csprngEntropy(32) 92 sig, _ := Sign(msg, seckey) 93 sig[64] = 99 94 _, err := RecoverPubkey(msg, sig) 95 if err != ErrInvalidRecoveryID { 96 t.Fatalf("got %q, want %q", err, ErrInvalidRecoveryID) 97 } 98 } 99 100 func TestSignAndRecover(t *testing.T) { 101 pubkey1, seckey := generateKeyPair() 102 msg := csprngEntropy(32) 103 sig, err := Sign(msg, seckey) 104 if err != nil { 105 t.Errorf("signature error: %s", err) 106 } 107 pubkey2, err := RecoverPubkey(msg, sig) 108 if err != nil { 109 t.Errorf("recover error: %s", err) 110 } 111 if !bytes.Equal(pubkey1, pubkey2) { 112 t.Errorf("pubkey mismatch: want: %x have: %x", pubkey1, pubkey2) 113 } 114 } 115 116 func TestSignDeterministic(t *testing.T) { 117 _, seckey := generateKeyPair() 118 msg := make([]byte, 32) 119 copy(msg, "hi there") 120 121 sig1, err := Sign(msg, seckey) 122 if err != nil { 123 t.Fatal(err) 124 } 125 sig2, err := Sign(msg, seckey) 126 if err != nil { 127 t.Fatal(err) 128 } 129 if !bytes.Equal(sig1, sig2) { 130 t.Fatal("signatures not equal") 131 } 132 } 133 134 func TestRandomMessagesWithSameKey(t *testing.T) { 135 pubkey, seckey := generateKeyPair() 136 keys := func() ([]byte, []byte) { 137 return pubkey, seckey 138 } 139 signAndRecoverWithRandomMessages(t, keys) 140 } 141 142 func TestRandomMessagesWithRandomKeys(t *testing.T) { 143 keys := func() ([]byte, []byte) { 144 pubkey, seckey := generateKeyPair() 145 return pubkey, seckey 146 } 147 signAndRecoverWithRandomMessages(t, keys) 148 } 149 150 func signAndRecoverWithRandomMessages(t *testing.T, keys func() ([]byte, []byte)) { 151 for i := 0; i < TestCount; i++ { 152 pubkey1, seckey := keys() 153 msg := csprngEntropy(32) 154 sig, err := Sign(msg, seckey) 155 if err != nil { 156 t.Fatalf("signature error: %s", err) 157 } 158 if sig == nil { 159 t.Fatal("signature is nil") 160 } 161 compactSigCheck(t, sig) 162 163 // TODO: why do we flip around the recovery id? 164 sig[len(sig)-1] %= 4 165 166 pubkey2, err := RecoverPubkey(msg, sig) 167 if err != nil { 168 t.Fatalf("recover error: %s", err) 169 } 170 if pubkey2 == nil { 171 t.Error("pubkey is nil") 172 } 173 if !bytes.Equal(pubkey1, pubkey2) { 174 t.Fatalf("pubkey mismatch: want: %x have: %x", pubkey1, pubkey2) 175 } 176 } 177 } 178 179 func TestRecoveryOfRandomSignature(t *testing.T) { 180 pubkey1, _ := generateKeyPair() 181 msg := csprngEntropy(32) 182 183 for i := 0; i < TestCount; i++ { 184 // recovery can sometimes work, but if so should always give wrong pubkey 185 pubkey2, _ := RecoverPubkey(msg, randSig()) 186 if bytes.Equal(pubkey1, pubkey2) { 187 t.Fatalf("iteration: %d: pubkey mismatch: do NOT want %x: ", i, pubkey2) 188 } 189 } 190 } 191 192 func TestRandomMessagesAgainstValidSig(t *testing.T) { 193 pubkey1, seckey := generateKeyPair() 194 msg := csprngEntropy(32) 195 sig, _ := Sign(msg, seckey) 196 197 for i := 0; i < TestCount; i++ { 198 msg = csprngEntropy(32) 199 pubkey2, _ := RecoverPubkey(msg, sig) 200 // recovery can sometimes work, but if so should always give wrong pubkey 201 if bytes.Equal(pubkey1, pubkey2) { 202 t.Fatalf("iteration: %d: pubkey mismatch: do NOT want %x: ", i, pubkey2) 203 } 204 } 205 } 206 207 // Useful when the underlying libsecp256k1 API changes to quickly 208 // check only recover function without use of signature function 209 func TestRecoverSanity(t *testing.T) { 210 msg, _ := hex.DecodeString("ce0677bb30baa8cf067c88db9811f4333d131bf8bcf12fe7065d211dce971008") 211 sig, _ := hex.DecodeString("90f27b8b488db00b00606796d2987f6a5f59ae62ea05effe84fef5b8b0e549984a691139ad57a3f0b906637673aa2f63d1f55cb1a69199d4009eea23ceaddc9301") 212 pubkey1, _ := hex.DecodeString("04e32df42865e97135acfb65f3bae71bdc86f4d49150ad6a440b6f15878109880a0a2b2667f7e725ceea70c673093bf67663e0312623c8e091b13cf2c0f11ef652") 213 pubkey2, err := RecoverPubkey(msg, sig) 214 if err != nil { 215 t.Fatalf("recover error: %s", err) 216 } 217 if !bytes.Equal(pubkey1, pubkey2) { 218 t.Errorf("pubkey mismatch: want: %x have: %x", pubkey1, pubkey2) 219 } 220 } 221 222 func BenchmarkSign(b *testing.B) { 223 _, seckey := generateKeyPair() 224 msg := csprngEntropy(32) 225 b.ResetTimer() 226 227 for i := 0; i < b.N; i++ { 228 Sign(msg, seckey) 229 } 230 } 231 232 func BenchmarkRecover(b *testing.B) { 233 msg := csprngEntropy(32) 234 _, seckey := generateKeyPair() 235 sig, _ := Sign(msg, seckey) 236 b.ResetTimer() 237 238 for i := 0; i < b.N; i++ { 239 RecoverPubkey(msg, sig) 240 } 241 }