secp256.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267
  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. package secp256k1
  17. // TODO: set USE_SCALAR_4X64 depending on platform?
  18. /*
  19. #cgo CFLAGS: -I./libsecp256k1
  20. #cgo CFLAGS: -I./libsecp256k1/src/
  21. #define USE_NUM_NONE
  22. #define USE_FIELD_10X26
  23. #define USE_FIELD_INV_BUILTIN
  24. #define USE_SCALAR_8X32
  25. #define USE_SCALAR_INV_BUILTIN
  26. #define NDEBUG
  27. #include "./libsecp256k1/src/secp256k1.c"
  28. #include "./libsecp256k1/src/modules/recovery/main_impl.h"
  29. #include "pubkey_scalar_mul.h"
  30. typedef void (*callbackFunc) (const char* msg, void* data);
  31. extern void secp256k1GoPanicIllegal(const char* msg, void* data);
  32. extern void secp256k1GoPanicError(const char* msg, void* data);
  33. */
  34. import "C"
  35. import (
  36. "errors"
  37. "math/big"
  38. "unsafe"
  39. "github.com/ethereum/go-ethereum/crypto/randentropy"
  40. )
  41. //#define USE_FIELD_5X64
  42. /*
  43. TODO:
  44. > store private keys in buffer and shuffle (deters persistance on swap disc)
  45. > byte permutation (changing)
  46. > xor with chaning random block (to deter scanning memory for 0x63) (stream cipher?)
  47. */
  48. // holds ptr to secp256k1_context_struct (see secp256k1/include/secp256k1.h)
  49. var (
  50. context *C.secp256k1_context
  51. N *big.Int
  52. )
  53. func init() {
  54. N, _ = new(big.Int).SetString("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141", 16)
  55. // around 20 ms on a modern CPU.
  56. context = C.secp256k1_context_create(3) // SECP256K1_START_SIGN | SECP256K1_START_VERIFY
  57. C.secp256k1_context_set_illegal_callback(context, C.callbackFunc(C.secp256k1GoPanicIllegal), nil)
  58. C.secp256k1_context_set_error_callback(context, C.callbackFunc(C.secp256k1GoPanicError), nil)
  59. }
  60. var (
  61. ErrInvalidMsgLen = errors.New("invalid message length for signature recovery")
  62. ErrInvalidSignatureLen = errors.New("invalid signature length")
  63. ErrInvalidRecoveryID = errors.New("invalid signature recovery id")
  64. )
  65. func GenerateKeyPair() ([]byte, []byte) {
  66. var seckey []byte = randentropy.GetEntropyCSPRNG(32)
  67. var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
  68. var pubkey64 []byte = make([]byte, 64) // secp256k1_pubkey
  69. var pubkey65 []byte = make([]byte, 65) // 65 byte uncompressed pubkey
  70. pubkey64_ptr := (*C.secp256k1_pubkey)(unsafe.Pointer(&pubkey64[0]))
  71. pubkey65_ptr := (*C.uchar)(unsafe.Pointer(&pubkey65[0]))
  72. ret := C.secp256k1_ec_pubkey_create(
  73. context,
  74. pubkey64_ptr,
  75. seckey_ptr,
  76. )
  77. if ret != C.int(1) {
  78. return GenerateKeyPair() // invalid secret, try again
  79. }
  80. var output_len C.size_t
  81. C.secp256k1_ec_pubkey_serialize( // always returns 1
  82. context,
  83. pubkey65_ptr,
  84. &output_len,
  85. pubkey64_ptr,
  86. 0, // SECP256K1_EC_COMPRESSED
  87. )
  88. return pubkey65, seckey
  89. }
  90. func GeneratePubKey(seckey []byte) ([]byte, error) {
  91. if err := VerifySeckeyValidity(seckey); err != nil {
  92. return nil, err
  93. }
  94. var pubkey []byte = make([]byte, 64)
  95. var pubkey_ptr *C.secp256k1_pubkey = (*C.secp256k1_pubkey)(unsafe.Pointer(&pubkey[0]))
  96. var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
  97. ret := C.secp256k1_ec_pubkey_create(
  98. context,
  99. pubkey_ptr,
  100. seckey_ptr,
  101. )
  102. if ret != C.int(1) {
  103. return nil, errors.New("Unable to generate pubkey from seckey")
  104. }
  105. return pubkey, nil
  106. }
  107. func Sign(msg []byte, seckey []byte) ([]byte, error) {
  108. msg_ptr := (*C.uchar)(unsafe.Pointer(&msg[0]))
  109. seckey_ptr := (*C.uchar)(unsafe.Pointer(&seckey[0]))
  110. sig := make([]byte, 65)
  111. sig_ptr := (*C.secp256k1_ecdsa_recoverable_signature)(unsafe.Pointer(&sig[0]))
  112. nonce := randentropy.GetEntropyCSPRNG(32)
  113. ndata_ptr := unsafe.Pointer(&nonce[0])
  114. noncefp_ptr := &(*C.secp256k1_nonce_function_default)
  115. if C.secp256k1_ec_seckey_verify(context, seckey_ptr) != C.int(1) {
  116. return nil, errors.New("Invalid secret key")
  117. }
  118. ret := C.secp256k1_ecdsa_sign_recoverable(
  119. context,
  120. sig_ptr,
  121. msg_ptr,
  122. seckey_ptr,
  123. noncefp_ptr,
  124. ndata_ptr,
  125. )
  126. if ret == C.int(0) {
  127. return Sign(msg, seckey) //invalid secret, try again
  128. }
  129. sig_serialized := make([]byte, 65)
  130. sig_serialized_ptr := (*C.uchar)(unsafe.Pointer(&sig_serialized[0]))
  131. var recid C.int
  132. C.secp256k1_ecdsa_recoverable_signature_serialize_compact(
  133. context,
  134. sig_serialized_ptr, // 64 byte compact signature
  135. &recid,
  136. sig_ptr, // 65 byte "recoverable" signature
  137. )
  138. sig_serialized[64] = byte(int(recid)) // add back recid to get 65 bytes sig
  139. return sig_serialized, nil
  140. }
  141. func VerifySeckeyValidity(seckey []byte) error {
  142. if len(seckey) != 32 {
  143. return errors.New("priv key is not 32 bytes")
  144. }
  145. var seckey_ptr *C.uchar = (*C.uchar)(unsafe.Pointer(&seckey[0]))
  146. ret := C.secp256k1_ec_seckey_verify(context, seckey_ptr)
  147. if int(ret) != 1 {
  148. return errors.New("invalid seckey")
  149. }
  150. return nil
  151. }
  152. // RecoverPubkey returns the the public key of the signer.
  153. // msg must be the 32-byte hash of the message to be signed.
  154. // sig must be a 65-byte compact ECDSA signature containing the
  155. // recovery id as the last element.
  156. func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) {
  157. if len(msg) != 32 {
  158. return nil, ErrInvalidMsgLen
  159. }
  160. if err := checkSignature(sig); err != nil {
  161. return nil, err
  162. }
  163. msg_ptr := (*C.uchar)(unsafe.Pointer(&msg[0]))
  164. sig_ptr := (*C.uchar)(unsafe.Pointer(&sig[0]))
  165. pubkey := make([]byte, 64)
  166. /*
  167. this slice is used for both the recoverable signature and the
  168. resulting serialized pubkey (both types in libsecp256k1 are 65
  169. bytes). this saves one allocation of 65 bytes, which is nice as
  170. pubkey recovery is one bottleneck during load in Ethereum
  171. */
  172. bytes65 := make([]byte, 65)
  173. pubkey_ptr := (*C.secp256k1_pubkey)(unsafe.Pointer(&pubkey[0]))
  174. recoverable_sig_ptr := (*C.secp256k1_ecdsa_recoverable_signature)(unsafe.Pointer(&bytes65[0]))
  175. recid := C.int(sig[64])
  176. ret := C.secp256k1_ecdsa_recoverable_signature_parse_compact(
  177. context,
  178. recoverable_sig_ptr,
  179. sig_ptr,
  180. recid)
  181. if ret == C.int(0) {
  182. return nil, errors.New("Failed to parse signature")
  183. }
  184. ret = C.secp256k1_ecdsa_recover(
  185. context,
  186. pubkey_ptr,
  187. recoverable_sig_ptr,
  188. msg_ptr,
  189. )
  190. if ret == C.int(0) {
  191. return nil, errors.New("Failed to recover public key")
  192. }
  193. serialized_pubkey_ptr := (*C.uchar)(unsafe.Pointer(&bytes65[0]))
  194. var output_len C.size_t
  195. C.secp256k1_ec_pubkey_serialize( // always returns 1
  196. context,
  197. serialized_pubkey_ptr,
  198. &output_len,
  199. pubkey_ptr,
  200. 0, // SECP256K1_EC_COMPRESSED
  201. )
  202. return bytes65, nil
  203. }
  204. func checkSignature(sig []byte) error {
  205. if len(sig) != 65 {
  206. return ErrInvalidSignatureLen
  207. }
  208. if sig[64] >= 4 {
  209. return ErrInvalidRecoveryID
  210. }
  211. return nil
  212. }
  213. // reads num into buf as big-endian bytes.
  214. func readBits(buf []byte, num *big.Int) {
  215. const wordLen = int(unsafe.Sizeof(big.Word(0)))
  216. i := len(buf)
  217. for _, d := range num.Bits() {
  218. for j := 0; j < wordLen && i > 0; j++ {
  219. i--
  220. buf[i] = byte(d)
  221. d >>= 8
  222. }
  223. }
  224. }