verify_wasm.go raw

   1  //go:build js || wasm || tinygo || wasm32
   2  
   3  package p256k1
   4  
   5  import (
   6  	"sync"
   7  	"unsafe"
   8  )
   9  
  10  // WASM-compatible secp256k1 verification types and functions
  11  // These use the 32-bit field/scalar representations
  12  
  13  // secp256k1_context represents a context
  14  type secp256k1_context struct {
  15  	ecmult_gen_ctx secp256k1_ecmult_gen_context
  16  	declassify     int
  17  }
  18  
  19  type secp256k1_ecmult_gen_context struct {
  20  	built int
  21  }
  22  
  23  // secp256k1_declassify declassifies data (no-op in non-VERIFY builds)
  24  func secp256k1_declassify(ctx *secp256k1_context, p unsafe.Pointer, len uintptr) {
  25  	// No-op
  26  }
  27  
  28  // secp256k1_xonly_pubkey represents an x-only public key
  29  type secp256k1_xonly_pubkey struct {
  30  	data [32]byte
  31  }
  32  
  33  // secp256k1_scalar wraps 32-bit Scalar for C-like API
  34  type secp256k1_scalar struct {
  35  	s Scalar
  36  }
  37  
  38  // secp256k1_fe wraps 32-bit FieldElement for C-like API
  39  type secp256k1_fe struct {
  40  	fe FieldElement
  41  }
  42  
  43  // secp256k1_ge represents a group element in affine coordinates
  44  type secp256k1_ge struct {
  45  	x, y     secp256k1_fe
  46  	infinity int
  47  }
  48  
  49  // secp256k1_gej represents a group element in Jacobian coordinates
  50  type secp256k1_gej struct {
  51  	x, y, z  secp256k1_fe
  52  	infinity int
  53  }
  54  
  55  // ============================================================================
  56  // SCALAR OPERATIONS
  57  // ============================================================================
  58  
  59  // secp256k1_scalar_set_b32 sets scalar from 32 bytes
  60  func secp256k1_scalar_set_b32(r *secp256k1_scalar, b32 []byte, overflow *int) {
  61  	of := r.s.setB32(b32)
  62  	if overflow != nil {
  63  		if of {
  64  			*overflow = 1
  65  		} else {
  66  			*overflow = 0
  67  		}
  68  	}
  69  }
  70  
  71  // secp256k1_scalar_negate negates a scalar
  72  func secp256k1_scalar_negate(r *secp256k1_scalar, a *secp256k1_scalar) {
  73  	r.s = a.s
  74  	r.s.negate(&r.s)
  75  }
  76  
  77  // secp256k1_scalar_is_zero checks if scalar is zero
  78  func secp256k1_scalar_is_zero(a *secp256k1_scalar) bool {
  79  	return a.s.isZero()
  80  }
  81  
  82  // ============================================================================
  83  // FIELD OPERATIONS
  84  // ============================================================================
  85  
  86  // secp256k1_fe_set_b32_limit sets field element from 32 bytes, checking limit
  87  func secp256k1_fe_set_b32_limit(r *secp256k1_fe, b32 []byte) bool {
  88  	return r.fe.setB32(b32) == nil
  89  }
  90  
  91  // secp256k1_fe_normalize_var normalizes field element
  92  func secp256k1_fe_normalize_var(r *secp256k1_fe) {
  93  	r.fe.normalize()
  94  }
  95  
  96  // secp256k1_fe_is_odd checks if field element is odd
  97  func secp256k1_fe_is_odd(a *secp256k1_fe) bool {
  98  	return a.fe.n[0]&1 == 1
  99  }
 100  
 101  // secp256k1_fe_get_b32 gets 32 bytes from field element
 102  func secp256k1_fe_get_b32(r []byte, a *secp256k1_fe) {
 103  	a.fe.getB32(r)
 104  }
 105  
 106  // secp256k1_fe_set_int sets field element to integer
 107  func secp256k1_fe_set_int(r *secp256k1_fe, a int) {
 108  	r.fe.setInt(a)
 109  }
 110  
 111  // secp256k1_fe_equal compares two field elements
 112  func secp256k1_fe_equal(a, b *secp256k1_fe) bool {
 113  	// Compare all 10 limbs
 114  	for i := 0; i < 10; i++ {
 115  		if a.fe.n[i] != b.fe.n[i] {
 116  			return false
 117  		}
 118  	}
 119  	return true
 120  }
 121  
 122  // ============================================================================
 123  // GROUP OPERATIONS
 124  // ============================================================================
 125  
 126  // secp256k1_ge_is_infinity checks if group element is infinity
 127  func secp256k1_ge_is_infinity(a *secp256k1_ge) bool {
 128  	return a.infinity != 0
 129  }
 130  
 131  // secp256k1_gej_set_ge sets Jacobian from affine
 132  func secp256k1_gej_set_ge(r *secp256k1_gej, a *secp256k1_ge) {
 133  	r.infinity = a.infinity
 134  	r.x = a.x
 135  	r.y = a.y
 136  	secp256k1_fe_set_int(&r.z, 1)
 137  }
 138  
 139  // secp256k1_ge_set_gej_var sets affine from Jacobian
 140  func secp256k1_ge_set_gej_var(r *secp256k1_ge, a *secp256k1_gej) {
 141  	if a.infinity != 0 {
 142  		r.infinity = 1
 143  		return
 144  	}
 145  	r.infinity = 0
 146  
 147  	// Convert from Jacobian to affine
 148  	var gej GroupElementJacobian
 149  	gej.x = a.x.fe
 150  	gej.y = a.y.fe
 151  	gej.z = a.z.fe
 152  	gej.infinity = a.infinity != 0
 153  
 154  	var ge GroupElementAffine
 155  	ge.setGEJ(&gej)
 156  
 157  	r.x.fe = ge.x
 158  	r.y.fe = ge.y
 159  }
 160  
 161  // secp256k1_xonly_pubkey_load loads x-only public key
 162  func secp256k1_xonly_pubkey_load(ctx *secp256k1_context, ge *secp256k1_ge, pubkey *secp256k1_xonly_pubkey) bool {
 163  	// Reconstruct point from X coordinate (x-only pubkey only has X)
 164  	var x FieldElement
 165  	if err := x.setB32(pubkey.data[:]); err != nil {
 166  		return false
 167  	}
 168  
 169  	// Try to recover Y coordinate (use even Y for BIP-340)
 170  	var gep GroupElementAffine
 171  	if !gep.setXOVar(&x, false) {
 172  		return false
 173  	}
 174  
 175  	ge.x.fe = gep.x
 176  	ge.y.fe = gep.y
 177  	if gep.infinity {
 178  		ge.infinity = 1
 179  	} else {
 180  		ge.infinity = 0
 181  	}
 182  
 183  	return true
 184  }
 185  
 186  // secp256k1_ecmult performs scalar multiplication: r = a*s + G*t
 187  func secp256k1_ecmult(r *secp256k1_gej, a *secp256k1_gej, na *secp256k1_scalar, ng *secp256k1_scalar) {
 188  	// Convert types
 189  	var aJac GroupElementJacobian
 190  	aJac.x = a.x.fe
 191  	aJac.y = a.y.fe
 192  	aJac.z = a.z.fe
 193  	aJac.infinity = a.infinity != 0
 194  
 195  	var aAff GroupElementAffine
 196  	aAff.setGEJ(&aJac)
 197  
 198  	var result GroupElementJacobian
 199  
 200  	// Use GLV/Strauss/wNAF for the scalar multiplication
 201  	// r = na*a + ng*G
 202  	if !na.s.isZero() && !ng.s.isZero() {
 203  		// Both scalars non-zero: compute na*a, then add ng*G
 204  		ecmultStraussWNAFGLV(&result, &aAff, &na.s)
 205  
 206  		var gMul GroupElementJacobian
 207  		ecmultGenGLV(&gMul, &ng.s)
 208  
 209  		result.addVar(&result, &gMul)
 210  	} else if !na.s.isZero() {
 211  		// Only na*a
 212  		ecmultStraussWNAFGLV(&result, &aAff, &na.s)
 213  	} else if !ng.s.isZero() {
 214  		// Only ng*G
 215  		ecmultGenGLV(&result, &ng.s)
 216  	} else {
 217  		result.infinity = true
 218  	}
 219  
 220  	// Convert back
 221  	r.x.fe = result.x
 222  	r.y.fe = result.y
 223  	r.z.fe = result.z
 224  	if result.infinity {
 225  		r.infinity = 1
 226  	} else {
 227  		r.infinity = 0
 228  	}
 229  }
 230  
 231  // ============================================================================
 232  // SCHNORR CHALLENGE
 233  // ============================================================================
 234  
 235  // secp256k1_schnorrsig_challenge computes BIP-340 challenge
 236  func secp256k1_schnorrsig_challenge(e *secp256k1_scalar, r32 []byte, msg []byte, msglen int, pk32 []byte) {
 237  	// TaggedHash("BIP0340/challenge", r32 || pk32 || msg)
 238  	var input []byte
 239  	input = append(input, r32[:32]...)
 240  	input = append(input, pk32[:32]...)
 241  	input = append(input, msg[:msglen]...)
 242  
 243  	hash := TaggedHash([]byte("BIP0340/challenge"), input)
 244  
 245  	var overflow int
 246  	secp256k1_scalar_set_b32(e, hash[:], &overflow)
 247  }
 248  
 249  // ============================================================================
 250  // SCHNORR VERIFICATION
 251  // ============================================================================
 252  
 253  // Global precomputed context for Schnorr verification
 254  var (
 255  	schnorrVerifyContext     *secp256k1_context
 256  	schnorrVerifyContextOnce sync.Once
 257  )
 258  
 259  // initSchnorrVerifyContext initializes the global Schnorr verification context
 260  func initSchnorrVerifyContext() {
 261  	schnorrVerifyContext = &secp256k1_context{
 262  		ecmult_gen_ctx: secp256k1_ecmult_gen_context{built: 1},
 263  		declassify:     0,
 264  	}
 265  }
 266  
 267  // getSchnorrVerifyContext returns the precomputed Schnorr verification context
 268  func getSchnorrVerifyContext() *secp256k1_context {
 269  	schnorrVerifyContextOnce.Do(initSchnorrVerifyContext)
 270  	return schnorrVerifyContext
 271  }
 272  
 273  // secp256k1_schnorrsig_verify verifies a BIP-340 Schnorr signature
 274  func secp256k1_schnorrsig_verify(ctx *secp256k1_context, sig64 []byte, msg []byte, msglen int, pubkey *secp256k1_xonly_pubkey) int {
 275  	var s secp256k1_scalar
 276  	var e secp256k1_scalar
 277  	var rj secp256k1_gej
 278  	var pk secp256k1_ge
 279  	var pkj secp256k1_gej
 280  	var rx secp256k1_fe
 281  	var r secp256k1_ge
 282  	var overflow int
 283  
 284  	if ctx == nil {
 285  		return 0
 286  	}
 287  	if sig64 == nil {
 288  		return 0
 289  	}
 290  	if msg == nil && msglen != 0 {
 291  		return 0
 292  	}
 293  	if pubkey == nil {
 294  		return 0
 295  	}
 296  
 297  	// Check signature length
 298  	if len(sig64) < 64 {
 299  		return 0
 300  	}
 301  
 302  	if !secp256k1_fe_set_b32_limit(&rx, sig64[:32]) {
 303  		return 0
 304  	}
 305  
 306  	secp256k1_scalar_set_b32(&s, sig64[32:], &overflow)
 307  	if overflow != 0 {
 308  		return 0
 309  	}
 310  
 311  	if !secp256k1_xonly_pubkey_load(ctx, &pk, pubkey) {
 312  		return 0
 313  	}
 314  
 315  	// Compute e - extract normalized pk.x bytes efficiently
 316  	secp256k1_fe_normalize_var(&pk.x)
 317  	var pkXBytes [32]byte
 318  	secp256k1_fe_get_b32(pkXBytes[:], &pk.x)
 319  	secp256k1_schnorrsig_challenge(&e, sig64[:32], msg, msglen, pkXBytes[:])
 320  
 321  	// Compute rj = s*G + (-e)*pkj
 322  	secp256k1_scalar_negate(&e, &e)
 323  	secp256k1_gej_set_ge(&pkj, &pk)
 324  	secp256k1_ecmult(&rj, &pkj, &e, &s)
 325  
 326  	secp256k1_ge_set_gej_var(&r, &rj)
 327  	if secp256k1_ge_is_infinity(&r) {
 328  		return 0
 329  	}
 330  
 331  	// Normalize r.y and check if odd
 332  	secp256k1_fe_normalize_var(&r.y)
 333  	if secp256k1_fe_is_odd(&r.y) {
 334  		return 0
 335  	}
 336  
 337  	// Normalize r.x and rx, then compare
 338  	secp256k1_fe_normalize_var(&r.x)
 339  	secp256k1_fe_normalize_var(&rx)
 340  
 341  	if !secp256k1_fe_equal(&rx, &r.x) {
 342  		return 0
 343  	}
 344  
 345  	return 1
 346  }
 347