main.go raw
1 // WASM module exporting secp256k1 Schnorr operations.
2 // Compiled with: GOOS=js GOARCH=wasm go build -o crypto.wasm ./cmd/crypto-wasm/
3 package main
4
5 import (
6 "common/crypto/secp256k1"
7 "syscall/js"
8 )
9
10 func main() {
11 js.Global().Set("_secp256k1_pubkey", js.FuncOf(pubKeyFromSecKey))
12 js.Global().Set("_secp256k1_sign", js.FuncOf(signSchnorr))
13 js.Global().Set("_secp256k1_verify", js.FuncOf(verifySchnorr))
14 // Block forever — keep the Go runtime alive.
15 <-make(chan struct{})
16 }
17
18 func pubKeyFromSecKey(_ js.Value, args []js.Value) any {
19 seckey := jsBytes32(args[0])
20 pub, ok := secp256k1.PubKeyFromSecKey(seckey)
21 if !ok {
22 return js.Null()
23 }
24 return toJS(pub[:])
25 }
26
27 func signSchnorr(_ js.Value, args []js.Value) any {
28 seckey := jsBytes32(args[0])
29 msg := jsBytes32(args[1])
30 aux := jsBytes32(args[2])
31 sig, ok := secp256k1.SignSchnorr(seckey, msg, aux)
32 if !ok {
33 return js.Null()
34 }
35 return toJS(sig[:])
36 }
37
38 func verifySchnorr(_ js.Value, args []js.Value) any {
39 pubkey := jsBytes32(args[0])
40 msg := jsBytes32(args[1])
41 sig := jsBytes64(args[2])
42 return secp256k1.VerifySchnorr(pubkey, msg, sig)
43 }
44
45 func jsBytes32(v js.Value) [32]byte {
46 var b [32]byte
47 buf := make([]byte, 32)
48 js.CopyBytesToGo(buf, v)
49 copy(b[:], buf)
50 return b
51 }
52
53 func jsBytes64(v js.Value) [64]byte {
54 var b [64]byte
55 buf := make([]byte, 64)
56 js.CopyBytesToGo(buf, v)
57 copy(b[:], buf)
58 return b
59 }
60
61 func toJS(b []byte) any {
62 if b == nil {
63 return js.Null()
64 }
65 r := js.Global().Get("Uint8Array").New(len(b))
66 js.CopyBytesToJS(r, b)
67 return r
68 }
69