signature_libsecp256k1.go raw
1 //go:build libsecp256k1
2
3 package nostr
4
5 /*
6 #cgo CFLAGS: -I${SRCDIR}/libsecp256k1/include -I${SRCDIR}/libsecp256k1/src
7 #cgo CFLAGS: -DECMULT_GEN_PREC_BITS=4
8 #cgo CFLAGS: -DECMULT_WINDOW_SIZE=15
9 #cgo CFLAGS: -DENABLE_MODULE_SCHNORRSIG=1
10 #cgo CFLAGS: -DENABLE_MODULE_EXTRAKEYS=1
11
12 #include "./libsecp256k1/src/secp256k1.c"
13 #include "./libsecp256k1/src/precomputed_ecmult.c"
14 #include "./libsecp256k1/src/precomputed_ecmult_gen.c"
15 #include "./libsecp256k1/src/ecmult_gen.h"
16 #include "./libsecp256k1/src/ecmult.h"
17 #include "./libsecp256k1/src/modules/extrakeys/main_impl.h"
18 #include "./libsecp256k1/src/modules/schnorrsig/main_impl.h"
19
20 #include "./libsecp256k1/include/secp256k1.h"
21 #include "./libsecp256k1/include/secp256k1_extrakeys.h"
22 #include "./libsecp256k1/include/secp256k1_schnorrsig.h"
23 */
24 import "C"
25
26 import (
27 "crypto/rand"
28 "crypto/sha256"
29 "encoding/hex"
30 "errors"
31 "fmt"
32 "unsafe"
33
34 "github.com/btcsuite/btcd/btcec/v2/schnorr"
35 )
36
37 func (evt Event) CheckSignature() (bool, error) {
38 var pk [32]byte
39 _, err := hex.Decode(pk[:], []byte(evt.PubKey))
40 if err != nil {
41 return false, fmt.Errorf("event pubkey '%s' is invalid hex: %w", evt.PubKey, err)
42 }
43
44 var sig [64]byte
45 _, err = hex.Decode(sig[:], []byte(evt.Sig))
46 if err != nil {
47 return false, fmt.Errorf("event signature '%s' is invalid hex: %w", evt.Sig, err)
48 }
49
50 msg := sha256.Sum256(evt.Serialize())
51
52 var xonly C.secp256k1_xonly_pubkey
53 if C.secp256k1_xonly_pubkey_parse(globalSecp256k1Context, &xonly, (*C.uchar)(unsafe.Pointer(&pk[0]))) != 1 {
54 return false, fmt.Errorf("failed to parse xonly pubkey")
55 }
56
57 res := C.secp256k1_schnorrsig_verify(globalSecp256k1Context, (*C.uchar)(unsafe.Pointer(&sig[0])), (*C.uchar)(unsafe.Pointer(&msg[0])), 32, &xonly)
58 return res == 1, nil
59 }
60
61 func (evt *Event) Sign(secretKey string, signOpts ...schnorr.SignOption) error {
62 sk, err := hex.DecodeString(secretKey)
63 if err != nil {
64 return fmt.Errorf("Sign called with invalid secret key '%s': %w", secretKey, err)
65 }
66
67 if evt.Tags == nil {
68 evt.Tags = make(Tags, 0)
69 }
70
71 var keypair C.secp256k1_keypair
72 if C.secp256k1_keypair_create(globalSecp256k1Context, &keypair, (*C.uchar)(unsafe.Pointer(&sk[0]))) != 1 {
73 return errors.New("failed to parse private key")
74 }
75
76 var xonly C.secp256k1_xonly_pubkey
77 var pk [32]byte
78 C.secp256k1_keypair_xonly_pub(globalSecp256k1Context, &xonly, nil, &keypair)
79 C.secp256k1_xonly_pubkey_serialize(globalSecp256k1Context, (*C.uchar)(unsafe.Pointer(&pk[0])), &xonly)
80 evt.PubKey = hex.EncodeToString(pk[:])
81
82 h := sha256.Sum256(evt.Serialize())
83
84 var sig [64]byte
85 var random [32]byte
86 rand.Read(random[:])
87 if C.secp256k1_schnorrsig_sign32(globalSecp256k1Context, (*C.uchar)(unsafe.Pointer(&sig[0])), (*C.uchar)(unsafe.Pointer(&h[0])), &keypair, (*C.uchar)(unsafe.Pointer(&random[0]))) != 1 {
88 return errors.New("failed to sign message")
89 }
90
91 evt.ID = hex.EncodeToString(h[:])
92 evt.Sig = hex.EncodeToString(sig[:])
93
94 return nil
95 }
96
97 var globalSecp256k1Context *C.secp256k1_context
98
99 func init() {
100 globalSecp256k1Context = C.secp256k1_context_create(C.SECP256K1_CONTEXT_SIGN | C.SECP256K1_CONTEXT_VERIFY)
101 if globalSecp256k1Context == nil {
102 panic("failed to create secp256k1 context")
103 }
104 }
105