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