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