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 }