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