github.com/immesys/bw2bc@v1.1.0/crypto/secp256k1/secp256.go (about)

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