lbcd/gensecp256k1.go
Jimmy Song d69442834c Optimize ScalarBaseMult
Code uses a windowing/precomputing strategy to minimize ECC math.
Every 8-bit window of the 256 bits that compose a possible scalar multiple has a complete map that's pre-computed.
The precomputed data is in secp256k1.go and the generator for that file is in gensecp256k1.go

Also fixed a spelling error in a benchmark test.

Results so far seem to indicate the time taken is about 35% of what it was before.

Closes #2
2014-09-24 19:07:58 -05:00

67 lines
2.7 KiB
Go

// Copyright (c) 2014 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
// +build gensecp256k1
package btcec
import (
"fmt"
)
// 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
}
// PrintBytePoints prints all the possible points per 8-bit window.
// normally, this is used to generate secp256k1.go
func (curve *KoblitzCurve) PrintBytePoints() {
bitSize := curve.Params().BitSize
byteSize := bitSize / 8
doublingPoints := curve.getDoublingPoints()
fmt.Println("// Copyright (c) 2014 Conformal Systems LLC.")
fmt.Println("// Use of this source code is governed by an ISC")
fmt.Println("// license that can be found in the LICENSE file.")
fmt.Println()
fmt.Println("package btcec")
fmt.Println()
fmt.Println("// Auto-generated file (see gensecp256k1.go)")
fmt.Printf("var secp256k1BytePoints = [%d][256][3]fieldVal{\n", byteSize)
// Segregate the bits into byte-sized windows
for byteNum := 0; byteNum < byteSize; byteNum++ {
fmt.Printf("\t{\n")
// 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
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)
}
}
fmt.Printf("\t\t{\n\t\t\tfieldVal{[10]uint32{%d, %d, %d, %d, %d, %d, %d, %d, %d, %d}},\n", px.n[0], px.n[1], px.n[2], px.n[3], px.n[4], px.n[5], px.n[6], px.n[7], px.n[8], px.n[9])
fmt.Printf("\t\t\tfieldVal{[10]uint32{%d, %d, %d, %d, %d, %d, %d, %d, %d, %d}},\n", py.n[0], py.n[1], py.n[2], py.n[3], py.n[4], py.n[5], py.n[6], py.n[7], py.n[8], py.n[9])
fmt.Printf("\t\t\tfieldVal{[10]uint32{%d, %d, %d, %d, %d, %d, %d, %d, %d, %d}},\n\t\t},\n", pz.n[0], pz.n[1], pz.n[2], pz.n[3], pz.n[4], pz.n[5], pz.n[6], pz.n[7], pz.n[8], pz.n[9])
}
fmt.Printf("\t},\n")
}
fmt.Printf("}\n")
}