github.com/immesys/bw2bc@v1.1.0/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./secp256k1 23 #cgo darwin CFLAGS: -I/usr/local/include 24 #cgo freebsd CFLAGS: -I/usr/local/include 25 #cgo linux,arm CFLAGS: -I/usr/local/arm/include 26 #cgo LDFLAGS: -lgmp 27 #cgo darwin LDFLAGS: -L/usr/local/lib 28 #cgo freebsd LDFLAGS: -L/usr/local/lib 29 #cgo linux,arm LDFLAGS: -L/usr/local/arm/lib 30 #define USE_NUM_GMP 31 #define USE_FIELD_10X26 32 #define USE_FIELD_INV_BUILTIN 33 #define USE_SCALAR_8X32 34 #define USE_SCALAR_INV_BUILTIN 35 #define NDEBUG 36 #include "./secp256k1/src/secp256k1.c" 37 */ 38 import "C" 39 40 import ( 41 "bytes" 42 "errors" 43 "unsafe" 44 45 "github.com/ethereum/go-ethereum/crypto/randentropy" 46 ) 47 48 //#define USE_FIELD_5X64 49 50 /* 51 Todo: 52 > Centralize key management in module 53 > add pubkey/private key struct 54 > Dont let keys leave module; address keys as ints 55 56 > store private keys in buffer and shuffle (deters persistance on swap disc) 57 > Byte permutation (changing) 58 > xor with chaning random block (to deter scanning memory for 0x63) (stream cipher?) 59 60 On Disk 61 > Store keys in wallets 62 > use slow key derivation function for wallet encryption key (2 seconds) 63 */ 64 65 func init() { 66 //takes 10ms to 100ms 67 C.secp256k1_start(3) // SECP256K1_START_SIGN | SECP256K1_START_VERIFY 68 } 69 70 func Stop() { 71 C.secp256k1_stop() 72 } 73 74 func GenerateKeyPair() ([]byte, []byte) { 75 76 pubkey_len := C.int(65) 77 const seckey_len = 32 78 79 var pubkey []byte = make([]byte, pubkey_len) 80 var seckey []byte = randentropy.GetEntropyCSPRNG(seckey_len) 81 82 var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0])) 83 var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) 84 85 ret := C.secp256k1_ec_pubkey_create( 86 pubkey_ptr, &pubkey_len, 87 seckey_ptr, 0) 88 89 if ret != C.int(1) { 90 return GenerateKeyPair() //invalid secret, try again 91 } 92 return pubkey, seckey 93 } 94 95 func GeneratePubKey(seckey []byte) ([]byte, error) { 96 if err := VerifySeckeyValidity(seckey); err != nil { 97 return nil, err 98 } 99 100 pubkey_len := C.int(65) 101 const seckey_len = 32 102 103 var pubkey []byte = make([]byte, pubkey_len) 104 105 var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0])) 106 var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) 107 108 ret := C.secp256k1_ec_pubkey_create( 109 pubkey_ptr, &pubkey_len, 110 seckey_ptr, 0) 111 112 if ret != C.int(1) { 113 return nil, errors.New("Unable to generate pubkey from seckey") 114 } 115 116 return pubkey, nil 117 } 118 119 func Sign(msg []byte, seckey []byte) ([]byte, error) { 120 nonce := randentropy.GetEntropyCSPRNG(32) 121 122 var sig []byte = make([]byte, 65) 123 var recid C.int 124 125 var msg_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&msg[0])) 126 var sig_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&sig[0])) 127 var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) 128 129 var noncefp_ptr = &(*C.secp256k1_nonce_function_default) 130 var ndata_ptr = unsafe.Pointer(&nonce[0]) 131 132 if C.secp256k1_ec_seckey_verify(seckey_ptr) != C.int(1) { 133 return nil, errors.New("Invalid secret key") 134 } 135 136 ret := C.secp256k1_ecdsa_sign_compact( 137 msg_ptr, 138 sig_ptr, 139 seckey_ptr, 140 noncefp_ptr, 141 ndata_ptr, 142 &recid) 143 144 sig[64] = byte(int(recid)) 145 146 if ret != C.int(1) { 147 // nonce invalid, retry 148 return Sign(msg, seckey) 149 } 150 151 return sig, nil 152 153 } 154 155 func VerifySeckeyValidity(seckey []byte) error { 156 if len(seckey) != 32 { 157 return errors.New("priv key is not 32 bytes") 158 } 159 var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) 160 ret := C.secp256k1_ec_seckey_verify(seckey_ptr) 161 if int(ret) != 1 { 162 return errors.New("invalid seckey") 163 } 164 return nil 165 } 166 167 func VerifyPubkeyValidity(pubkey []byte) error { 168 if len(pubkey) != 65 { 169 return errors.New("pub key is not 65 bytes") 170 } 171 var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0])) 172 ret := C.secp256k1_ec_pubkey_verify(pubkey_ptr, 65) 173 if int(ret) != 1 { 174 return errors.New("invalid pubkey") 175 } 176 177 return nil 178 } 179 180 func VerifySignatureValidity(sig []byte) bool { 181 //64+1 182 if len(sig) != 65 { 183 return false 184 } 185 //malleability check, highest bit must be 1 186 if (sig[32] & 0x80) == 0x80 { 187 return false 188 } 189 //recovery id check 190 if sig[64] >= 4 { 191 return false 192 } 193 194 return true 195 } 196 197 //for compressed signatures, does not need pubkey 198 func VerifySignature(msg []byte, sig []byte, pubkey1 []byte) error { 199 if msg == nil || sig == nil || pubkey1 == nil { 200 return errors.New("inputs must be non-nil") 201 } 202 if len(sig) != 65 { 203 return errors.New("invalid signature length") 204 } 205 if len(pubkey1) != 65 { 206 return errors.New("Invalid public key length") 207 } 208 209 //to enforce malleability, highest bit of S must be 0 210 //S starts at 32nd byte 211 if (sig[32] & 0x80) == 0x80 { //highest bit must be 1 212 return errors.New("Signature not malleable") 213 } 214 215 if sig[64] >= 4 { 216 return errors.New("Recover byte invalid") 217 } 218 219 // if pubkey recovered, signature valid 220 pubkey2, err := RecoverPubkey(msg, sig) 221 if err != nil { 222 return err 223 } 224 if len(pubkey2) != 65 { 225 return errors.New("Invalid recovered public key length") 226 } 227 if !bytes.Equal(pubkey1, pubkey2) { 228 return errors.New("Public key does not match recovered public key") 229 } 230 231 return nil 232 } 233 234 //recovers the public key from the signature 235 //recovery of pubkey means correct signature 236 func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) { 237 if len(sig) != 65 { 238 return nil, errors.New("Invalid signature length") 239 } 240 241 var pubkey []byte = make([]byte, 65) 242 243 var msg_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&msg[0])) 244 var sig_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&sig[0])) 245 var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0])) 246 247 var pubkeylen C.int 248 249 ret := C.secp256k1_ecdsa_recover_compact( 250 msg_ptr, 251 sig_ptr, 252 pubkey_ptr, 253 &pubkeylen, 254 C.int(0), 255 C.int(sig[64]), 256 ) 257 258 if ret == C.int(0) { 259 return nil, errors.New("Failed to recover public key") 260 } else if pubkeylen != C.int(65) { 261 return nil, errors.New("Impossible Error: Invalid recovered public key length") 262 } else { 263 return pubkey, nil 264 } 265 return nil, errors.New("Impossible Error: func RecoverPubkey has reached an unreachable state") 266 }