Skip to content

Commit

Permalink
btcec: Optimize pre-computed table load.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
davecgh committed Feb 12, 2015
1 parent 15aa915 commit f6a437d
Show file tree
Hide file tree
Showing 4 changed files with 10 additions and 14 deletions.
2 changes: 1 addition & 1 deletion btcec/genprecomps.go
Expand Up @@ -50,7 +50,7 @@ func main() {
fmt.Fprintln(fi, "// Auto-generated file (see genprecomps.go)")
fmt.Fprintln(fi, "// DO NOT EDIT")
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()
fmt.Println("The following values are the computed linearly " +
Expand Down
2 changes: 1 addition & 1 deletion btcec/gensecp256k1.go
Expand Up @@ -18,7 +18,7 @@ import (

// secp256k1BytePoints are dummy points used so the code which generates the
// real values can compile.
var secp256k1BytePoints = []byte{}
var secp256k1BytePoints = ""

// 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)
Expand Down
18 changes: 7 additions & 11 deletions btcec/precompute.go
Expand Up @@ -5,11 +5,11 @@
package btcec

import (
"bytes"
"compress/zlib"
"encoding/base64"
"encoding/binary"
"io/ioutil"
"strings"
)

//go:generate go run -tags gensecp256k1 genprecomps.go
Expand All @@ -23,17 +23,14 @@ import (
func loadS256BytePoints() error {
// There will be no byte points to load when generating them.
bp := secp256k1BytePoints
if len(secp256k1BytePoints) == 0 {
if len(bp) == 0 {
return nil
}

// Decompress the pre-computed table used to accelerate scalar base
// multiplication.
decoded := make([]byte, base64.StdEncoding.DecodedLen(len(bp)))
if _, err := base64.StdEncoding.Decode(decoded, bp); err != nil {
return err
}
r, err := zlib.NewReader(bytes.NewReader(decoded))
decoder := base64.NewDecoder(base64.StdEncoding, strings.NewReader(bp))
r, err := zlib.NewReader(decoder)
if err != nil {
return err
}
Expand All @@ -48,7 +45,9 @@ func loadS256BytePoints() error {
for byteNum := 0; byteNum < 32; byteNum++ {
// All points in this window.
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++ {
px.n[i] = binary.LittleEndian.Uint32(serialized[offset:])
offset += 4
Expand All @@ -61,9 +60,6 @@ func loadS256BytePoints() error {
pz.n[i] = binary.LittleEndian.Uint32(serialized[offset:])
offset += 4
}
bytePoints[byteNum][i][0] = *px
bytePoints[byteNum][i][1] = *py
bytePoints[byteNum][i][2] = *pz
}
}
secp256k1.bytePoints = &bytePoints
Expand Down
2 changes: 1 addition & 1 deletion btcec/secp256k1.go

Large diffs are not rendered by default.

0 comments on commit f6a437d

Please sign in to comment.