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