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  }