github.com/klaytn/klaytn@v1.12.1/crypto/signature_nocgo.go (about) 1 // Modifications Copyright 2023 The klaytn Authors 2 // Copyright 2017 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/signature_cgo.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 //go:build nacl || js || !cgo || gofuzz 22 // +build nacl js !cgo gofuzz 23 24 package crypto 25 26 import ( 27 "crypto/ecdsa" 28 "crypto/elliptic" 29 "errors" 30 "fmt" 31 32 "github.com/btcsuite/btcd/btcec/v2" 33 btc_ecdsa "github.com/btcsuite/btcd/btcec/v2/ecdsa" 34 ) 35 36 // Ecrecover returns the uncompressed public key that created the given signature. 37 func Ecrecover(hash, sig []byte) ([]byte, error) { 38 pub, err := sigToPub(hash, sig) 39 if err != nil { 40 return nil, err 41 } 42 bytes := pub.SerializeUncompressed() 43 return bytes, err 44 } 45 46 func sigToPub(hash, sig []byte) (*btcec.PublicKey, error) { 47 if len(sig) != SignatureLength { 48 return nil, errors.New("invalid signature") 49 } 50 // Convert to btcec input format with 'recovery id' v at the beginning. 51 btcsig := make([]byte, SignatureLength) 52 btcsig[0] = sig[RecoveryIDOffset] + 27 53 copy(btcsig[1:], sig) 54 55 pub, _, err := btc_ecdsa.RecoverCompact(btcsig, hash) 56 return pub, err 57 } 58 59 // SigToPub returns the public key that created the given signature. 60 func SigToPub(hash, sig []byte) (*ecdsa.PublicKey, error) { 61 pub, err := sigToPub(hash, sig) 62 if err != nil { 63 return nil, err 64 } 65 return pub.ToECDSA(), nil 66 } 67 68 // Sign calculates an ECDSA signature. 69 // 70 // This function is susceptible to chosen plaintext attacks that can leak 71 // information about the private key that is used for signing. Callers must 72 // be aware that the given hash cannot be chosen by an adversary. Common 73 // solution is to hash any input before calculating the signature. 74 // 75 // The produced signature is in the [R || S || V] format where V is 0 or 1. 76 func Sign(hash []byte, prv *ecdsa.PrivateKey) ([]byte, error) { 77 if len(hash) != 32 { 78 return nil, fmt.Errorf("hash is required to be exactly 32 bytes (%d)", len(hash)) 79 } 80 if prv.Curve != btcec.S256() { 81 return nil, errors.New("private key curve is not secp256k1") 82 } 83 // ecdsa.PrivateKey -> btcec.PrivateKey 84 var priv btcec.PrivateKey 85 if overflow := priv.Key.SetByteSlice(prv.D.Bytes()); overflow || priv.Key.IsZero() { 86 return nil, errors.New("invalid private key") 87 } 88 defer priv.Zero() 89 sig, err := btc_ecdsa.SignCompact(&priv, hash, false) // ref uncompressed pubkey 90 if err != nil { 91 return nil, err 92 } 93 // Convert to Ethereum signature format with 'recovery id' v at the end. 94 v := sig[0] - 27 95 copy(sig, sig[1:]) 96 sig[RecoveryIDOffset] = v 97 return sig, nil 98 } 99 100 // VerifySignature checks that the given public key created signature over hash. 101 // The public key should be in compressed (33 bytes) or uncompressed (65 bytes) format. 102 // The signature should have the 64 byte [R || S] format. 103 func VerifySignature(pubkey, hash, signature []byte) bool { 104 if len(signature) != 64 { 105 return false 106 } 107 var r, s btcec.ModNScalar 108 if r.SetByteSlice(signature[:32]) { 109 return false // overflow 110 } 111 if s.SetByteSlice(signature[32:]) { 112 return false 113 } 114 sig := btc_ecdsa.NewSignature(&r, &s) 115 key, err := btcec.ParsePubKey(pubkey) 116 if err != nil { 117 return false 118 } 119 // Reject malleable signatures. libsecp256k1 does this check but btcec doesn't. 120 if s.IsOverHalfOrder() { 121 return false 122 } 123 return sig.Verify(hash, key) 124 } 125 126 // DecompressPubkey parses a public key in the 33-byte compressed format. 127 func DecompressPubkey(pubkey []byte) (*ecdsa.PublicKey, error) { 128 if len(pubkey) != 33 { 129 return nil, errors.New("invalid compressed public key length") 130 } 131 key, err := btcec.ParsePubKey(pubkey) 132 if err != nil { 133 return nil, err 134 } 135 return key.ToECDSA(), nil 136 } 137 138 // CompressPubkey encodes a public key to the 33-byte compressed format. The 139 // provided PublicKey must be valid. Namely, the coordinates must not be larger 140 // than 32 bytes each, they must be less than the field prime, and it must be a 141 // point on the secp256k1 curve. This is the case for a PublicKey constructed by 142 // elliptic.Unmarshal (see UnmarshalPubkey), or by ToECDSA and ecdsa.GenerateKey 143 // when constructing a PrivateKey. 144 func CompressPubkey(pubkey *ecdsa.PublicKey) []byte { 145 // NOTE: the coordinates may be validated with 146 // btcec.ParsePubKey(FromECDSAPub(pubkey)) 147 var x, y btcec.FieldVal 148 x.SetByteSlice(pubkey.X.Bytes()) 149 y.SetByteSlice(pubkey.Y.Bytes()) 150 return btcec.NewPublicKey(&x, &y).SerializeCompressed() 151 } 152 153 // S256 returns an instance of the secp256k1 curve. 154 func S256() elliptic.Curve { 155 return btcec.S256() 156 }