schnorr.go raw
1 package secp
2
3 import (
4 "fmt"
5 )
6
7 // Keypair represents a secp256k1 keypair for Schnorr signatures
8 type Keypair [96]byte
9
10 // XOnlyPublicKey represents a 64-byte x-only public key (internal format)
11 type XOnlyPublicKey [64]byte
12
13 // CreateKeypair creates a keypair from a 32-byte secret key
14 func (c *Context) CreateKeypair(seckey []byte) (keypair Keypair, err error) {
15 if keypairCreate == nil {
16 err = fmt.Errorf("schnorrsig module not available")
17 return
18 }
19
20 if len(seckey) != PrivateKeySize {
21 err = fmt.Errorf("private key must be %d bytes", PrivateKeySize)
22 return
23 }
24
25 ret := keypairCreate(c.ctx, &keypair[0], &seckey[0])
26 if ret != 1 {
27 err = fmt.Errorf("failed to create keypair")
28 return
29 }
30
31 return
32 }
33
34 // KeypairXOnlyPub extracts the x-only public key from a keypair
35 func (c *Context) KeypairXOnlyPub(keypair Keypair) (xonly XOnlyPublicKey, pkParity int32, err error) {
36 if keypairXonlyPub == nil {
37 err = fmt.Errorf("schnorrsig module not available")
38 return
39 }
40
41 ret := keypairXonlyPub(c.ctx, &xonly[0], &pkParity, &keypair[0])
42 if ret != 1 {
43 err = fmt.Errorf("failed to extract xonly pubkey")
44 return
45 }
46
47 return
48 }
49
50 // SchnorrSign creates a Schnorr signature (BIP-340)
51 func (c *Context) SchnorrSign(msg32 []byte, keypair Keypair, auxRand32 []byte) (sig []byte, err error) {
52 if schnorrsigSign32 == nil {
53 err = fmt.Errorf("schnorrsig module not available")
54 return
55 }
56
57 if len(msg32) != 32 {
58 err = fmt.Errorf("message must be 32 bytes")
59 return
60 }
61
62 var auxPtr *byte
63 if len(auxRand32) > 0 {
64 if len(auxRand32) != 32 {
65 err = fmt.Errorf("aux_rand must be 32 bytes")
66 return
67 }
68 auxPtr = &auxRand32[0]
69 }
70
71 sig = make([]byte, SchnorrSignatureSize)
72 ret := schnorrsigSign32(c.ctx, &sig[0], &msg32[0], &keypair[0], auxPtr)
73 if ret != 1 {
74 err = fmt.Errorf("failed to create Schnorr signature")
75 return
76 }
77
78 return
79 }
80
81 // SchnorrVerify verifies a Schnorr signature (BIP-340)
82 func (c *Context) SchnorrVerify(sig64 []byte, msg []byte, xonlyPubkey []byte) (valid bool, err error) {
83 if schnorrsigVerify == nil {
84 err = fmt.Errorf("schnorrsig module not available")
85 return
86 }
87
88 if len(sig64) != SchnorrSignatureSize {
89 err = fmt.Errorf("signature must be %d bytes", SchnorrSignatureSize)
90 return
91 }
92
93 // xonlyPubkey can be either 32 bytes (serialized) or 64 bytes (internal)
94 var xonly [64]byte
95 if len(xonlyPubkey) == 32 {
96 // Parse the 32-byte serialized format
97 ret := xonlyPubkeyParse(c.ctx, &xonly[0], &xonlyPubkey[0])
98 if ret != 1 {
99 err = fmt.Errorf("failed to parse xonly pubkey")
100 return
101 }
102 } else if len(xonlyPubkey) == 64 {
103 // Already in internal format
104 copy(xonly[:], xonlyPubkey)
105 } else {
106 err = fmt.Errorf("xonly public key must be 32 or 64 bytes")
107 return
108 }
109
110 ret := schnorrsigVerify(c.ctx, &sig64[0], &msg[0], uint64(len(msg)), &xonly[0])
111 valid = ret == 1
112
113 return
114 }
115
116 // ParseXOnlyPublicKey parses a 32-byte x-only public key
117 func (c *Context) ParseXOnlyPublicKey(input32 []byte) (xonly []byte, err error) {
118 if xonlyPubkeyParse == nil {
119 err = fmt.Errorf("schnorrsig module not available")
120 return
121 }
122
123 if len(input32) != 32 {
124 err = fmt.Errorf("xonly public key must be 32 bytes")
125 return
126 }
127
128 xonly = make([]byte, 64) // Internal representation is 64 bytes
129 ret := xonlyPubkeyParse(c.ctx, &xonly[0], &input32[0])
130 if ret != 1 {
131 err = fmt.Errorf("failed to parse xonly public key")
132 return
133 }
134
135 return
136 }
137
138 // SerializeXOnlyPublicKey serializes an x-only public key to 32 bytes
139 func (c *Context) SerializeXOnlyPublicKey(xonly []byte) (output32 []byte, err error) {
140 if xonlyPubkeySerialize == nil {
141 err = fmt.Errorf("schnorrsig module not available")
142 return
143 }
144
145 if len(xonly) != 64 {
146 err = fmt.Errorf("xonly public key must be 64 bytes (internal format)")
147 return
148 }
149
150 output32 = make([]byte, 32)
151 ret := xonlyPubkeySerialize(c.ctx, &output32[0], &xonly[0])
152 if ret != 1 {
153 err = fmt.Errorf("failed to serialize xonly public key")
154 return
155 }
156
157 return
158 }
159
160 // XOnlyPublicKeyFromPublicKey converts a regular public key to an x-only public key
161 func (c *Context) XOnlyPublicKeyFromPublicKey(pubkey []byte) (xonly []byte, pkParity int32, err error) {
162 if xonlyPubkeyFromPubkey == nil {
163 err = fmt.Errorf("schnorrsig module not available")
164 return
165 }
166
167 if len(pubkey) != PublicKeySize {
168 err = fmt.Errorf("public key must be %d bytes", PublicKeySize)
169 return
170 }
171
172 xonly = make([]byte, 64) // Internal representation
173 ret := xonlyPubkeyFromPubkey(c.ctx, &xonly[0], &pkParity, &pubkey[0])
174 if ret != 1 {
175 err = fmt.Errorf("failed to convert to xonly public key")
176 return
177 }
178
179 return
180 }
181