github.com/igggame/nebulas-go@v2.1.0+incompatible/crypto/keystore/secp256k1/secp256k1.go (about)

     1  // Copyright (C) 2017 go-nebulas authors
     2  //
     3  // This file is part of the go-nebulas library.
     4  //
     5  // the go-nebulas library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // the go-nebulas library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU General Public License
    16  // along with the go-nebulas library.  If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  
    19  package secp256k1
    20  
    21  /*
    22  #cgo CFLAGS: -I./libsecp256k1
    23  #cgo CFLAGS: -I./libsecp256k1/src/
    24  #define USE_NUM_NONE
    25  #define USE_FIELD_10X26
    26  #define USE_FIELD_INV_BUILTIN
    27  #define USE_SCALAR_8X32
    28  #define USE_SCALAR_INV_BUILTIN
    29  #define ENABLE_MODULE_RECOVERY
    30  #define NDEBUG
    31  #include "./libsecp256k1/src/secp256k1.c"
    32  */
    33  import "C"
    34  
    35  //#cgo CFLAGS: -std=gnu99 -Wno-error
    36  //#cgo LDFLAGS: -lgmp
    37  //#cgo CFLAGS: -Wno-error
    38  
    39  import (
    40  	"errors"
    41  	"unsafe"
    42  
    43  	"github.com/nebulasio/go-nebulas/crypto/utils"
    44  )
    45  
    46  const (
    47  	// EcdsaPrivateKeyLength private key length
    48  	EcdsaPrivateKeyLength = 32
    49  )
    50  
    51  var (
    52  	// ErrInvalidMsgLen invalid message length
    53  	ErrInvalidMsgLen = errors.New("invalid message length, need 32 bytes")
    54  
    55  	// ErrGetPublicKeyFailed private key to public failed
    56  	ErrGetPublicKeyFailed = errors.New("private key to public failed")
    57  
    58  	// ErrInvalidSignature invalid signature length
    59  	ErrInvalidSignature = errors.New("invalid signature")
    60  
    61  	// ErrInvalidPrivateKey invalid private key
    62  	ErrInvalidPrivateKey = errors.New("invalid private key")
    63  
    64  	// ErrInvalidPublicKey invalid public key
    65  	ErrInvalidPublicKey = errors.New("invalid public key")
    66  
    67  	// ErrSignFailed sign failed
    68  	ErrSignFailed = errors.New("sign failed")
    69  
    70  	// ErrRecoverFailed recover failed
    71  	ErrRecoverFailed = errors.New("recovery failed")
    72  )
    73  
    74  var ctx *C.secp256k1_context
    75  
    76  // use bitcoin's libsecp256k1 library
    77  // use like https://github.com/btccom/secp256k1-go/blob/master/secp256k1/secp256k1.go
    78  
    79  func init() {
    80  	ctx = C.secp256k1_context_create(C.SECP256K1_CONTEXT_SIGN | C.SECP256K1_CONTEXT_VERIFY)
    81  }
    82  
    83  // NewSeckey generate a ecdsa private key by secp256k1
    84  func NewSeckey() []byte {
    85  	var priv []byte
    86  
    87  	// in bitcoin src, they call SeckeyVerify func to verify the generated private key
    88  	// to make sure valid.
    89  	for {
    90  		priv = utils.RandomCSPRNG(EcdsaPrivateKeyLength)
    91  		if SeckeyVerify(priv) {
    92  			break
    93  		}
    94  	}
    95  	return priv
    96  }
    97  
    98  // SeckeyVerify check private is ok for secp256k1
    99  func SeckeyVerify(seckey []byte) bool {
   100  	return C.secp256k1_ec_seckey_verify(ctx, cBuf(seckey)) == 1
   101  }
   102  
   103  // GetPublicKey private key to public key
   104  func GetPublicKey(seckey []byte) ([]byte, error) {
   105  
   106  	var pubkey C.secp256k1_pubkey
   107  	result := int(C.secp256k1_ec_pubkey_create(ctx, &pubkey, cBuf(seckey)))
   108  	if result != 1 {
   109  		return nil, ErrGetPublicKeyFailed
   110  	}
   111  
   112  	output := make([]C.uchar, 65)
   113  	outputLen := C.size_t(65)
   114  	result = int(C.secp256k1_ec_pubkey_serialize(ctx, &output[0], &outputLen, &pubkey, C.SECP256K1_EC_UNCOMPRESSED))
   115  	if result != 1 {
   116  		return nil, ErrGetPublicKeyFailed
   117  	}
   118  	return goBytes(output, C.int(outputLen)), nil
   119  }
   120  
   121  // RecoverECDSAPublicKey recover verifies the compact signature "signature" of "hash"
   122  func RecoverECDSAPublicKey(msg []byte, signature []byte) ([]byte, error) {
   123  	if len(msg) != 32 {
   124  		return nil, ErrInvalidMsgLen
   125  	}
   126  	if len(signature) != 65 {
   127  		return nil, ErrInvalidSignature
   128  	}
   129  	var (
   130  		sig    C.secp256k1_ecdsa_recoverable_signature
   131  		pubkey C.secp256k1_pubkey
   132  	)
   133  
   134  	result := int(C.secp256k1_ecdsa_recoverable_signature_parse_compact(ctx, &sig, (*C.uchar)(unsafe.Pointer(&signature[0])), (C.int(signature[64]))))
   135  	if result != 1 {
   136  		return nil, ErrRecoverFailed
   137  	}
   138  	if int(C.secp256k1_ecdsa_recover(ctx, &pubkey, &sig, cBuf(msg))) != 1 {
   139  		return nil, ErrRecoverFailed
   140  	}
   141  	output := make([]C.uchar, 65)
   142  	outputLen := C.size_t(65)
   143  	result = int(C.secp256k1_ec_pubkey_serialize(ctx, &output[0], &outputLen, &pubkey, C.SECP256K1_EC_UNCOMPRESSED))
   144  	if result != 1 {
   145  		return nil, ErrRecoverFailed
   146  	}
   147  	return goBytes(output, C.int(outputLen)), nil
   148  }
   149  
   150  // Sign sign hash with private key
   151  func Sign(msg []byte, seckey []byte) ([]byte, error) {
   152  	if len(msg) != 32 {
   153  		return nil, ErrInvalidMsgLen
   154  	}
   155  
   156  	if C.secp256k1_ec_seckey_verify(ctx, cBuf(seckey)) != 1 {
   157  		return nil, ErrInvalidPrivateKey
   158  	}
   159  
   160  	var (
   161  		noncefunc = C.secp256k1_nonce_function_rfc6979
   162  		sigstruct C.secp256k1_ecdsa_recoverable_signature
   163  	)
   164  	if C.secp256k1_ecdsa_sign_recoverable(ctx, &sigstruct, cBuf(msg), cBuf(seckey), noncefunc, nil) == 0 {
   165  		return nil, ErrSignFailed
   166  	}
   167  
   168  	var (
   169  		sig   = make([]byte, 65)
   170  		recid C.int
   171  	)
   172  	C.secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, cBuf(sig), &recid, &sigstruct)
   173  	sig[64] = byte(recid) // add back recid to get 65 bytes sig
   174  	return sig, nil
   175  }
   176  
   177  // Verify verify with public key
   178  func Verify(msg []byte, signature []byte, pub []byte) (bool, error) {
   179  	if len(msg) != 32 {
   180  		return false, ErrInvalidMsgLen
   181  	}
   182  
   183  	var (
   184  		sig    C.secp256k1_ecdsa_signature
   185  		pubkey C.secp256k1_pubkey
   186  	)
   187  	result := int(C.secp256k1_ec_pubkey_parse(ctx, &pubkey, cBuf(pub), C.size_t(len(pub))))
   188  	if result != 1 {
   189  		return false, ErrInvalidPublicKey
   190  	}
   191  	result = int(C.secp256k1_ecdsa_signature_parse_compact(ctx, &sig, cBuf(signature)))
   192  	if result != 1 {
   193  		return false, ErrInvalidSignature
   194  	}
   195  	result = int(C.secp256k1_ecdsa_verify(ctx, &sig, cBuf(msg), &pubkey))
   196  	return result == 1, nil
   197  }
   198  
   199  func cBuf(goSlice []byte) *C.uchar {
   200  	return (*C.uchar)(unsafe.Pointer(&goSlice[0]))
   201  }
   202  
   203  func goBytes(cSlice []C.uchar, size C.int) []byte {
   204  	return C.GoBytes(unsafe.Pointer(&cSlice[0]), size)
   205  }