p256k1_signer_js.go raw
1 //go:build js || wasm || tinygo || wasm32
2
3 package signer
4
5 import (
6 "errors"
7
8 "git.smesh.lol/orly/pkg/p256k1/exchange"
9 "git.smesh.lol/orly/pkg/p256k1/keys"
10 "git.smesh.lol/orly/pkg/p256k1/schnorr"
11 )
12
13 // P256K1Signer implements the I and Gen interfaces using the p256k1 domain packages (WASM build)
14 type P256K1Signer struct {
15 keypair *keys.KeyPair
16 xonlyPub *schnorr.XOnlyPubkey
17 hasSecret bool
18 sigBuf []byte
19 ecdhBuf []byte
20 }
21
22 func NewP256K1Signer() *P256K1Signer {
23 return &P256K1Signer{hasSecret: false}
24 }
25
26 func (s *P256K1Signer) Generate() error {
27 kp, err := keys.Generate()
28 if err != nil {
29 return err
30 }
31 xonly, parity, err := schnorr.XOnlyFromPubkey(kp.Pubkey())
32 if err != nil {
33 return err
34 }
35 if parity == 1 {
36 seckey, err := keys.NegatePrivate(kp.Seckey())
37 if err != nil {
38 return errors.New("failed to negate secret key")
39 }
40 kp, err = keys.Create(seckey)
41 if err != nil {
42 return err
43 }
44 xonly, _, err = schnorr.XOnlyFromPubkey(kp.Pubkey())
45 if err != nil {
46 return err
47 }
48 }
49 s.keypair = kp
50 s.xonlyPub = xonly
51 s.hasSecret = true
52 return nil
53 }
54
55 func (s *P256K1Signer) InitSec(sec []byte) error {
56 if len(sec) != 32 {
57 return errors.New("secret key must be 32 bytes")
58 }
59 kp, err := keys.Create(sec)
60 if err != nil {
61 return err
62 }
63 xonly, parity, err := schnorr.XOnlyFromPubkey(kp.Pubkey())
64 if err != nil {
65 return err
66 }
67 if parity == 1 {
68 seckey, err := keys.NegatePrivate(kp.Seckey())
69 if err != nil {
70 return errors.New("failed to negate secret key")
71 }
72 kp, err = keys.Create(seckey)
73 if err != nil {
74 return err
75 }
76 xonly, _, err = schnorr.XOnlyFromPubkey(kp.Pubkey())
77 if err != nil {
78 return err
79 }
80 }
81 s.keypair = kp
82 s.xonlyPub = xonly
83 s.hasSecret = true
84 return nil
85 }
86
87 func (s *P256K1Signer) InitPub(pub []byte) error {
88 if len(pub) != 32 {
89 return errors.New("public key must be 32 bytes")
90 }
91 xonly, err := schnorr.ParseXOnlyPubkey(pub)
92 if err != nil {
93 return err
94 }
95 s.xonlyPub = xonly
96 s.keypair = nil
97 s.hasSecret = false
98 return nil
99 }
100
101 func (s *P256K1Signer) Sec() []byte {
102 if !s.hasSecret || s.keypair == nil {
103 return nil
104 }
105 return s.keypair.Seckey()
106 }
107
108 func (s *P256K1Signer) Pub() []byte {
109 if s.xonlyPub == nil {
110 return nil
111 }
112 serialized := s.xonlyPub.Serialize()
113 return serialized[:]
114 }
115
116 func (s *P256K1Signer) Sign(msg []byte) (sig []byte, err error) {
117 if !s.hasSecret || s.keypair == nil {
118 return nil, errors.New("no secret key available for signing")
119 }
120 if len(msg) != 32 {
121 return nil, errors.New("message must be 32 bytes")
122 }
123 if cap(s.sigBuf) < 64 {
124 s.sigBuf = make([]byte, 64)
125 } else {
126 s.sigBuf = s.sigBuf[:64]
127 }
128 if err := schnorr.SignRaw(s.sigBuf, msg, s.keypair, nil); err != nil {
129 return nil, err
130 }
131 return s.sigBuf, nil
132 }
133
134 func (s *P256K1Signer) Verify(msg, sig []byte) (valid bool, err error) {
135 if s.xonlyPub == nil {
136 return false, errors.New("no public key available for verification")
137 }
138 if len(msg) != 32 {
139 return false, errors.New("message must be 32 bytes")
140 }
141 if len(sig) != 64 {
142 return false, errors.New("signature must be 64 bytes")
143 }
144 valid = schnorr.VerifyRaw(sig, msg, s.xonlyPub)
145 return valid, nil
146 }
147
148 func (s *P256K1Signer) Zero() {
149 if s.keypair != nil {
150 s.keypair.Clear()
151 s.keypair = nil
152 }
153 s.hasSecret = false
154 s.xonlyPub = nil
155 }
156
157 func (s *P256K1Signer) ECDH(pub []byte) (secret []byte, err error) {
158 if !s.hasSecret || s.keypair == nil {
159 return nil, errors.New("no secret key available for ECDH")
160 }
161 if len(pub) != 32 {
162 return nil, errors.New("public key must be 32 bytes")
163 }
164 var compressedPub [33]byte
165 compressedPub[0] = 0x02
166 copy(compressedPub[1:], pub)
167 pubkey, err := keys.ParsePublic(compressedPub[:])
168 if err != nil {
169 return nil, err
170 }
171 if cap(s.ecdhBuf) < 32 {
172 s.ecdhBuf = make([]byte, 32)
173 } else {
174 s.ecdhBuf = s.ecdhBuf[:32]
175 }
176 if err := exchange.SharedSecretRaw(s.ecdhBuf, pubkey, s.keypair.Seckey()); err != nil {
177 return nil, err
178 }
179 return s.ecdhBuf, nil
180 }
181
182 func (s *P256K1Signer) ECDHRaw(pub []byte) (sharedX []byte, err error) {
183 if !s.hasSecret || s.keypair == nil {
184 return nil, errors.New("no secret key available for ECDH")
185 }
186 var compressedPub [33]byte
187 if len(pub) == 32 {
188 compressedPub[0] = 0x02
189 copy(compressedPub[1:], pub)
190 } else if len(pub) == 33 {
191 copy(compressedPub[:], pub)
192 } else {
193 return nil, errors.New("public key must be 32 bytes (x-only) or 33 bytes (compressed)")
194 }
195 pubkey, err := keys.ParsePublic(compressedPub[:])
196 if err != nil {
197 if len(pub) == 32 {
198 compressedPub[0] = 0x03
199 pubkey, err = keys.ParsePublic(compressedPub[:])
200 if err != nil {
201 return nil, err
202 }
203 } else {
204 return nil, err
205 }
206 }
207 if cap(s.ecdhBuf) < 32 {
208 s.ecdhBuf = make([]byte, 32)
209 } else {
210 s.ecdhBuf = s.ecdhBuf[:32]
211 }
212 if err := exchange.XOnlySharedSecretRaw(s.ecdhBuf, pubkey, s.keypair.Seckey()); err != nil {
213 return nil, err
214 }
215 return s.ecdhBuf, nil
216 }
217