]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/internal/nistec: use precomputed P-256 generators in purego
authorFilippo Valsorda <filippo@golang.org>
Sat, 27 Jul 2024 13:39:07 +0000 (15:39 +0200)
committerGopher Robot <gobot@golang.org>
Tue, 19 Nov 2024 22:30:17 +0000 (22:30 +0000)
Change-Id: I73cd2ff857512a90585b860906061b71d1c19e41
Reviewed-on: https://go-review.googlesource.com/c/go/+/627941
Reviewed-by: Russ Cox <rsc@golang.org>
Auto-Submit: Filippo Valsorda <filippo@golang.org>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>

src/crypto/internal/nistec/p256.go
src/crypto/internal/nistec/p256_asm.go
src/crypto/internal/nistec/p256_table.bin [moved from src/crypto/internal/nistec/p256_asm_table.bin with 100% similarity]
src/crypto/internal/nistec/p256_test.go [moved from src/crypto/internal/nistec/p256_asm_table_test.go with 63% similarity]

index dd025e70592cd9d2a596cbe10305f8e3bf1937a8..611bfbac73aa7a90dfb4f1567f0854e0d7858d9f 100644 (file)
@@ -9,10 +9,13 @@ package nistec
 import (
        "crypto/internal/nistec/fiat"
        "crypto/subtle"
+       _ "embed"
        "errors"
        "internal/byteorder"
+       "internal/goarch"
        "math/bits"
        "sync"
+       "unsafe"
 )
 
 // p256ElementLength is the length of an element of the base or scalar field,
@@ -522,40 +525,29 @@ func (table *p256AffineTable) Select(p *p256AffinePoint, n uint8) {
        }
 }
 
-var _p256GeneratorTable *[43]p256AffineTable
-var p256GeneratorTableOnce sync.Once
-
-// p256GeneratorTable returns a sequence of p256Tables. The first table contains
-// multiples of G. Each successive table is the previous table doubled four
-// times.
-func p256GeneratorTable() *[43]p256AffineTable {
-       p256GeneratorTableOnce.Do(func() {
-               _p256GeneratorTable = new([43]p256AffineTable)
-               base := NewP256Point().SetGenerator()
-               for i := 0; i < 43; i++ {
-                       p := NewP256Point().Set(base)
-                       _p256GeneratorTable[i][0] = *p256ToAffine(p)
-                       for j := 1; j < 32; j++ {
-                               p := NewP256Point().AddAffine(base, &_p256GeneratorTable[i][j-1], 1)
-                               _p256GeneratorTable[i][j] = *p256ToAffine(p)
-                       }
-                       base.Double(base)
-                       base.Double(base)
-                       base.Double(base)
-                       base.Double(base)
-                       base.Double(base)
-                       base.Double(base)
+// p256GeneratorTables is a series of precomputed multiples of G, the canonical
+// generator. The first p256AffineTable contains multiples of G. The second one
+// multiples of [2⁶]G, the third one of [2¹²]G, and so on, where each successive
+// table is the previous table doubled six times. Six is the width of the
+// sliding window used in ScalarBaseMult, and having each table already
+// pre-doubled lets us avoid the doublings between windows entirely. This table
+// MUST NOT be modified, as it aliases into p256GeneratorTablesEmbed below.
+var p256GeneratorTables *[43]p256AffineTable
+
+//go:embed p256_table.bin
+var p256GeneratorTablesEmbed string
+
+func init() {
+       p256GeneratorTablesPtr := (*unsafe.Pointer)(unsafe.Pointer(&p256GeneratorTablesEmbed))
+       if goarch.BigEndian {
+               var newTable [43 * 32 * 2 * 4]uint64
+               for i, x := range (*[43 * 32 * 2 * 4][8]byte)(*p256GeneratorTablesPtr) {
+                       newTable[i] = byteorder.LeUint64(x[:])
                }
-       })
-       return _p256GeneratorTable
-}
-
-func p256ToAffine(p *P256Point) *p256AffinePoint {
-       inv := new(fiat.P256Element).Invert(&p.z)
-       pa := &p256AffinePoint{}
-       pa.x.Mul(&p.x, inv)
-       pa.y.Mul(&p.y, inv)
-       return pa
+               newTablePtr := unsafe.Pointer(&newTable)
+               p256GeneratorTablesPtr = &newTablePtr
+       }
+       p256GeneratorTables = (*[43]p256AffineTable)(*p256GeneratorTablesPtr)
 }
 
 func boothW6(in uint64) (uint8, int) {
@@ -575,7 +567,6 @@ func (p *P256Point) ScalarBaseMult(scalar []byte) (*P256Point, error) {
        s := new(p256OrdElement)
        p256OrdBigToLittle(s, (*[32]byte)(scalar))
        p256OrdReduce(s)
-       tables := p256GeneratorTable()
 
        p.Set(NewP256Point())
 
@@ -589,7 +580,7 @@ func (p *P256Point) ScalarBaseMult(scalar []byte) (*P256Point, error) {
        _ = sign
 
        t := &p256AffinePoint{}
-       table := &tables[(index+1)/6]
+       table := &p256GeneratorTables[(index+1)/6]
        table.Select(t, sel)
        selIsNotZero := subtle.ConstantTimeByteEq(sel, 0) ^ 1
        p.x.Select(&t.x, &p.x, selIsNotZero)
@@ -610,7 +601,7 @@ func (p *P256Point) ScalarBaseMult(scalar []byte) (*P256Point, error) {
 
                selIsNotZero := subtle.ConstantTimeByteEq(sel, 0) ^ 1
 
-               table := &tables[(index+1)/6]
+               table := &p256GeneratorTables[(index+1)/6]
                table.Select(t, sel)
                t.Negate(sign)
                p.AddAffine(p, t, selIsNotZero)
index 599eee96236422c07e3c7d39959a460f5472d802..632a64127eb1d4476cdb21b6f17c1074793b361c 100644 (file)
@@ -324,12 +324,12 @@ type p256AffineTable [32]p256AffinePoint
 // generator. The first p256AffineTable contains multiples of G. The second one
 // multiples of [2⁶]G, the third one of [2¹²]G, and so on, where each successive
 // table is the previous table doubled six times. Six is the width of the
-// sliding window used in p256ScalarMult, and having each table already
+// sliding window used in p256ScalarBaseMult, and having each table already
 // pre-doubled lets us avoid the doublings between windows entirely. This table
 // MUST NOT be modified, as it aliases into p256PrecomputedEmbed below.
 var p256Precomputed *[43]p256AffineTable
 
-//go:embed p256_asm_table.bin
+//go:embed p256_table.bin
 var p256PrecomputedEmbed string
 
 func init() {
similarity index 63%
rename from src/crypto/internal/nistec/p256_asm_table_test.go
rename to src/crypto/internal/nistec/p256_test.go
index cba455d32db965dc2a61cd2bcb1aafaa1b818c40..7ebe7209dcc718da5ddf398beaeabb852fee4f62 100644 (file)
@@ -2,11 +2,13 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-//go:build !purego && (amd64 || arm64 || ppc64le || s390x)
+//go:build (!amd64 && !arm64 && !ppc64le && !s390x) || purego
 
 package nistec
 
 import (
+       "bytes"
+       "crypto/internal/nistec/fiat"
        "fmt"
        "testing"
 )
@@ -16,7 +18,7 @@ func TestP256PrecomputedTable(t *testing.T) {
 
        for i := 0; i < 43; i++ {
                t.Run(fmt.Sprintf("table[%d]", i), func(t *testing.T) {
-                       testP256AffineTable(t, base, &p256Precomputed[i])
+                       testP256AffineTable(t, base, &p256GeneratorTables[i])
                })
 
                for k := 0; k < 6; k++ {
@@ -27,22 +29,19 @@ func TestP256PrecomputedTable(t *testing.T) {
 
 func testP256AffineTable(t *testing.T, base *P256Point, table *p256AffineTable) {
        p := NewP256Point()
-       zInv := new(p256Element)
-       zInvSq := new(p256Element)
+       zInv := new(fiat.P256Element)
 
        for j := 0; j < 32; j++ {
                p.Add(p, base)
 
                // Convert p to affine coordinates.
-               p256Inverse(zInv, &p.z)
-               p256Sqr(zInvSq, zInv, 1)
-               p256Mul(zInv, zInv, zInvSq)
+               zInv.Invert(&p.z)
+               p.x.Mul(&p.x, zInv)
+               p.y.Mul(&p.y, zInv)
+               p.z.One()
 
-               p256Mul(&p.x, &p.x, zInvSq)
-               p256Mul(&p.y, &p.y, zInv)
-               p.z = p256One
-
-               if p256Equal(&table[j].x, &p.x) != 1 || p256Equal(&table[j].y, &p.y) != 1 {
+               if !bytes.Equal(table[j].x.Bytes(), p.x.Bytes()) ||
+                       !bytes.Equal(table[j].y.Bytes(), p.y.Bytes()) {
                        t.Fatalf("incorrect table entry at index %d", j)
                }
        }