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