├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── secp256k1.go └── secp256k1_test.go /.gitignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/toxeus/go-secp256k1/77e56d25bcd62254427c9281dbb5afed9e1b3927/.gitignore -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "c-secp256k1"] 2 | path = c-secp256k1 3 | url = https://github.com/bitcoin/secp256k1.git 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Filip Gospodinov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # secp256k1 bindings for Go 2 | 3 | ## General info 4 | 5 | The Go API mirrors the API of the C implementation. Therefore, 6 | please consult `c-secp256k1/include/secp256k1.h` for documentation. 7 | Going forward I plan to implement a new API that is more aligned 8 | with the APIs from Go's standard lib crypto packages. Then, it makes 9 | more sense to add a standalone documentation, and hopefully breaking 10 | changes in the C implementation can be abstracted away. 11 | 12 | ## How to get and build 13 | 14 | ```bash 15 | go get -d github.com/toxeus/go-secp256k1 16 | cd $GOPATH/src/github.com/toxeus/go-secp256k1 17 | git submodule update --init # not needed for Go >= 1.6 18 | cd c-secp256k1 19 | ./autogen.sh && ./configure && make 20 | cd .. 21 | go install 22 | ``` 23 | 24 | ## How to update 25 | 26 | ```bash 27 | cd $GOPATH/src/github.com/toxeus/go-secp256k1 28 | git submodule update 29 | cd c-secp256k1 30 | make distclean && ./autogen.sh && ./configure && make 31 | cd .. 32 | go clean && go install 33 | ``` 34 | -------------------------------------------------------------------------------- /secp256k1.go: -------------------------------------------------------------------------------- 1 | package secp256k1 2 | 3 | // #include "c-secp256k1/include/secp256k1.h" 4 | // #cgo LDFLAGS: ${SRCDIR}/c-secp256k1/.libs/libsecp256k1.a -lgmp 5 | import "C" 6 | import "unsafe" 7 | 8 | // The Go API mirrors the API of the C implementation. Therefore, 9 | // please consult c-secp256k1/include/secp256k1.h for documentation. 10 | // Going forward I plan to implement a new API that is more aligned 11 | // with the APIs from Go's standard lib crypto packages. Then, it makes 12 | // more sense to have a good documentation, and hopefully breaking 13 | // changes in the C implementation can be abstracted away. 14 | 15 | const hashLen int = 32 16 | 17 | func Start() { 18 | C.secp256k1_start(C.SECP256K1_START_VERIFY | C.SECP256K1_START_SIGN) 19 | } 20 | 21 | func Stop() { 22 | C.secp256k1_stop() 23 | } 24 | 25 | func Pubkey_create(seckey [32]byte, compressed bool) ([]byte, bool) { 26 | comp := C.int(0) 27 | bufsize := 65 28 | if compressed { 29 | comp = 1 30 | bufsize = 33 31 | } 32 | pubkey := make([]C.uchar, bufsize) 33 | pubkeylen := C.int(0) 34 | success := C.secp256k1_ec_pubkey_create(&pubkey[0], 35 | &pubkeylen, 36 | cBuf(seckey[:]), 37 | comp) 38 | return C.GoBytes(unsafe.Pointer(&pubkey[0]), pubkeylen), goBool(success) 39 | } 40 | 41 | func Seckey_verify(seckey [32]byte) bool { 42 | success := C.secp256k1_ec_seckey_verify(cBuf(seckey[:])) 43 | return goBool(success) 44 | } 45 | 46 | func Pubkey_verify(pubkey []byte) bool { 47 | success := C.secp256k1_ec_pubkey_verify(cBuf(pubkey), C.int(len(pubkey))) 48 | return goBool(success) 49 | } 50 | 51 | func Sign(msgHash [hashLen]byte, seckey [32]byte, nonce *[32]byte) ([]byte, bool) { 52 | var sig [72]C.uchar 53 | siglen := C.int(len(sig)) 54 | success := C.secp256k1_ecdsa_sign(cBuf(msgHash[:]), 55 | &sig[0], 56 | &siglen, 57 | cBuf(seckey[:]), 58 | nil, 59 | unsafe.Pointer(nonce)) 60 | return C.GoBytes(unsafe.Pointer(&sig[0]), siglen), goBool(success) 61 | } 62 | 63 | func Verify(msgHash [hashLen]byte, sig []byte, pubkey []byte) bool { 64 | success := C.secp256k1_ecdsa_verify(cBuf(msgHash[:]), 65 | cBuf(sig), 66 | C.int(len(sig)), 67 | cBuf(pubkey), 68 | C.int(len(pubkey))) 69 | // success can be also -1 and -2 to indicate invalid sig or invalid pubkey 70 | // for now we just ignore that 71 | return goBool(success) 72 | } 73 | 74 | func goBool(success C.int) bool { 75 | return success == 1 76 | } 77 | 78 | func cBuf(goSlice []byte) *C.uchar { 79 | return (*C.uchar)(unsafe.Pointer(&goSlice[0])) 80 | } 81 | -------------------------------------------------------------------------------- /secp256k1_test.go: -------------------------------------------------------------------------------- 1 | package secp256k1_test 2 | 3 | import ( 4 | "crypto/rand" 5 | "crypto/sha256" 6 | "io" 7 | "testing" 8 | 9 | "github.com/toxeus/go-secp256k1" 10 | ) 11 | 12 | func Test_secp256k1(t *testing.T) { 13 | secp256k1.Start() 14 | defer secp256k1.Stop() 15 | var seckey [32]byte 16 | io.ReadFull(rand.Reader, seckey[:]) 17 | if isValid := secp256k1.Seckey_verify(seckey); !isValid { 18 | t.FailNow() 19 | } 20 | pubkey, _ := secp256k1.Pubkey_create(seckey, true) 21 | if isValid := secp256k1.Pubkey_verify(pubkey); !isValid { 22 | t.FailNow() 23 | } 24 | msg := make([]byte, 32) 25 | io.ReadFull(rand.Reader, msg) 26 | hash := sha256.Sum256(msg) 27 | var nonce [32]byte 28 | io.ReadFull(rand.Reader, nonce[:]) 29 | sig, ok := secp256k1.Sign(hash, seckey, &nonce) 30 | if !ok { 31 | t.FailNow() 32 | } 33 | if ok := secp256k1.Verify(hash, sig, pubkey); !ok { 34 | t.FailNow() 35 | } 36 | } 37 | --------------------------------------------------------------------------------