btcec: Optimize pre-computed table load.

This commit modifies the pre-computed table used to optimize the secp256k1
scalar multiplication to a string instead of a byte slice.  This change
makes the compile more efficient since the Go compiler internally
represents bytes slices inefficiently.

This reduces the memory needed to compile btcec to 3MB versus the previous
40MB before this change.

In addition, it modifies the code which loads the pre-computed table to
deserialize directly into the table instead of into locals that are then
copied.

Fixes #297.
This commit is contained in:
Dave Collins 2015-02-11 23:10:53 -06:00
parent 15aa91514a
commit f6a437d4c9
4 changed files with 10 additions and 14 deletions

View file

@ -50,7 +50,7 @@ func main() {
fmt.Fprintln(fi, "// Auto-generated file (see genprecomps.go)") fmt.Fprintln(fi, "// Auto-generated file (see genprecomps.go)")
fmt.Fprintln(fi, "// DO NOT EDIT") fmt.Fprintln(fi, "// DO NOT EDIT")
fmt.Fprintln(fi) fmt.Fprintln(fi)
fmt.Fprintf(fi, "var secp256k1BytePoints = []byte(%q)\n", encoded) fmt.Fprintf(fi, "var secp256k1BytePoints = %q\n", string(encoded))
a1, b1, a2, b2 := btcec.S256().EndomorphismVectors() a1, b1, a2, b2 := btcec.S256().EndomorphismVectors()
fmt.Println("The following values are the computed linearly " + fmt.Println("The following values are the computed linearly " +

View file

@ -18,7 +18,7 @@ import (
// secp256k1BytePoints are dummy points used so the code which generates the // secp256k1BytePoints are dummy points used so the code which generates the
// real values can compile. // real values can compile.
var secp256k1BytePoints = []byte{} var secp256k1BytePoints = ""
// getDoublingPoints returns all the possible G^(2^i) for i in // 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) // 0..n-1 where n is the curve's bit size (256 in the case of secp256k1)

View file

@ -5,11 +5,11 @@
package btcec package btcec
import ( import (
"bytes"
"compress/zlib" "compress/zlib"
"encoding/base64" "encoding/base64"
"encoding/binary" "encoding/binary"
"io/ioutil" "io/ioutil"
"strings"
) )
//go:generate go run -tags gensecp256k1 genprecomps.go //go:generate go run -tags gensecp256k1 genprecomps.go
@ -23,17 +23,14 @@ import (
func loadS256BytePoints() error { func loadS256BytePoints() error {
// There will be no byte points to load when generating them. // There will be no byte points to load when generating them.
bp := secp256k1BytePoints bp := secp256k1BytePoints
if len(secp256k1BytePoints) == 0 { if len(bp) == 0 {
return nil return nil
} }
// Decompress the pre-computed table used to accelerate scalar base // Decompress the pre-computed table used to accelerate scalar base
// multiplication. // multiplication.
decoded := make([]byte, base64.StdEncoding.DecodedLen(len(bp))) decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(bp))
if _, err := base64.StdEncoding.Decode(decoded, bp); err != nil { r, err := zlib.NewReader(decoder)
return err
}
r, err := zlib.NewReader(bytes.NewReader(decoded))
if err != nil { if err != nil {
return err return err
} }
@ -48,7 +45,9 @@ func loadS256BytePoints() error {
for byteNum := 0; byteNum < 32; byteNum++ { for byteNum := 0; byteNum < 32; byteNum++ {
// All points in this window. // All points in this window.
for i := 0; i < 256; i++ { for i := 0; i < 256; i++ {
px, py, pz := new(fieldVal), new(fieldVal), new(fieldVal) px := &bytePoints[byteNum][i][0]
py := &bytePoints[byteNum][i][1]
pz := &bytePoints[byteNum][i][2]
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
px.n[i] = binary.LittleEndian.Uint32(serialized[offset:]) px.n[i] = binary.LittleEndian.Uint32(serialized[offset:])
offset += 4 offset += 4
@ -61,9 +60,6 @@ func loadS256BytePoints() error {
pz.n[i] = binary.LittleEndian.Uint32(serialized[offset:]) pz.n[i] = binary.LittleEndian.Uint32(serialized[offset:])
offset += 4 offset += 4
} }
bytePoints[byteNum][i][0] = *px
bytePoints[byteNum][i][1] = *py
bytePoints[byteNum][i][2] = *pz
} }
} }
secp256k1.bytePoints = &bytePoints secp256k1.bytePoints = &bytePoints

File diff suppressed because one or more lines are too long