You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

306 lines
8.1 KiB

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