1
2
3
4
5
6
7
8
9
10
11
12 package main
13
14
15
16
17 import (
18 "bytes"
19 "compress/zlib"
20 "encoding/base64"
21 "fmt"
22 "log"
23 "math/big"
24 "os"
25
26 "github.com/decred/dcrd/dcrec/secp256k1/v4"
27 )
28
29
30 var curveParams = secp256k1.Params()
31
32
33
34 func bigAffineToJacobian(x, y *big.Int, result *secp256k1.JacobianPoint) {
35 result.X.SetByteSlice(x.Bytes())
36 result.Y.SetByteSlice(y.Bytes())
37 result.Z.SetInt(1)
38 }
39
40
41
42
43 func serializedBytePoints() []byte {
44
45
46 doublingPoints := make([]secp256k1.JacobianPoint, curveParams.BitSize)
47 var q secp256k1.JacobianPoint
48 bigAffineToJacobian(curveParams.Gx, curveParams.Gy, &q)
49 for i := 0; i < curveParams.BitSize; i++ {
50
51 doublingPoints[i] = q
52 secp256k1.DoubleNonConst(&q, &q)
53 }
54
55
56 curveByteSize := curveParams.BitSize / 8
57 serialized := make([]byte, curveByteSize*256*2*32)
58 offset := 0
59 for byteNum := 0; byteNum < curveByteSize; byteNum++ {
60
61 startingBit := 8 * (curveByteSize - byteNum - 1)
62 windowPoints := doublingPoints[startingBit : startingBit+8]
63
64
65
66 for i := 0; i < 256; i++ {
67 var point secp256k1.JacobianPoint
68 for bit := 0; bit < 8; bit++ {
69 if i>>uint(bit)&1 == 1 {
70 secp256k1.AddNonConst(&point, &windowPoints[bit], &point)
71 }
72 }
73 point.ToAffine()
74
75 point.X.PutBytesUnchecked(serialized[offset:])
76 offset += 32
77 point.Y.PutBytesUnchecked(serialized[offset:])
78 offset += 32
79 }
80 }
81
82 return serialized
83 }
84
85
86
87
88 func sqrt(n *big.Int) *big.Int {
89
90 guess := big.NewInt(2)
91 guess.Exp(guess, big.NewInt(int64(n.BitLen()/2)), nil)
92
93
94 big2 := big.NewInt(2)
95 prevGuess := big.NewInt(0)
96 for {
97 prevGuess.Set(guess)
98 guess.Add(guess, new(big.Int).Div(n, guess))
99 guess.Div(guess, big2)
100 if guess.Cmp(prevGuess) == 0 {
101 break
102 }
103 }
104 return guess
105 }
106
107
108
109 type endomorphismParams struct {
110 lambda *big.Int
111 beta *big.Int
112 a1, b1 *big.Int
113 a2, b2 *big.Int
114 z1, z2 *big.Int
115 }
116
117
118
119
120
121
122
123 func endomorphismVectors(lambda *big.Int) (a1, b1, a2, b2 *big.Int) {
124
125
126
127
128 nSqrt := sqrt(curveParams.N)
129 u, v := new(big.Int).Set(curveParams.N), new(big.Int).Set(lambda)
130 x1, y1 := big.NewInt(1), big.NewInt(0)
131 x2, y2 := big.NewInt(0), big.NewInt(1)
132 q, r := new(big.Int), new(big.Int)
133 qu, qx1, qy1 := new(big.Int), new(big.Int), new(big.Int)
134 s, t := new(big.Int), new(big.Int)
135 ri, ti := new(big.Int), new(big.Int)
136 a1, b1, a2, b2 = new(big.Int), new(big.Int), new(big.Int), new(big.Int)
137 found, oneMore := false, false
138 for u.Sign() != 0 {
139
140 q.Div(v, u)
141
142
143 qu.Mul(q, u)
144 r.Sub(v, qu)
145
146
147 qx1.Mul(q, x1)
148 s.Sub(x2, qx1)
149
150
151 qy1.Mul(q, y1)
152 t.Sub(y2, qy1)
153
154
155 v.Set(u)
156 u.Set(r)
157 x2.Set(x1)
158 x1.Set(s)
159 y2.Set(y1)
160 y1.Set(t)
161
162
163
164 if !found && r.Cmp(nSqrt) < 0 {
165
166
167
168
169
170
171 a1.Set(r)
172 b1.Neg(t)
173 found = true
174 oneMore = true
175
176
177
178 continue
179
180 } else if oneMore {
181
182
183
184
185
186 rSquared := new(big.Int).Mul(ri, ri)
187 tSquared := new(big.Int).Mul(ti, ti)
188 sum1 := new(big.Int).Add(rSquared, tSquared)
189
190
191 r2Squared := new(big.Int).Mul(r, r)
192 t2Squared := new(big.Int).Mul(t, t)
193 sum2 := new(big.Int).Add(r2Squared, t2Squared)
194
195
196 if sum1.Cmp(sum2) <= 0 {
197
198 a2.Set(ri)
199 b2.Neg(ti)
200 } else {
201
202 a2.Set(r)
203 b2.Neg(t)
204 }
205
206
207 break
208 }
209
210 ri.Set(r)
211 ti.Set(t)
212 }
213
214 return a1, b1, a2, b2
215 }
216
217
218
219 func deriveEndomorphismParams() [2]endomorphismParams {
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243 roots := func(prime *big.Int) [2]big.Int {
244 var result [2]big.Int
245 one := big.NewInt(1)
246 twoInverse := new(big.Int).ModInverse(big.NewInt(2), prime)
247 negThree := new(big.Int).Neg(big.NewInt(3))
248 sqrtNegThree := new(big.Int).ModSqrt(negThree, prime)
249 sqrtNegThreePlusOne := new(big.Int).Add(sqrtNegThree, one)
250 negSqrtNegThreePlusOne := new(big.Int).Neg(sqrtNegThreePlusOne)
251 result[0].Mul(negSqrtNegThreePlusOne, twoInverse)
252 result[0].Mod(&result[0], prime)
253 sqrtNegThreeMinusOne := new(big.Int).Sub(sqrtNegThree, one)
254 result[1].Mul(sqrtNegThreeMinusOne, twoInverse)
255 result[1].Mod(&result[1], prime)
256 return result
257 }
258
259
260
261
262 lambdas := roots(curveParams.N)
263 betas := roots(curveParams.P)
264
265
266
267 checkRoots := func(foundRoots [2]big.Int, prime *big.Int) {
268
269 one := big.NewInt(1)
270 for i := 0; i < len(foundRoots); i++ {
271 root := &foundRoots[i]
272 result := new(big.Int).Mul(root, root)
273 result.Add(result, root)
274 result.Add(result, one)
275 result.Mod(result, prime)
276 if result.Sign() != 0 {
277 panic(fmt.Sprintf("%[1]x^2 + %[1]x + 1 != 0 (mod %x)", root,
278 prime))
279 }
280 }
281 }
282 checkRoots(lambdas, curveParams.N)
283 checkRoots(betas, curveParams.P)
284
285
286
287 checkVectors := func(a, b *big.Int, lambda *big.Int) {
288 result := new(big.Int).Mul(b, lambda)
289 result.Add(result, a)
290 result.Mod(result, curveParams.N)
291 if result.Sign() != 0 {
292 panic(fmt.Sprintf("%x + %x*lambda != 0 (mod %x)", a, b,
293 curveParams.N))
294 }
295 }
296
297 var endoParams [2]endomorphismParams
298 for i := 0; i < 2; i++ {
299
300
301
302 lambda := &lambdas[i]
303 a1, b1, a2, b2 := endomorphismVectors(lambda)
304
305
306 checkVectors(a1, b1, lambda)
307 checkVectors(a2, b2, lambda)
308
309
310
311
312
313
314 const shift = 320
315 z1 := new(big.Int).Lsh(b2, shift)
316 z1.Div(z1, curveParams.N)
317 z2 := new(big.Int).Neg(b1)
318 z2.Lsh(z2, shift)
319 z2.Div(z2, curveParams.N)
320
321 params := &endoParams[i]
322 params.lambda = lambda
323 params.beta = &betas[i]
324 params.a1 = a1
325 params.b1 = b1
326 params.a2 = a2
327 params.b2 = b2
328 params.z1 = z1
329 params.z2 = z2
330 }
331
332 return endoParams
333 }
334
335 func main() {
336 fi, err := os.Create("compressedbytepoints.go")
337 if err != nil {
338 log.Fatal(err)
339 }
340 defer fi.Close()
341
342
343 serialized := serializedBytePoints()
344 var compressed bytes.Buffer
345 w := zlib.NewWriter(&compressed)
346 if _, err := w.Write(serialized); err != nil {
347 fmt.Println(err)
348 os.Exit(1)
349 }
350 w.Close()
351
352
353 encoded := make([]byte, base64.StdEncoding.EncodedLen(compressed.Len()))
354 base64.StdEncoding.Encode(encoded, compressed.Bytes())
355
356 fmt.Fprintln(fi, "// Copyright (c) 2015 The btcsuite developers")
357 fmt.Fprintln(fi, "// Copyright (c) 2015-2022 The Decred developers")
358 fmt.Fprintln(fi, "// Use of this source code is governed by an ISC")
359 fmt.Fprintln(fi, "// license that can be found in the LICENSE file.")
360 fmt.Fprintln(fi)
361 fmt.Fprintln(fi, "package secp256k1")
362 fmt.Fprintln(fi)
363 fmt.Fprintln(fi, "// Auto-generated file (see genprecomps.go)")
364 fmt.Fprintln(fi, "// DO NOT EDIT")
365 fmt.Fprintln(fi)
366 fmt.Fprintf(fi, "var compressedBytePoints = %q\n", string(encoded))
367 fmt.Fprintln(fi)
368 fmt.Fprintln(fi, "// Set accessor to a real function.")
369 fmt.Fprintln(fi, "func init() {")
370 fmt.Fprintln(fi, " compressedBytePointsFn = func() string {")
371 fmt.Fprintln(fi, " return compressedBytePoints")
372 fmt.Fprintln(fi, " }")
373 fmt.Fprintln(fi, "}")
374
375 printParams := func(p *endomorphismParams) {
376 fmt.Printf("lambda: %x\n", p.lambda)
377 fmt.Printf(" beta: %x\n", p.beta)
378 fmt.Printf(" a1: %x\n", p.a1)
379 fmt.Printf(" b1: %x\n", p.b1)
380 fmt.Printf(" a2: %x\n", p.a2)
381 fmt.Printf(" b2: %x\n", p.b2)
382 fmt.Printf(" z1: %x\n", p.z1)
383 fmt.Printf(" z2: %x\n", p.z2)
384 }
385 endoParams := deriveEndomorphismParams()
386 fmt.Println("The following are the computed values to make use of the " +
387 "secp256k1 endomorphism.\nThey consist of the lambda and beta " +
388 "values along with the associated linearly independent vectors " +
389 "(a1, b1, a2, b2) and estimates (z1, z2) used when decomposing " +
390 "scalars:")
391 printParams(&endoParams[0])
392 fmt.Println()
393
394 fmt.Println("Alternatively, the following parameters are valid as well:")
395 printParams(&endoParams[1])
396 }
397
View as plain text