github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/crypto/secp256k1/secp256.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 // TODO: set USE_SCALAR_4X64 depending on platform? 20 21 /* 22 #cgo CFLAGS: -I./libsecp256k1 23 #cgo CFLAGS: -I./libsecp256k1/src/ 24 #define USE_NUM_NONE 25 #define USE_FIELD_10X26 26 #define USE_FIELD_INV_BUILTIN 27 #define USE_SCALAR_8X32 28 #define USE_SCALAR_INV_BUILTIN 29 #define NDEBUG 30 #include "./libsecp256k1/src/secp256k1.c" 31 #include "./libsecp256k1/src/modules/recovery/main_impl.h" 32 #include "pubkey_scalar_mul.h" 33 34 typedef void (*callbackFunc) (const char* msg, void* data); 35 extern void secp256k1GoPanicIllegal(const char* msg, void* data); 36 extern void secp256k1GoPanicError(const char* msg, void* data); 37 */ 38 import "C" 39 40 import ( 41 "errors" 42 "math/big" 43 "unsafe" 44 45 "github.com/ethereumproject/go-ethereum/crypto/randentropy" 46 ) 47 48 //#define USE_FIELD_5X64 49 50 /* 51 TODO: 52 > store private keys in buffer and shuffle (deters persistance on swap disc) 53 > byte permutation (changing) 54 > xor with chaning random block (to deter scanning memory for 0x63) (stream cipher?) 55 */ 56 57 // holds ptr to secp256k1_context_struct (see secp256k1/include/secp256k1.h) 58 var ( 59 context *C.secp256k1_context 60 N *big.Int 61 HalfN *big.Int 62 ) 63 64 func init() { 65 N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16) 66 // N / 2 == 57896044618658097711785492504343953926418782139537452191302581570759080747168 67 HalfN, _ = new(big.Int).SetString("7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0", 16) 68 69 // around 20 ms on a modern CPU. 70 context = C.secp256k1_context_create(3) // SECP256K1_START_SIGN | SECP256K1_START_VERIFY 71 C.secp256k1_context_set_illegal_callback(context, C.callbackFunc(C.secp256k1GoPanicIllegal), nil) 72 C.secp256k1_context_set_error_callback(context, C.callbackFunc(C.secp256k1GoPanicError), nil) 73 } 74 75 var ( 76 ErrInvalidMsgLen = errors.New("invalid message length for signature recovery") 77 ErrInvalidSignatureLen = errors.New("invalid signature length") 78 ErrInvalidRecoveryID = errors.New("invalid signature recovery id") 79 ErrInvalidKey = errors.New("invalid private key") 80 ErrInvalidPubkey = errors.New("invalid public key") 81 ErrSignFailed = errors.New("signing failed") 82 ErrRecoverFailed = errors.New("recovery failed") 83 ) 84 85 func GenerateKeyPair() ([]byte, []byte) { 86 var seckey []byte = randentropy.GetEntropyCSPRNG(32) 87 var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) 88 var pubkey64 []byte = make([]byte, 64) // secp256k1_pubkey 89 var pubkey65 []byte = make([]byte, 65) // 65 byte uncompressed pubkey 90 pubkey64_ptr := (*C.secp256k1_pubkey)(unsafe.Pointer(&pubkey64[0])) 91 pubkey65_ptr := (*C.uchar)(unsafe.Pointer(&pubkey65[0])) 92 93 ret := C.secp256k1_ec_pubkey_create( 94 context, 95 pubkey64_ptr, 96 seckey_ptr, 97 ) 98 99 if ret != C.int(1) { 100 return GenerateKeyPair() // invalid secret, try again 101 } 102 103 var output_len C.size_t 104 105 C.secp256k1_ec_pubkey_serialize( // always returns 1 106 context, 107 pubkey65_ptr, 108 &output_len, 109 pubkey64_ptr, 110 0, // SECP256K1_EC_COMPRESSED 111 ) 112 113 return pubkey65, seckey 114 } 115 116 func GeneratePubKey(seckey []byte) ([]byte, error) { 117 if err := VerifySeckeyValidity(seckey); err != nil { 118 return nil, err 119 } 120 121 var pubkey []byte = make([]byte, 64) 122 var pubkey_ptr *C.secp256k1_pubkey = (*C.secp256k1_pubkey)(unsafe.Pointer(&pubkey[0])) 123 124 var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) 125 126 ret := C.secp256k1_ec_pubkey_create( 127 context, 128 pubkey_ptr, 129 seckey_ptr, 130 ) 131 132 if ret != C.int(1) { 133 return nil, errors.New("Unable to generate pubkey from seckey") 134 } 135 136 return pubkey, nil 137 } 138 139 // SignNondeterministic generates nondeterministic signature b/c of a random k-value in the ECDSA algorithm. This function is included 140 // only for purpose of demonstration and comparison with the deterministic Sign function. 141 func SignNondeterministic(msg []byte, seckey []byte) ([]byte, error) { 142 msg_ptr := (*C.uchar)(unsafe.Pointer(&msg[0])) 143 seckey_ptr := (*C.uchar)(unsafe.Pointer(&seckey[0])) 144 145 sig := make([]byte, 65) 146 sig_ptr := (*C.secp256k1_ecdsa_recoverable_signature)(unsafe.Pointer(&sig[0])) 147 148 nonce := randentropy.GetEntropyCSPRNG(32) 149 ndata_ptr := unsafe.Pointer(&nonce[0]) 150 151 noncefp_ptr := &(*C.secp256k1_nonce_function_default) 152 153 if C.secp256k1_ec_seckey_verify(context, seckey_ptr) != C.int(1) { 154 return nil, errors.New("Invalid secret key") 155 } 156 157 ret := C.secp256k1_ecdsa_sign_recoverable( 158 context, 159 sig_ptr, 160 msg_ptr, 161 seckey_ptr, 162 noncefp_ptr, 163 ndata_ptr, 164 ) 165 166 if ret == C.int(0) { 167 return Sign(msg, seckey) //invalid secret, try again 168 } 169 170 sig_serialized := make([]byte, 65) 171 sig_serialized_ptr := (*C.uchar)(unsafe.Pointer(&sig_serialized[0])) 172 var recid C.int 173 174 C.secp256k1_ecdsa_recoverable_signature_serialize_compact( 175 context, 176 sig_serialized_ptr, // 64 byte compact signature 177 &recid, 178 sig_ptr, // 65 byte "recoverable" signature 179 ) 180 181 sig_serialized[64] = byte(int(recid)) // add back recid to get 65 bytes sig 182 183 return sig_serialized, nil 184 185 } 186 187 // Sign creates a recoverable ECDSA signature. 188 // The produced signature is in the 65-byte [R || S || V] format where V is 0 or 1. 189 // 190 // The caller is responsible for ensuring that msg cannot be chosen 191 // directly by an attacker. It is usually preferable to use a cryptographic 192 // hash function on any input before handing it to this function. 193 func Sign(msg []byte, seckey []byte) ([]byte, error) { 194 if len(msg) != 32 { 195 return nil, ErrInvalidMsgLen 196 } 197 if len(seckey) != 32 { 198 return nil, ErrInvalidKey 199 } 200 seckeydata := (*C.uchar)(unsafe.Pointer(&seckey[0])) 201 if C.secp256k1_ec_seckey_verify(context, seckeydata) != 1 { 202 return nil, ErrInvalidKey 203 } 204 205 var ( 206 msgdata = (*C.uchar)(unsafe.Pointer(&msg[0])) 207 noncefunc = C.secp256k1_nonce_function_rfc6979 208 sigstruct C.secp256k1_ecdsa_recoverable_signature 209 ) 210 if C.secp256k1_ecdsa_sign_recoverable(context, &sigstruct, msgdata, seckeydata, noncefunc, nil) == 0 { 211 return nil, ErrSignFailed 212 } 213 214 var ( 215 sig = make([]byte, 65) 216 sigdata = (*C.uchar)(unsafe.Pointer(&sig[0])) 217 recid C.int 218 ) 219 C.secp256k1_ecdsa_recoverable_signature_serialize_compact(context, sigdata, &recid, &sigstruct) 220 sig[64] = byte(recid) // add back recid to get 65 bytes sig 221 return sig, nil 222 } 223 224 func VerifySeckeyValidity(seckey []byte) error { 225 if len(seckey) != 32 { 226 return errors.New("priv key is not 32 bytes") 227 } 228 var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) 229 ret := C.secp256k1_ec_seckey_verify(context, seckey_ptr) 230 if int(ret) != 1 { 231 return errors.New("invalid seckey") 232 } 233 return nil 234 } 235 236 // RecoverPubkey returns the the public key of the signer. 237 // msg must be the 32-byte hash of the message to be signed. 238 // sig must be a 65-byte compact ECDSA signature containing the 239 // recovery id as the last element. 240 func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) { 241 if len(msg) != 32 { 242 return nil, ErrInvalidMsgLen 243 } 244 if err := checkSignature(sig); err != nil { 245 return nil, err 246 } 247 248 msg_ptr := (*C.uchar)(unsafe.Pointer(&msg[0])) 249 sig_ptr := (*C.uchar)(unsafe.Pointer(&sig[0])) 250 pubkey := make([]byte, 64) 251 /* 252 this slice is used for both the recoverable signature and the 253 resulting serialized pubkey (both types in libsecp256k1 are 65 254 bytes). this saves one allocation of 65 bytes, which is nice as 255 pubkey recovery is one bottleneck during load in Ethereum 256 */ 257 bytes65 := make([]byte, 65) 258 pubkey_ptr := (*C.secp256k1_pubkey)(unsafe.Pointer(&pubkey[0])) 259 recoverable_sig_ptr := (*C.secp256k1_ecdsa_recoverable_signature)(unsafe.Pointer(&bytes65[0])) 260 recid := C.int(sig[64]) 261 262 ret := C.secp256k1_ecdsa_recoverable_signature_parse_compact( 263 context, 264 recoverable_sig_ptr, 265 sig_ptr, 266 recid) 267 if ret == C.int(0) { 268 return nil, errors.New("Failed to parse signature") 269 } 270 271 ret = C.secp256k1_ecdsa_recover( 272 context, 273 pubkey_ptr, 274 recoverable_sig_ptr, 275 msg_ptr, 276 ) 277 if ret == C.int(0) { 278 return nil, errors.New("Failed to recover public key") 279 } 280 281 serialized_pubkey_ptr := (*C.uchar)(unsafe.Pointer(&bytes65[0])) 282 var output_len C.size_t 283 C.secp256k1_ec_pubkey_serialize( // always returns 1 284 context, 285 serialized_pubkey_ptr, 286 &output_len, 287 pubkey_ptr, 288 0, // SECP256K1_EC_COMPRESSED 289 ) 290 return bytes65, nil 291 } 292 293 func checkSignature(sig []byte) error { 294 if len(sig) != 65 { 295 return ErrInvalidSignatureLen 296 } 297 if sig[64] >= 4 { 298 return ErrInvalidRecoveryID 299 } 300 return nil 301 } 302 303 // reads num into buf as big-endian bytes. 304 func readBits(buf []byte, num *big.Int) { 305 const wordLen = int(unsafe.Sizeof(big.Word(0))) 306 i := len(buf) 307 for _, d := range num.Bits() { 308 for j := 0; j < wordLen && i > 0; j++ { 309 i-- 310 buf[i] = byte(d) 311 d >>= 8 312 } 313 } 314 }