func GenerateKeyPair() ([]byte, []byte) { var seckey []byte = randentropy.GetEntropyCSPRNG(32) var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0])) var pubkey64 []byte = make([]byte, 64) // secp256k1_pubkey var pubkey65 []byte = make([]byte, 65) // 65 byte uncompressed pubkey pubkey64_ptr := (*C.secp256k1_pubkey)(unsafe.Pointer(&pubkey64[0])) pubkey65_ptr := (*C.uchar)(unsafe.Pointer(&pubkey65[0])) ret := C.secp256k1_ec_pubkey_create( context, pubkey64_ptr, seckey_ptr, ) if ret != C.int(1) { return GenerateKeyPair() // invalid secret, try again } var output_len C.size_t C.secp256k1_ec_pubkey_serialize( // always returns 1 context, pubkey65_ptr, &output_len, pubkey64_ptr, 0, // SECP256K1_EC_COMPRESSED ) return pubkey65, seckey }
// recovers a public key from the signature func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) { if len(sig) != 65 { return nil, errors.New("Invalid signature length") } msg_ptr := (*C.uchar)(unsafe.Pointer(&msg[0])) sig_ptr := (*C.uchar)(unsafe.Pointer(&sig[0])) pubkey := make([]byte, 64) /* this slice is used for both the recoverable signature and the resulting serialized pubkey (both types in libsecp256k1 are 65 bytes). this saves one allocation of 65 bytes, which is nice as pubkey recovery is one bottleneck during load in Ethereum */ bytes65 := make([]byte, 65) pubkey_ptr := (*C.secp256k1_pubkey)(unsafe.Pointer(&pubkey[0])) recoverable_sig_ptr := (*C.secp256k1_ecdsa_recoverable_signature)(unsafe.Pointer(&bytes65[0])) recid := C.int(sig[64]) ret := C.secp256k1_ecdsa_recoverable_signature_parse_compact( context, recoverable_sig_ptr, sig_ptr, recid) if ret == C.int(0) { return nil, errors.New("Failed to parse signature") } ret = C.secp256k1_ecdsa_recover( context, pubkey_ptr, recoverable_sig_ptr, msg_ptr, ) if ret == C.int(0) { return nil, errors.New("Failed to recover public key") } else { serialized_pubkey_ptr := (*C.uchar)(unsafe.Pointer(&bytes65[0])) var output_len C.size_t C.secp256k1_ec_pubkey_serialize( // always returns 1 context, serialized_pubkey_ptr, &output_len, pubkey_ptr, 0, // SECP256K1_EC_COMPRESSED ) return bytes65, nil } }