debug_helpers_32.go raw

   1  //go:build js || wasm || tinygo || wasm32
   2  
   3  package p256k1
   4  
   5  import (
   6  	"encoding/hex"
   7  	"fmt"
   8  )
   9  
  10  // GetGeneratorXY returns the generator point coordinates as byte slices.
  11  func GetGeneratorXY() (x, y []byte) {
  12  	gx := make([]byte, 32)
  13  	gy := make([]byte, 32)
  14  	g := Generator
  15  	g.x.normalize()
  16  	g.y.normalize()
  17  	g.x.getB32(gx)
  18  	g.y.getB32(gy)
  19  	return gx, gy
  20  }
  21  
  22  // TestFieldSetGetB32 tests the setB32→getB32 round-trip.
  23  func TestFieldSetGetB32(in []byte) []byte {
  24  	var fe FieldElement
  25  	fe.setB32(in)
  26  	out := make([]byte, 32)
  27  	fe.getB32(out)
  28  	return out
  29  }
  30  
  31  // DumpFieldLimbs prints the internal limb representation of a field element.
  32  func DumpFieldLimbs(b []byte) {
  33  	var fe FieldElement
  34  	fe.setB32(b)
  35  	fmt.Printf("  10x26 limbs: [")
  36  	for i := 0; i < 10; i++ {
  37  		if i > 0 {
  38  			fmt.Print(", ")
  39  		}
  40  		fmt.Printf("0x%07x", fe.n[i])
  41  	}
  42  	fmt.Printf("]\n")
  43  	fmt.Printf("  magnitude=%d normalized=%v\n", fe.magnitude, fe.normalized)
  44  	fe.normalize()
  45  	fmt.Printf("  after normalize: [")
  46  	for i := 0; i < 10; i++ {
  47  		if i > 0 {
  48  			fmt.Print(", ")
  49  		}
  50  		fmt.Printf("0x%07x", fe.n[i])
  51  	}
  52  	fmt.Printf("]\n")
  53  }
  54  
  55  // TestFieldMul multiplies two field elements given as 32-byte big-endian.
  56  func TestFieldMul(a, b []byte) []byte {
  57  	var fa, fb, fc FieldElement
  58  	fa.setB32(a)
  59  	fb.setB32(b)
  60  	fc.mul(&fa, &fb)
  61  	out := make([]byte, 32)
  62  	fc.getB32(out)
  63  	return out
  64  }
  65  
  66  // TestFieldSqr squares a field element given as 32-byte big-endian.
  67  func TestFieldSqr(a []byte) []byte {
  68  	var fa, fc FieldElement
  69  	fa.setB32(a)
  70  	fc.sqr(&fa)
  71  	out := make([]byte, 32)
  72  	fc.getB32(out)
  73  	return out
  74  }
  75  
  76  // TestFieldInvMul computes inv(a)*a — should return 1.
  77  func TestFieldInvMul(a []byte) []byte {
  78  	var fa, inv, result FieldElement
  79  	fa.setB32(a)
  80  	inv.inv(&fa)
  81  	result.mul(&inv, &fa)
  82  	out := make([]byte, 32)
  83  	result.getB32(out)
  84  	return out
  85  }
  86  
  87  // TestFieldSqrt computes sqrt(a) and returns (result, ok).
  88  func TestFieldSqrt(a []byte) ([]byte, bool) {
  89  	var fa, fr FieldElement
  90  	fa.setB32(a)
  91  	ok := fr.sqrt(&fa)
  92  	out := make([]byte, 32)
  93  	fr.getB32(out)
  94  	return out, ok
  95  }
  96  
  97  // TestFieldAdd computes a + b mod p.
  98  func TestFieldAdd(a, b []byte) []byte {
  99  	var fa, fb FieldElement
 100  	fa.setB32(a)
 101  	fb.setB32(b)
 102  	fa.add(&fb)
 103  	out := make([]byte, 32)
 104  	fa.getB32(out)
 105  	return out
 106  }
 107  
 108  // TestJacobianRoundTrip converts affine→Jacobian(z=1)→affine.
 109  func TestJacobianRoundTrip(xb, yb []byte) ([]byte, []byte) {
 110  	var pt GroupElementAffine
 111  	pt.x.setB32(xb)
 112  	pt.y.setB32(yb)
 113  	pt.infinity = false
 114  
 115  	var jac GroupElementJacobian
 116  	jac.setGE(&pt)
 117  
 118  	var aff GroupElementAffine
 119  	aff.setGEJ(&jac)
 120  	aff.x.normalize()
 121  	aff.y.normalize()
 122  
 123  	ox := make([]byte, 32)
 124  	oy := make([]byte, 32)
 125  	aff.x.getB32(ox)
 126  	aff.y.getB32(oy)
 127  	return ox, oy
 128  }
 129  
 130  // TestPointDouble doubles an affine point and returns the result as affine.
 131  func TestPointDouble(xb, yb []byte) ([]byte, []byte) {
 132  	var pt GroupElementAffine
 133  	pt.x.setB32(xb)
 134  	pt.y.setB32(yb)
 135  	pt.infinity = false
 136  
 137  	var jac GroupElementJacobian
 138  	jac.setGE(&pt)
 139  
 140  	var doubled GroupElementJacobian
 141  	doubled.double(&jac)
 142  
 143  	var aff GroupElementAffine
 144  	aff.setGEJ(&doubled)
 145  	aff.x.normalize()
 146  	aff.y.normalize()
 147  
 148  	ox := make([]byte, 32)
 149  	oy := make([]byte, 32)
 150  	aff.x.getB32(ox)
 151  	aff.y.getB32(oy)
 152  	return ox, oy
 153  }
 154  
 155  // TestJacobianNonTrivialZ tests Jacobian round-trip with z=3.
 156  func TestJacobianNonTrivialZ(xb, yb []byte) ([]byte, []byte) {
 157  	var x, y, z FieldElement
 158  	x.setB32(xb)
 159  	y.setB32(yb)
 160  	z.setInt(3)
 161  
 162  	// Scale: X' = x*z^2, Y' = y*z^3
 163  	var z2, z3 FieldElement
 164  	z2.sqr(&z)       // z^2 = 9
 165  	z3.mul(&z2, &z)  // z^3 = 27
 166  	var xj, yj FieldElement
 167  	xj.mul(&x, &z2)
 168  	yj.mul(&y, &z3)
 169  
 170  	// Build Jacobian point
 171  	var jac GroupElementJacobian
 172  	jac.x = xj
 173  	jac.y = yj
 174  	jac.z = z
 175  	jac.infinity = false
 176  
 177  	// Convert back
 178  	var aff GroupElementAffine
 179  	aff.setGEJ(&jac)
 180  	aff.x.normalize()
 181  	aff.y.normalize()
 182  
 183  	ox := make([]byte, 32)
 184  	oy := make([]byte, 32)
 185  	aff.x.getB32(ox)
 186  	aff.y.getB32(oy)
 187  	return ox, oy
 188  }
 189  
 190  // TestPointDoubleVerbose dumps intermediate values from point doubling.
 191  func TestPointDoubleVerbose(xb, yb []byte) {
 192  	var pt GroupElementAffine
 193  	pt.x.setB32(xb)
 194  	pt.y.setB32(yb)
 195  	pt.infinity = false
 196  
 197  	var jac GroupElementJacobian
 198  	jac.setGE(&pt)
 199  
 200  	var doubled GroupElementJacobian
 201  	doubled.double(&jac)
 202  
 203  	// Dump Jacobian coords before conversion
 204  	var xj, yj, zj [32]byte
 205  	doubled.x.normalize()
 206  	doubled.y.normalize()
 207  	doubled.z.normalize()
 208  	doubled.x.getB32(xj[:])
 209  	doubled.y.getB32(yj[:])
 210  	doubled.z.getB32(zj[:])
 211  	fmt.Printf("  Jac X = %s\n", hex.EncodeToString(xj[:]))
 212  	fmt.Printf("  Jac Y = %s\n", hex.EncodeToString(yj[:]))
 213  	fmt.Printf("  Jac Z = %s\n", hex.EncodeToString(zj[:]))
 214  
 215  	// Test: inv(Z) * Z = 1?
 216  	var zinv, check FieldElement
 217  	zinv.inv(&doubled.z)
 218  	check.mul(&zinv, &doubled.z)
 219  	check.normalize()
 220  	var cb [32]byte
 221  	check.getB32(cb[:])
 222  	fmt.Printf("  inv(Z)*Z = %s\n", hex.EncodeToString(cb[:]))
 223  
 224  	// Convert to affine
 225  	var aff GroupElementAffine
 226  	aff.setGEJ(&doubled)
 227  	aff.x.normalize()
 228  	aff.y.normalize()
 229  	var ax, ay [32]byte
 230  	aff.x.getB32(ax[:])
 231  	aff.y.getB32(ay[:])
 232  	fmt.Printf("  Aff X = %s\n", hex.EncodeToString(ax[:]))
 233  	fmt.Printf("  Aff Y = %s\n", hex.EncodeToString(ay[:]))
 234  }
 235  
 236  // TestEcmultGenSimple computes seckey*G via the non-GLV simple path
 237  // and returns the compressed pubkey (33 bytes).
 238  func TestEcmultGenSimple(seckey []byte) [33]byte {
 239  	var scalar Scalar
 240  	scalar.setB32(seckey)
 241  	var jac GroupElementJacobian
 242  	ecmultGenSimple(&jac, &scalar)
 243  	var aff GroupElementAffine
 244  	aff.setGEJ(&jac)
 245  	aff.x.normalize()
 246  	aff.y.normalize()
 247  	var result [33]byte
 248  	aff.x.getB32(result[1:33])
 249  	// Determine parity
 250  	var yb [32]byte
 251  	aff.y.getB32(yb[:])
 252  	if yb[31]&1 == 0 {
 253  		result[0] = 0x02
 254  	} else {
 255  		result[0] = 0x03
 256  	}
 257  	return result
 258  }
 259