field_4x64_bridge.go raw

   1  //go:build amd64 && !purego
   2  
   3  package p256k1
   4  
   5  // field4x64Mul uses the faster 4x64 representation for field multiplication.
   6  // Converts 5x52 inputs to 4x64, multiplies, and converts back.
   7  func field4x64Mul(r, a, b *FieldElement) {
   8  	// Convert 5x52 to 4x64
   9  	var a4, b4, r4 Field4x64
  10  
  11  	// Normalize inputs first - 5x52 with magnitude > 1 has limbs that may exceed 52 bits
  12  	var aNorm, bNorm FieldElement
  13  	aNorm = *a
  14  	bNorm = *b
  15  	aNorm.normalizeWeak()
  16  	bNorm.normalizeWeak()
  17  
  18  	// Pack 5x52 limbs into 4x64
  19  	// 5x52: n[0..4] where each is 52 bits (except n[4] which is 48 bits)
  20  	// 4x64: n[0..3] where each is 64 bits
  21  	a4.n[0] = aNorm.n[0] | (aNorm.n[1] << 52)
  22  	a4.n[1] = (aNorm.n[1] >> 12) | (aNorm.n[2] << 40)
  23  	a4.n[2] = (aNorm.n[2] >> 24) | (aNorm.n[3] << 28)
  24  	a4.n[3] = (aNorm.n[3] >> 36) | (aNorm.n[4] << 16)
  25  	a4.magnitude = 1
  26  	a4.normalized = false
  27  
  28  	b4.n[0] = bNorm.n[0] | (bNorm.n[1] << 52)
  29  	b4.n[1] = (bNorm.n[1] >> 12) | (bNorm.n[2] << 40)
  30  	b4.n[2] = (bNorm.n[2] >> 24) | (bNorm.n[3] << 28)
  31  	b4.n[3] = (bNorm.n[3] >> 36) | (bNorm.n[4] << 16)
  32  	b4.magnitude = 1
  33  	b4.normalized = false
  34  
  35  	// Multiply using BMI2 assembly
  36  	r4.Mul(&a4, &b4)
  37  
  38  	// Convert 4x64 back to 5x52
  39  	r.n[0] = r4.n[0] & 0xFFFFFFFFFFFFF
  40  	r.n[1] = ((r4.n[0] >> 52) | (r4.n[1] << 12)) & 0xFFFFFFFFFFFFF
  41  	r.n[2] = ((r4.n[1] >> 40) | (r4.n[2] << 24)) & 0xFFFFFFFFFFFFF
  42  	r.n[3] = ((r4.n[2] >> 28) | (r4.n[3] << 36)) & 0xFFFFFFFFFFFFF
  43  	r.n[4] = (r4.n[3] >> 16) & 0x0FFFFFFFFFFFF
  44  
  45  	r.magnitude = 1
  46  	r.normalized = false
  47  }
  48  
  49  // field4x64Sqr uses the faster 4x64 representation for field squaring.
  50  func field4x64Sqr(r, a *FieldElement) {
  51  	// Convert 5x52 to 4x64
  52  	var a4, r4 Field4x64
  53  
  54  	// Normalize input first
  55  	var aNorm FieldElement
  56  	aNorm = *a
  57  	aNorm.normalizeWeak()
  58  
  59  	a4.n[0] = aNorm.n[0] | (aNorm.n[1] << 52)
  60  	a4.n[1] = (aNorm.n[1] >> 12) | (aNorm.n[2] << 40)
  61  	a4.n[2] = (aNorm.n[2] >> 24) | (aNorm.n[3] << 28)
  62  	a4.n[3] = (aNorm.n[3] >> 36) | (aNorm.n[4] << 16)
  63  	a4.magnitude = 1
  64  	a4.normalized = false
  65  
  66  	// Square using BMI2 assembly
  67  	r4.Sqr(&a4)
  68  
  69  	// Convert 4x64 back to 5x52
  70  	r.n[0] = r4.n[0] & 0xFFFFFFFFFFFFF
  71  	r.n[1] = ((r4.n[0] >> 52) | (r4.n[1] << 12)) & 0xFFFFFFFFFFFFF
  72  	r.n[2] = ((r4.n[1] >> 40) | (r4.n[2] << 24)) & 0xFFFFFFFFFFFFF
  73  	r.n[3] = ((r4.n[2] >> 28) | (r4.n[3] << 36)) & 0xFFFFFFFFFFFFF
  74  	r.n[4] = (r4.n[3] >> 16) & 0x0FFFFFFFFFFFF
  75  
  76  	r.magnitude = 1
  77  	r.normalized = false
  78  }
  79  
  80  // hasField4x64 returns false - the bridge has conversion issues.
  81  // The existing fieldMulAsmBMI2/fieldSqrAsmBMI2 work correctly for 5x52.
  82  // Field4x64 can be used directly for new code that doesn't need 5x52 compatibility.
  83  func hasField4x64() bool {
  84  	return false
  85  }
  86