github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/crypto/secp256k1/secp256.go (about)

     1  // This file is part of the go-sberex library. The go-sberex library is 
     2  // free software: you can redistribute it and/or modify it under the terms 
     3  // of the GNU Lesser General Public License as published by the Free 
     4  // Software Foundation, either version 3 of the License, or (at your option)
     5  // any later version.
     6  //
     7  // The go-sberex library is distributed in the hope that it will be useful, 
     8  // but WITHOUT ANY WARRANTY; without even the implied warranty of
     9  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 
    10  // General Public License <http://www.gnu.org/licenses/> for more details.
    11  
    12  // Package secp256k1 wraps the bitcoin secp256k1 C library.
    13  package secp256k1
    14  
    15  /*
    16  #cgo CFLAGS: -I./libsecp256k1
    17  #cgo CFLAGS: -I./libsecp256k1/src/
    18  #define USE_NUM_NONE
    19  #define USE_FIELD_10X26
    20  #define USE_FIELD_INV_BUILTIN
    21  #define USE_SCALAR_8X32
    22  #define USE_SCALAR_INV_BUILTIN
    23  #define NDEBUG
    24  #include "./libsecp256k1/src/secp256k1.c"
    25  #include "./libsecp256k1/src/modules/recovery/main_impl.h"
    26  #include "ext.h"
    27  
    28  typedef void (*callbackFunc) (const char* msg, void* data);
    29  extern void secp256k1GoPanicIllegal(const char* msg, void* data);
    30  extern void secp256k1GoPanicError(const char* msg, void* data);
    31  */
    32  import "C"
    33  
    34  import (
    35  	"errors"
    36  	"math/big"
    37  	"unsafe"
    38  )
    39  
    40  var context *C.secp256k1_context
    41  
    42  func init() {
    43  	// around 20 ms on a modern CPU.
    44  	context = C.secp256k1_context_create_sign_verify()
    45  	C.secp256k1_context_set_illegal_callback(context, C.callbackFunc(C.secp256k1GoPanicIllegal), nil)
    46  	C.secp256k1_context_set_error_callback(context, C.callbackFunc(C.secp256k1GoPanicError), nil)
    47  }
    48  
    49  var (
    50  	ErrInvalidMsgLen       = errors.New("invalid message length, need 32 bytes")
    51  	ErrInvalidSignatureLen = errors.New("invalid signature length")
    52  	ErrInvalidRecoveryID   = errors.New("invalid signature recovery id")
    53  	ErrInvalidKey          = errors.New("invalid private key")
    54  	ErrInvalidPubkey       = errors.New("invalid public key")
    55  	ErrSignFailed          = errors.New("signing failed")
    56  	ErrRecoverFailed       = errors.New("recovery failed")
    57  )
    58  
    59  // Sign creates a recoverable ECDSA signature.
    60  // The produced signature is in the 65-byte [R || S || V] format where V is 0 or 1.
    61  //
    62  // The caller is responsible for ensuring that msg cannot be chosen
    63  // directly by an attacker. It is usually preferable to use a cryptographic
    64  // hash function on any input before handing it to this function.
    65  func Sign(msg []byte, seckey []byte) ([]byte, error) {
    66  	if len(msg) != 32 {
    67  		return nil, ErrInvalidMsgLen
    68  	}
    69  	if len(seckey) != 32 {
    70  		return nil, ErrInvalidKey
    71  	}
    72  	seckeydata := (*C.uchar)(unsafe.Pointer(&seckey[0]))
    73  	if C.secp256k1_ec_seckey_verify(context, seckeydata) != 1 {
    74  		return nil, ErrInvalidKey
    75  	}
    76  
    77  	var (
    78  		msgdata   = (*C.uchar)(unsafe.Pointer(&msg[0]))
    79  		noncefunc = C.secp256k1_nonce_function_rfc6979
    80  		sigstruct C.secp256k1_ecdsa_recoverable_signature
    81  	)
    82  	if C.secp256k1_ecdsa_sign_recoverable(context, &sigstruct, msgdata, seckeydata, noncefunc, nil) == 0 {
    83  		return nil, ErrSignFailed
    84  	}
    85  
    86  	var (
    87  		sig     = make([]byte, 65)
    88  		sigdata = (*C.uchar)(unsafe.Pointer(&sig[0]))
    89  		recid   C.int
    90  	)
    91  	C.secp256k1_ecdsa_recoverable_signature_serialize_compact(context, sigdata, &recid, &sigstruct)
    92  	sig[64] = byte(recid) // add back recid to get 65 bytes sig
    93  	return sig, nil
    94  }
    95  
    96  // RecoverPubkey returns the the public key of the signer.
    97  // msg must be the 32-byte hash of the message to be signed.
    98  // sig must be a 65-byte compact ECDSA signature containing the
    99  // recovery id as the last element.
   100  func RecoverPubkey(msg []byte, sig []byte) ([]byte, error) {
   101  	if len(msg) != 32 {
   102  		return nil, ErrInvalidMsgLen
   103  	}
   104  	if err := checkSignature(sig); err != nil {
   105  		return nil, err
   106  	}
   107  
   108  	var (
   109  		pubkey  = make([]byte, 65)
   110  		sigdata = (*C.uchar)(unsafe.Pointer(&sig[0]))
   111  		msgdata = (*C.uchar)(unsafe.Pointer(&msg[0]))
   112  	)
   113  	if C.secp256k1_ext_ecdsa_recover(context, (*C.uchar)(unsafe.Pointer(&pubkey[0])), sigdata, msgdata) == 0 {
   114  		return nil, ErrRecoverFailed
   115  	}
   116  	return pubkey, nil
   117  }
   118  
   119  // VerifySignature checks that the given pubkey created signature over message.
   120  // The signature should be in [R || S] format.
   121  func VerifySignature(pubkey, msg, signature []byte) bool {
   122  	if len(msg) != 32 || len(signature) != 64 || len(pubkey) == 0 {
   123  		return false
   124  	}
   125  	sigdata := (*C.uchar)(unsafe.Pointer(&signature[0]))
   126  	msgdata := (*C.uchar)(unsafe.Pointer(&msg[0]))
   127  	keydata := (*C.uchar)(unsafe.Pointer(&pubkey[0]))
   128  	return C.secp256k1_ext_ecdsa_verify(context, sigdata, msgdata, keydata, C.size_t(len(pubkey))) != 0
   129  }
   130  
   131  // DecompressPubkey parses a public key in the 33-byte compressed format.
   132  // It returns non-nil coordinates if the public key is valid.
   133  func DecompressPubkey(pubkey []byte) (x, y *big.Int) {
   134  	if len(pubkey) != 33 {
   135  		return nil, nil
   136  	}
   137  	var (
   138  		pubkeydata = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
   139  		pubkeylen  = C.size_t(len(pubkey))
   140  		out        = make([]byte, 65)
   141  		outdata    = (*C.uchar)(unsafe.Pointer(&out[0]))
   142  		outlen     = C.size_t(len(out))
   143  	)
   144  	if C.secp256k1_ext_reencode_pubkey(context, outdata, outlen, pubkeydata, pubkeylen) == 0 {
   145  		return nil, nil
   146  	}
   147  	return new(big.Int).SetBytes(out[1:33]), new(big.Int).SetBytes(out[33:])
   148  }
   149  
   150  // CompressPubkey encodes a public key to 33-byte compressed format.
   151  func CompressPubkey(x, y *big.Int) []byte {
   152  	var (
   153  		pubkey     = S256().Marshal(x, y)
   154  		pubkeydata = (*C.uchar)(unsafe.Pointer(&pubkey[0]))
   155  		pubkeylen  = C.size_t(len(pubkey))
   156  		out        = make([]byte, 33)
   157  		outdata    = (*C.uchar)(unsafe.Pointer(&out[0]))
   158  		outlen     = C.size_t(len(out))
   159  	)
   160  	if C.secp256k1_ext_reencode_pubkey(context, outdata, outlen, pubkeydata, pubkeylen) == 0 {
   161  		panic("libsecp256k1 error")
   162  	}
   163  	return out
   164  }
   165  
   166  func checkSignature(sig []byte) error {
   167  	if len(sig) != 65 {
   168  		return ErrInvalidSignatureLen
   169  	}
   170  	if sig[64] >= 4 {
   171  		return ErrInvalidRecoveryID
   172  	}
   173  	return nil
   174  }