github.com/jonasnick/go-ethereum@v0.7.12-0.20150216215225-22176f05d387/crypto/secp256k1/secp256.go (about) 1 package secp256k1 2 3 /* 4 #cgo CFLAGS: -std=gnu99 -Wno-error 5 #cgo darwin CFLAGS: -I/usr/local/include 6 #cgo LDFLAGS: -lgmp 7 #cgo darwin LDFLAGS: -L/usr/local/lib 8 #define USE_FIELD_10X26 9 #define USE_NUM_GMP 10 #define USE_FIELD_INV_BUILTIN 11 #include "./secp256k1/src/secp256k1.c" 12 */ 13 import "C" 14 15 import ( 16 "bytes" 17 "errors" 18 "unsafe" 19 20 "github.com/jonasnick/go-ethereum/crypto/randentropy" 21 ) 22 23 //#define USE_FIELD_5X64 24 25 /* 26 Todo: 27 > Centralize key management in module 28 > add pubkey/private key struct 29 > Dont let keys leave module; address keys as ints 30 31 > store private keys in buffer and shuffle (deters persistance on swap disc) 32 > Byte permutation (changing) 33 > xor with chaning random block (to deter scanning memory for 0x63) (stream cipher?) 34 35 On Disk 36 > Store keys in wallets 37 > use slow key derivation function for wallet encryption key (2 seconds) 38 */ 39 40 func init() { 41 C.secp256k1_start() //takes 10ms to 100ms 42 } 43 44 func Stop() { 45 C.secp256k1_stop() 46 } 47 48 /* 49 int secp256k1_ecdsa_pubkey_create( 50 unsigned char *pubkey, int *pubkeylen, 51 const unsigned char *seckey, int compressed); 52 */ 53 54 /** Compute the public key for a secret key. 55 * In: compressed: whether the computed public key should be compressed 56 * seckey: pointer to a 32-byte private key. 57 * Out: pubkey: pointer to a 33-byte (if compressed) or 65-byte (if uncompressed) 58 * area to store the public key. 59 * pubkeylen: pointer to int that will be updated to contains the pubkey's 60 * length. 61 * Returns: 1: secret was valid, public key stores 62 * 0: secret was invalid, try again. 63 */ 64 65 //pubkey, seckey 66 67 func GenerateKeyPair() ([]byte, []byte) { 68 69 pubkey_len := C.int(65) 70 const seckey_len = 32 71 72 var pubkey []byte = make([]byte, pubkey_len) 73 var seckey []byte = randentropy.GetEntropyMixed(seckey_len) 74 75 var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0])) 76 var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) 77 78 ret := C.secp256k1_ecdsa_pubkey_create( 79 pubkey_ptr, &pubkey_len, 80 seckey_ptr, 0) 81 82 if ret != C.int(1) { 83 return GenerateKeyPair() //invalid secret, try again 84 } 85 return pubkey, seckey 86 } 87 88 func GeneratePubKey(seckey []byte) ([]byte, error) { 89 if err := VerifySeckeyValidity(seckey); err != nil { 90 return nil, err 91 } 92 93 pubkey_len := C.int(65) 94 const seckey_len = 32 95 96 var pubkey []byte = make([]byte, pubkey_len) 97 98 var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0])) 99 var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) 100 101 ret := C.secp256k1_ecdsa_pubkey_create( 102 pubkey_ptr, &pubkey_len, 103 seckey_ptr, 0) 104 105 if ret != C.int(1) { 106 return nil, errors.New("Unable to generate pubkey from seckey") 107 } 108 109 return pubkey, nil 110 } 111 112 /* 113 * Create a compact ECDSA signature (64 byte + recovery id). 114 * Returns: 1: signature created 115 * 0: nonce invalid, try another one 116 * In: msg: the message being signed 117 * msglen: the length of the message being signed 118 * seckey: pointer to a 32-byte secret key (assumed to be valid) 119 * nonce: pointer to a 32-byte nonce (generated with a cryptographic PRNG) 120 * Out: sig: pointer to a 64-byte array where the signature will be placed. 121 * recid: pointer to an int, which will be updated to contain the recovery id. 122 */ 123 124 /* 125 int secp256k1_ecdsa_sign_compact(const unsigned char *msg, int msglen, 126 unsigned char *sig64, 127 const unsigned char *seckey, 128 const unsigned char *nonce, 129 int *recid); 130 */ 131 132 func Sign(msg []byte, seckey []byte) ([]byte, error) { 133 nonce := randentropy.GetEntropyMixed(32) 134 135 var sig []byte = make([]byte, 65) 136 var recid C.int 137 138 var msg_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&msg[0])) 139 var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) 140 var nonce_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&nonce[0])) 141 var sig_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&sig[0])) 142 143 if C.secp256k1_ecdsa_seckey_verify(seckey_ptr) != C.int(1) { 144 return nil, errors.New("Invalid secret key") 145 } 146 147 ret := C.secp256k1_ecdsa_sign_compact( 148 msg_ptr, C.int(len(msg)), 149 sig_ptr, 150 seckey_ptr, 151 nonce_ptr, 152 &recid) 153 154 sig[64] = byte(int(recid)) 155 156 if ret != C.int(1) { 157 // nonce invalid, retry 158 return Sign(msg, seckey) 159 } 160 161 return sig, nil 162 163 } 164 165 /* 166 * Verify an ECDSA secret key. 167 * Returns: 1: secret key is valid 168 * 0: secret key is invalid 169 * In: seckey: pointer to a 32-byte secret key 170 */ 171 172 func VerifySeckeyValidity(seckey []byte) error { 173 if len(seckey) != 32 { 174 return errors.New("priv key is not 32 bytes") 175 } 176 var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) 177 ret := C.secp256k1_ecdsa_seckey_verify(seckey_ptr) 178 if int(ret) != 1 { 179 return errors.New("invalid seckey") 180 } 181 return nil 182 } 183 184 /* 185 * Validate a public key. 186 * Returns: 1: valid public key 187 * 0: invalid public key 188 */ 189 190 func VerifyPubkeyValidity(pubkey []byte) error { 191 if len(pubkey) != 65 { 192 return errors.New("pub key is not 65 bytes") 193 } 194 var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0])) 195 ret := C.secp256k1_ecdsa_pubkey_verify(pubkey_ptr, 65) 196 if int(ret) != 1 { 197 return errors.New("invalid pubkey") 198 } 199 200 return nil 201 } 202 203 func VerifySignatureValidity(sig []byte) bool { 204 //64+1 205 if len(sig) != 65 { 206 return false 207 } 208 //malleability check, highest bit must be 1 209 if (sig[32] & 0x80) == 0x80 { 210 return false 211 } 212 //recovery id check 213 if sig[64] >= 4 { 214 return false 215 } 216 217 return true 218 } 219 220 //for compressed signatures, does not need pubkey 221 func VerifySignature(msg []byte, sig []byte, pubkey1 []byte) error { 222 if msg == nil || sig == nil || pubkey1 == nil { 223 return errors.New("inputs must be non-nil") 224 } 225 if len(sig) != 65 { 226 return errors.New("invalid signature length") 227 } 228 if len(pubkey1) != 65 { 229 return errors.New("Invalid public key length") 230 } 231 232 //to enforce malleability, highest bit of S must be 0 233 //S starts at 32nd byte 234 if (sig[32] & 0x80) == 0x80 { //highest bit must be 1 235 return errors.New("Signature not malleable") 236 } 237 238 if sig[64] >= 4 { 239 return errors.New("Recover byte invalid") 240 } 241 242 // if pubkey recovered, signature valid 243 pubkey2, err := RecoverPubkey(msg, sig) 244 if err != nil { 245 return err 246 } 247 if len(pubkey2) != 65 { 248 return errors.New("Invalid recovered public key length") 249 } 250 if !bytes.Equal(pubkey1, pubkey2) { 251 return errors.New("Public key does not match recovered public key") 252 } 253 254 return nil 255 } 256 257 /* 258 int secp256k1_ecdsa_recover_compact(const unsigned char *msg, int msglen, 259 const unsigned char *sig64, 260 unsigned char *pubkey, int *pubkeylen, 261 int compressed, int recid); 262 */ 263 264 /* 265 * Recover an ECDSA public key from a compact signature. 266 * Returns: 1: public key succesfully recovered (which guarantees a correct signature). 267 * 0: otherwise. 268 * In: msg: the message assumed to be signed 269 * msglen: the length of the message 270 * compressed: whether to recover a compressed or uncompressed pubkey 271 * recid: the recovery id (as returned by ecdsa_sign_compact) 272 * Out: pubkey: pointer to a 33 or 65 byte array to put the pubkey. 273 * pubkeylen: pointer to an int that will contain the pubkey length. 274 */ 275 276 //recovers the public key from the signature 277 //recovery of pubkey means correct signature 278 func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) { 279 if len(sig) != 65 { 280 return nil, errors.New("Invalid signature length") 281 } 282 283 var pubkey []byte = make([]byte, 65) 284 285 var msg_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&msg[0])) 286 var sig_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&sig[0])) 287 var pubkey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&pubkey[0])) 288 289 var pubkeylen C.int 290 291 ret := C.secp256k1_ecdsa_recover_compact( 292 msg_ptr, C.int(len(msg)), 293 sig_ptr, 294 pubkey_ptr, &pubkeylen, 295 C.int(0), C.int(sig[64]), 296 ) 297 298 if ret == C.int(0) { 299 return nil, errors.New("Failed to recover public key") 300 } else if pubkeylen != C.int(65) { 301 return nil, errors.New("Impossible Error: Invalid recovered public key length") 302 } else { 303 return pubkey, nil 304 } 305 return nil, errors.New("Impossible Error: func RecoverPubkey has reached an unreachable state") 306 }