github.com/klaytn/klaytn@v1.12.1/crypto/crypto_test.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2014 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from crypto/crypto_test.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package crypto 22 23 import ( 24 "bytes" 25 "crypto/ecdsa" 26 "encoding/hex" 27 "math/big" 28 "os" 29 "reflect" 30 "runtime" 31 "sync" 32 "testing" 33 34 "github.com/klaytn/klaytn/common" 35 "github.com/klaytn/klaytn/common/hexutil" 36 ) 37 38 var ( 39 testAddrHex = "970e8128ab834e8eac17ab8e3812f010678cf791" 40 testPrivHex = "289c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032" 41 ) 42 43 // These tests are sanity checks. 44 // They should ensure that we don't e.g. use Sha3-224 instead of Sha3-256 45 // and that the sha3 library uses keccak-f permutation. 46 func TestKeccak256Hash(t *testing.T) { 47 msg := []byte("abc") 48 exp, _ := hex.DecodeString("4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45") 49 checkhash(t, "Sha3-256-array", func(in []byte) []byte { h := Keccak256Hash(in); return h[:] }, msg, exp) 50 } 51 52 func TestToECDSAErrors(t *testing.T) { 53 if _, err := HexToECDSA("0000000000000000000000000000000000000000000000000000000000000000"); err == nil { 54 t.Fatal("HexToECDSA should've returned error") 55 } 56 if _, err := HexToECDSA("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); err == nil { 57 t.Fatal("HexToECDSA should've returned error") 58 } 59 } 60 61 func BenchmarkSha3(b *testing.B) { 62 a := []byte("hello world") 63 for i := 0; i < b.N; i++ { 64 Keccak256(a) 65 } 66 } 67 68 func TestUnmarshalPubkey(t *testing.T) { 69 key, err := UnmarshalPubkey(nil) 70 if err != errInvalidPubkey || key != nil { 71 t.Fatalf("expected error, got %v, %v", err, key) 72 } 73 key, err = UnmarshalPubkey([]byte{1, 2, 3}) 74 if err != errInvalidPubkey || key != nil { 75 t.Fatalf("expected error, got %v, %v", err, key) 76 } 77 78 var ( 79 enc, _ = hex.DecodeString("04760c4460e5336ac9bbd87952a3c7ec4363fc0a97bd31c86430806e287b437fd1b01abc6e1db640cf3106b520344af1d58b00b57823db3e1407cbc433e1b6d04d") 80 dec = &ecdsa.PublicKey{ 81 Curve: S256(), 82 X: hexutil.MustDecodeBig("0x760c4460e5336ac9bbd87952a3c7ec4363fc0a97bd31c86430806e287b437fd1"), 83 Y: hexutil.MustDecodeBig("0xb01abc6e1db640cf3106b520344af1d58b00b57823db3e1407cbc433e1b6d04d"), 84 } 85 ) 86 key, err = UnmarshalPubkey(enc) 87 if err != nil { 88 t.Fatalf("expected no error, got %v", err) 89 } 90 if !reflect.DeepEqual(key, dec) { 91 t.Fatal("wrong result") 92 } 93 } 94 95 func TestSign(t *testing.T) { 96 key, _ := HexToECDSA(testPrivHex) 97 addr := common.HexToAddress(testAddrHex) 98 99 msg := Keccak256([]byte("foo")) 100 sig, err := Sign(msg, key) 101 if err != nil { 102 t.Errorf("Sign error: %s", err) 103 } 104 recoveredPub, err := Ecrecover(msg, sig) 105 if err != nil { 106 t.Errorf("ECRecover error: %s", err) 107 } 108 pubKey, _ := UnmarshalPubkey(recoveredPub) 109 recoveredAddr := PubkeyToAddress(*pubKey) 110 if addr != recoveredAddr { 111 t.Errorf("Address mismatch: want: %x have: %x", addr, recoveredAddr) 112 } 113 114 // should be equal to SigToPub 115 recoveredPub2, err := SigToPub(msg, sig) 116 if err != nil { 117 t.Errorf("ECRecover error: %s", err) 118 } 119 recoveredAddr2 := PubkeyToAddress(*recoveredPub2) 120 if addr != recoveredAddr2 { 121 t.Errorf("Address mismatch: want: %x have: %x", addr, recoveredAddr2) 122 } 123 } 124 125 func TestInvalidSign(t *testing.T) { 126 if _, err := Sign(make([]byte, 1), nil); err == nil { 127 t.Errorf("expected sign with hash 1 byte to error") 128 } 129 if _, err := Sign(make([]byte, 33), nil); err == nil { 130 t.Errorf("expected sign with hash 33 byte to error") 131 } 132 } 133 134 func TestNewContractAddress(t *testing.T) { 135 key, _ := HexToECDSA(testPrivHex) 136 addr := common.HexToAddress(testAddrHex) 137 genAddr := PubkeyToAddress(key.PublicKey) 138 // sanity check before using addr to create contract address 139 checkAddr(t, genAddr, addr) 140 141 caddr0 := CreateAddress(addr, 0) 142 caddr1 := CreateAddress(addr, 1) 143 caddr2 := CreateAddress(addr, 2) 144 checkAddr(t, common.HexToAddress("333c3310824b7c685133f2bedb2ca4b8b4df633d"), caddr0) 145 checkAddr(t, common.HexToAddress("8bda78331c916a08481428e4b07c96d3e916d165"), caddr1) 146 checkAddr(t, common.HexToAddress("c9ddedf451bc62ce88bf9292afb13df35b670699"), caddr2) 147 } 148 149 func TestLoadECDSAFile(t *testing.T) { 150 keyBytes := common.FromHex(testPrivHex) 151 fileName0 := "test_key0" 152 fileName1 := "test_key1" 153 checkKey := func(k *ecdsa.PrivateKey) { 154 checkAddr(t, PubkeyToAddress(k.PublicKey), common.HexToAddress(testAddrHex)) 155 loadedKeyBytes := FromECDSA(k) 156 if !bytes.Equal(loadedKeyBytes, keyBytes) { 157 t.Fatalf("private key mismatch: want: %x have: %x", keyBytes, loadedKeyBytes) 158 } 159 } 160 161 os.WriteFile(fileName0, []byte(testPrivHex), 0o600) 162 defer os.Remove(fileName0) 163 164 key0, err := LoadECDSA(fileName0) 165 if err != nil { 166 t.Fatal(err) 167 } 168 checkKey(key0) 169 170 // again, this time with SaveECDSA instead of manual save: 171 err = SaveECDSA(fileName1, key0) 172 if err != nil { 173 t.Fatal(err) 174 } 175 defer os.Remove(fileName1) 176 177 key1, err := LoadECDSA(fileName1) 178 if err != nil { 179 t.Fatal(err) 180 } 181 checkKey(key1) 182 } 183 184 func TestValidateSignatureValues(t *testing.T) { 185 check := func(expected bool, v byte, r, s *big.Int) { 186 if ValidateSignatureValues(v, r, s, false) != expected { 187 t.Errorf("mismatch for v: %d r: %d s: %d want: %v", v, r, s, expected) 188 } 189 } 190 minusOne := big.NewInt(-1) 191 one := common.Big1 192 zero := common.Big0 193 secp256k1nMinus1 := new(big.Int).Sub(secp256k1N, common.Big1) 194 195 // correct v,r,s 196 check(true, 0, one, one) 197 check(true, 1, one, one) 198 // incorrect v, correct r,s, 199 check(false, 2, one, one) 200 check(false, 3, one, one) 201 202 // incorrect v, combinations of incorrect/correct r,s at lower limit 203 check(false, 2, zero, zero) 204 check(false, 2, zero, one) 205 check(false, 2, one, zero) 206 check(false, 2, one, one) 207 208 // correct v for any combination of incorrect r,s 209 check(false, 0, zero, zero) 210 check(false, 0, zero, one) 211 check(false, 0, one, zero) 212 213 check(false, 1, zero, zero) 214 check(false, 1, zero, one) 215 check(false, 1, one, zero) 216 217 // correct sig with max r,s 218 check(true, 0, secp256k1nMinus1, secp256k1nMinus1) 219 // correct v, combinations of incorrect r,s at upper limit 220 check(false, 0, secp256k1N, secp256k1nMinus1) 221 check(false, 0, secp256k1nMinus1, secp256k1N) 222 check(false, 0, secp256k1N, secp256k1N) 223 224 // current callers ensures r,s cannot be negative, but let's test for that too 225 // as crypto package could be used stand-alone 226 check(false, 0, minusOne, one) 227 check(false, 0, one, minusOne) 228 } 229 230 func checkhash(t *testing.T, name string, f func([]byte) []byte, msg, exp []byte) { 231 sum := f(msg) 232 if !bytes.Equal(exp, sum) { 233 t.Fatalf("hash %s mismatch: want: %x have: %x", name, exp, sum) 234 } 235 } 236 237 func checkAddr(t *testing.T, addr0, addr1 common.Address) { 238 if addr0 != addr1 { 239 t.Fatalf("address mismatch: want: %x have: %x", addr0, addr1) 240 } 241 } 242 243 // test to help Python team with integration of libsecp256k1 244 // skip but keep it after they are done 245 func TestPythonIntegration(t *testing.T) { 246 kh := "289c2857d4598e37fb9647507e47a309d6133539bf21a8b9cb6df88fd5232032" 247 k0, _ := HexToECDSA(kh) 248 249 msg0 := Keccak256([]byte("foo")) 250 sig0, _ := Sign(msg0, k0) 251 252 msg1 := common.FromHex("00000000000000000000000000000000") 253 sig1, _ := Sign(msg0, k0) 254 255 t.Logf("msg: %x, privkey: %s sig: %x\n", msg0, kh, sig0) 256 t.Logf("msg: %x, privkey: %s sig: %x\n", msg1, kh, sig1) 257 } 258 259 func BenchmarkEcrecover(b *testing.B) { 260 data, sigs := generateBenchmarkMaterial(b.N) 261 b.ResetTimer() 262 for i := 0; i < b.N; i++ { 263 Ecrecover(data, sigs[i]) 264 } 265 } 266 267 func BenchmarkParallelEcrecover(b *testing.B) { 268 run := func(size int) func(b *testing.B) { 269 return func(b *testing.B) { 270 data, sigs := generateBenchmarkMaterial(size) 271 b.ResetTimer() 272 for i := 0; i < b.N; i++ { 273 parallelEcrecover(data, sigs) 274 } 275 } 276 } 277 278 b.Run("1", run(1)) 279 b.Run("30", run(30)) 280 b.Run("100", run(100)) 281 b.Run("1000", run(1000)) 282 } 283 284 func generateBenchmarkMaterial(L int) (data []byte, sigs [][]byte) { 285 data = common.HexToHash("0xabcd").Bytes() 286 sigs = make([][]byte, L) 287 for i := 0; i < L; i++ { 288 // any nonzero integer less than the order is a valid privkey 289 priv := ToECDSAUnsafe(big.NewInt(int64(i + 1)).Bytes()) 290 sig, _ := Sign(data, priv) 291 sigs[i] = sig 292 } 293 return 294 } 295 296 func parallelEcrecover(data []byte, sigs [][]byte) { 297 threads := runtime.NumCPU() 298 var wg sync.WaitGroup 299 wg.Add(threads) 300 301 jobs := make(chan []byte, len(sigs)) 302 for _, sig := range sigs { 303 jobs <- sig 304 } 305 306 for i := 0; i < threads; i++ { 307 go func() { 308 for sig := range jobs { 309 Ecrecover(data, sig) 310 } 311 wg.Done() 312 }() 313 } 314 315 close(jobs) 316 wg.Wait() 317 }