9535058a7b
This commit reworks the way that the pre-computed table which is used to accelerate scalar base multiple is generated and loaded to make use of the go generate infrastructure and greatly reduce the memory needed to compile as well as speed up the compile. Previously, the table was being generated using the in-memory representation directly written into the file. Since the table has a very large number of entries, the Go compiler was taking up to nearly 1GB to compile. It also took a comparatively long period of time to compile. Instead, this commit modifies the generated table to be a serialized, compressed, and base64-encoded byte slice. At init time, this process is reversed to create the in-memory representation. This approach provides fast compile times with much lower memory needed to compile (16MB versus 1GB). In addition, the init time cost is extremely low, especially as compared to computing the entire table. Finally, the automatic generation wasn't really automatic. It is now fully automatic with 'go generate'.
76 lines
2.5 KiB
Go
76 lines
2.5 KiB
Go
// Copyright (c) 2014-2015 Conformal Systems LLC.
|
|
// Use of this source code is governed by an ISC
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// This file is ignored during the regular build due to the following build tag.
|
|
// This build tag is set during go generate.
|
|
// +build gensecp256k1
|
|
|
|
package btcec
|
|
|
|
import "encoding/binary"
|
|
|
|
// secp256k1BytePoints are dummy points used so the code which generates the
|
|
// real values can compile.
|
|
var secp256k1BytePoints = []byte{}
|
|
|
|
// getDoublingPoints returns all the possible G^(2^i) for i in
|
|
// 0..n-1 where n is the curve's bit size (256 in the case of secp256k1)
|
|
// the coordinates are recorded as Jacobian coordinates.
|
|
func (curve *KoblitzCurve) getDoublingPoints() [][3]fieldVal {
|
|
bitSize := curve.Params().BitSize
|
|
doublingPoints := make([][3]fieldVal, bitSize)
|
|
|
|
// initialize px, py, pz to the Jacobian coordinates for the base point
|
|
px, py := curve.bigAffineToField(curve.Gx, curve.Gy)
|
|
pz := new(fieldVal).SetInt(1)
|
|
for i := 0; i < bitSize; i++ {
|
|
doublingPoints[i] = [3]fieldVal{*px, *py, *pz}
|
|
// P = 2*P
|
|
curve.doubleJacobian(px, py, pz, px, py, pz)
|
|
}
|
|
return doublingPoints
|
|
}
|
|
|
|
// SerializedBytePoints returns a serialized byte slice which contains all of
|
|
// the possible points per 8-bit window. This is used to when generating
|
|
// secp256k1.go.
|
|
func (curve *KoblitzCurve) SerializedBytePoints() []byte {
|
|
bitSize := curve.Params().BitSize
|
|
byteSize := bitSize / 8
|
|
doublingPoints := curve.getDoublingPoints()
|
|
|
|
// Segregate the bits into byte-sized windows
|
|
serialized := make([]byte, byteSize*256*3*10*4)
|
|
offset := 0
|
|
for byteNum := 0; byteNum < byteSize; byteNum++ {
|
|
// Grab the 8 bits that make up this byte from doublingPoints.
|
|
startingBit := 8 * (byteSize - byteNum - 1)
|
|
computingPoints := doublingPoints[startingBit : startingBit+8]
|
|
|
|
// Compute all points in this window and serialize them.
|
|
for i := 0; i < 256; i++ {
|
|
px, py, pz := new(fieldVal), new(fieldVal), new(fieldVal)
|
|
for j := 0; j < 8; j++ {
|
|
if i>>uint(j)&1 == 1 {
|
|
curve.addJacobian(px, py, pz, &computingPoints[j][0],
|
|
&computingPoints[j][1], &computingPoints[j][2], px, py, pz)
|
|
}
|
|
}
|
|
for i := 0; i < 10; i++ {
|
|
binary.LittleEndian.PutUint32(serialized[offset:], px.n[i])
|
|
offset += 4
|
|
}
|
|
for i := 0; i < 10; i++ {
|
|
binary.LittleEndian.PutUint32(serialized[offset:], py.n[i])
|
|
offset += 4
|
|
}
|
|
for i := 0; i < 10; i++ {
|
|
binary.LittleEndian.PutUint32(serialized[offset:], pz.n[i])
|
|
offset += 4
|
|
}
|
|
}
|
|
}
|
|
|
|
return serialized
|
|
}
|