Add initial nistec project files
This commit is contained in:
27
LICENSE
Normal file
27
LICENSE
Normal file
@@ -0,0 +1,27 @@
|
||||
Copyright 2009 The Go Authors.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Google LLC nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
24
README.md
Normal file
24
README.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# sources.truenas.cloud/code/nistec
|
||||
|
||||
```
|
||||
import "sources.truenas.cloud/code/nistec"
|
||||
```
|
||||
|
||||
This package implements the NIST P elliptic curves, according to FIPS 186-4
|
||||
and SEC 1, Version 2.0, exposing the necessary APIs to build a wide array of
|
||||
higher-level primitives.
|
||||
|
||||
It's an exported version of `crypto/internal/fips140/nistec` in the standard library,
|
||||
which powers `crypto/elliptic`, `crypto/ecdsa`, and `crypto/ecdh`.
|
||||
The git history has been preserved, and new upstream changes are applied periodically.
|
||||
|
||||
This package uses fiat-crypto or specialized assembly and Go code for its
|
||||
backend field arithmetic (not math/big) and exposes constant-time, heap
|
||||
allocation-free, byte slice-based safe APIs. Group operations use modern and
|
||||
safe complete addition formulas where possible. The point at infinity is
|
||||
handled and encoded according to SEC 1, Version 2.0, and invalid curve points
|
||||
can't be represented. This makes it particularly suitable to be used as a
|
||||
prime order group implementation.
|
||||
|
||||
Use the `purego` build tag to exclude the assembly and rely entirely on formally
|
||||
verified fiat-crypto arithmetic and complete addition formulas.
|
||||
11
_asm/go.mod
Normal file
11
_asm/go.mod
Normal file
@@ -0,0 +1,11 @@
|
||||
module crypto/internal/fips140/nistec/_asm
|
||||
|
||||
go 1.24
|
||||
|
||||
require github.com/mmcloughlin/avo v0.6.0
|
||||
|
||||
require (
|
||||
golang.org/x/mod v0.20.0 // indirect
|
||||
golang.org/x/sync v0.8.0 // indirect
|
||||
golang.org/x/tools v0.24.0 // indirect
|
||||
)
|
||||
8
_asm/go.sum
Normal file
8
_asm/go.sum
Normal file
@@ -0,0 +1,8 @@
|
||||
github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY=
|
||||
github.com/mmcloughlin/avo v0.6.0/go.mod h1:8CoAGaCSYXtCPR+8y18Y9aB/kxb8JSS6FRI7mSkvD+8=
|
||||
golang.org/x/mod v0.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
|
||||
golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
|
||||
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24=
|
||||
golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ=
|
||||
2708
_asm/p256_asm.go
Normal file
2708
_asm/p256_asm.go
Normal file
File diff suppressed because it is too large
Load Diff
62
benchmark_test.go
Normal file
62
benchmark_test.go
Normal file
@@ -0,0 +1,62 @@
|
||||
// Copyright 2024 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package nistec_test
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"testing"
|
||||
|
||||
"sources.truenas.cloud/code/nistec"
|
||||
)
|
||||
|
||||
func BenchmarkScalarMult(b *testing.B) {
|
||||
b.Run("P224", func(b *testing.B) {
|
||||
benchmarkScalarMult(b, nistec.NewP224Point().SetGenerator(), 28)
|
||||
})
|
||||
b.Run("P256", func(b *testing.B) {
|
||||
benchmarkScalarMult(b, nistec.NewP256Point().SetGenerator(), 32)
|
||||
})
|
||||
b.Run("P384", func(b *testing.B) {
|
||||
benchmarkScalarMult(b, nistec.NewP384Point().SetGenerator(), 48)
|
||||
})
|
||||
b.Run("P521", func(b *testing.B) {
|
||||
benchmarkScalarMult(b, nistec.NewP521Point().SetGenerator(), 66)
|
||||
})
|
||||
}
|
||||
|
||||
func benchmarkScalarMult[P nistPoint[P]](b *testing.B, p P, scalarSize int) {
|
||||
scalar := make([]byte, scalarSize)
|
||||
rand.Read(scalar)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
p.ScalarMult(p, scalar)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkScalarBaseMult(b *testing.B) {
|
||||
b.Run("P224", func(b *testing.B) {
|
||||
benchmarkScalarBaseMult(b, nistec.NewP224Point().SetGenerator(), 28)
|
||||
})
|
||||
b.Run("P256", func(b *testing.B) {
|
||||
benchmarkScalarBaseMult(b, nistec.NewP256Point().SetGenerator(), 32)
|
||||
})
|
||||
b.Run("P384", func(b *testing.B) {
|
||||
benchmarkScalarBaseMult(b, nistec.NewP384Point().SetGenerator(), 48)
|
||||
})
|
||||
b.Run("P521", func(b *testing.B) {
|
||||
benchmarkScalarBaseMult(b, nistec.NewP521Point().SetGenerator(), 66)
|
||||
})
|
||||
}
|
||||
|
||||
func benchmarkScalarBaseMult[P nistPoint[P]](b *testing.B, p P, scalarSize int) {
|
||||
scalar := make([]byte, scalarSize)
|
||||
rand.Read(scalar)
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
p.ScalarBaseMult(scalar)
|
||||
}
|
||||
}
|
||||
85
extra.go
Normal file
85
extra.go
Normal file
@@ -0,0 +1,85 @@
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package nistec
|
||||
|
||||
import "sources.truenas.cloud/code/nistec/internal/fiat"
|
||||
|
||||
// Negate sets p = -q and returns p.
|
||||
func (p *P224Point) Negate(q *P224Point) *P224Point {
|
||||
p.x.Set(q.x)
|
||||
p.y.Sub(new(fiat.P224Element), q.y)
|
||||
p.z.Set(q.z)
|
||||
return p
|
||||
}
|
||||
|
||||
// Negate sets p = -q and returns p.
|
||||
func (p *P384Point) Negate(q *P384Point) *P384Point {
|
||||
p.x.Set(q.x)
|
||||
p.y.Sub(new(fiat.P384Element), q.y)
|
||||
p.z.Set(q.z)
|
||||
return p
|
||||
}
|
||||
|
||||
// Negate sets p = -q and returns p.
|
||||
func (p *P521Point) Negate(q *P521Point) *P521Point {
|
||||
p.x.Set(q.x)
|
||||
p.y.Sub(new(fiat.P521Element), q.y)
|
||||
p.z.Set(q.z)
|
||||
return p
|
||||
}
|
||||
|
||||
// IsInfinity returns 1 if p is the point-at-infinity, 0 otherwise.
|
||||
func (p *P224Point) IsInfinity() int {
|
||||
return p.z.IsZero()
|
||||
}
|
||||
|
||||
// IsInfinity returns 1 if p is the point-at-infinity, 0 otherwise.
|
||||
func (p *P384Point) IsInfinity() int {
|
||||
return p.z.IsZero()
|
||||
}
|
||||
|
||||
// IsInfinity returns 1 if p is the point-at-infinity, 0 otherwise.
|
||||
func (p *P521Point) IsInfinity() int {
|
||||
return p.z.IsZero()
|
||||
}
|
||||
|
||||
// Equal returns 1 if p and q represent the same point, 0 otherwise.
|
||||
func (p *P224Point) Equal(q *P224Point) int {
|
||||
pinf := p.z.IsZero()
|
||||
qinf := q.z.IsZero()
|
||||
bothinf := pinf & qinf
|
||||
noneinf := (1 - pinf) & (1 - qinf)
|
||||
px := new(fiat.P224Element).Mul(p.x, q.z)
|
||||
qx := new(fiat.P224Element).Mul(q.x, p.z)
|
||||
py := new(fiat.P224Element).Mul(p.y, q.z)
|
||||
qy := new(fiat.P224Element).Mul(q.y, p.z)
|
||||
return bothinf | (noneinf & px.Equal(qx) & py.Equal(qy))
|
||||
}
|
||||
|
||||
// Equal returns 1 if p and q represent the same point, 0 otherwise.
|
||||
func (p *P384Point) Equal(q *P384Point) int {
|
||||
pinf := p.z.IsZero()
|
||||
qinf := q.z.IsZero()
|
||||
bothinf := pinf & qinf
|
||||
noneinf := (1 - pinf) & (1 - qinf)
|
||||
px := new(fiat.P384Element).Mul(p.x, q.z)
|
||||
qx := new(fiat.P384Element).Mul(q.x, p.z)
|
||||
py := new(fiat.P384Element).Mul(p.y, q.z)
|
||||
qy := new(fiat.P384Element).Mul(q.y, p.z)
|
||||
return bothinf | (noneinf & px.Equal(qx) & py.Equal(qy))
|
||||
}
|
||||
|
||||
// Equal returns 1 if p and q represent the same point, 0 otherwise.
|
||||
func (p *P521Point) Equal(q *P521Point) int {
|
||||
pinf := p.z.IsZero()
|
||||
qinf := q.z.IsZero()
|
||||
bothinf := pinf & qinf
|
||||
noneinf := (1 - pinf) & (1 - qinf)
|
||||
px := new(fiat.P521Element).Mul(p.x, q.z)
|
||||
qx := new(fiat.P521Element).Mul(q.x, p.z)
|
||||
py := new(fiat.P521Element).Mul(p.y, q.z)
|
||||
qy := new(fiat.P521Element).Mul(q.y, p.z)
|
||||
return bothinf | (noneinf & px.Equal(qx) & py.Equal(qy))
|
||||
}
|
||||
61
extra_asm.go
Normal file
61
extra_asm.go
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// 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)
|
||||
|
||||
package nistec
|
||||
|
||||
import "sources.truenas.cloud/code/nistec/internal/fiat"
|
||||
|
||||
// Negate sets p = -q and returns p.
|
||||
func (p *P256Point) Negate(q *P256Point) *P256Point {
|
||||
// fiat.P256Element is a little-endian Montgomery domain fully-reduced
|
||||
// element, like p256Element, so they are actually interchangable.
|
||||
qy := new(fiat.P256Element)
|
||||
*qy.Bits() = q.y
|
||||
py := new(fiat.P256Element).Sub(new(fiat.P256Element), qy)
|
||||
|
||||
p.x = q.x
|
||||
p.y = *py.Bits()
|
||||
p.z = q.z
|
||||
return p
|
||||
}
|
||||
|
||||
// IsInfinity returns 1 if p is the point-at-infinity, 0 otherwise.
|
||||
func (p *P256Point) IsInfinity() int {
|
||||
return p.isInfinity()
|
||||
}
|
||||
|
||||
// Equal returns 1 if p and q represent the same point, 0 otherwise.
|
||||
func (p *P256Point) Equal(q *P256Point) int {
|
||||
pinf := p256Equal(&p.z, &p256Zero)
|
||||
qinf := p256Equal(&q.z, &p256Zero)
|
||||
bothinf := pinf & qinf
|
||||
noneinf := (1 - pinf) & (1 - qinf)
|
||||
|
||||
// xp = Xp / Zp²
|
||||
// yp = Yp / Zp³
|
||||
// xq = Xq / Zq²
|
||||
// yq = Yq / Zq³
|
||||
// If Zp != 0 and Zq != 0, then:
|
||||
// xp == yp <=> Xp*Zq² == Xq*Zp²
|
||||
// xq == yq <=> Yp*Zq³ == Yq*Zp³
|
||||
px := new(p256Element)
|
||||
qx := new(p256Element)
|
||||
py := new(p256Element)
|
||||
qy := new(p256Element)
|
||||
pz := new(p256Element)
|
||||
qz := new(p256Element)
|
||||
p256Sqr(pz, &p.z, 1)
|
||||
p256Sqr(qz, &q.z, 1)
|
||||
p256Mul(px, &p.x, qz)
|
||||
p256Mul(qx, &q.x, pz)
|
||||
samex := p256Equal(px, qx)
|
||||
p256Mul(pz, pz, &p.z)
|
||||
p256Mul(qz, qz, &q.z)
|
||||
p256Mul(py, &p.y, qz)
|
||||
p256Mul(qy, &q.y, pz)
|
||||
samey := p256Equal(py, qy)
|
||||
return bothinf | (noneinf & samex & samey)
|
||||
}
|
||||
35
extra_noasm.go
Normal file
35
extra_noasm.go
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// 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)
|
||||
|
||||
package nistec
|
||||
|
||||
import "sources.truenas.cloud/code/nistec/internal/fiat"
|
||||
|
||||
// Negate sets p = -q and returns p.
|
||||
func (p *P256Point) Negate(q *P256Point) *P256Point {
|
||||
p.x.Set(&q.x)
|
||||
p.y.Sub(new(fiat.P256Element), &q.y)
|
||||
p.z.Set(&q.z)
|
||||
return p
|
||||
}
|
||||
|
||||
// IsInfinity returns 1 if p is the point-at-infinity, 0 otherwise.
|
||||
func (p *P256Point) IsInfinity() int {
|
||||
return p.z.IsZero()
|
||||
}
|
||||
|
||||
// Equal returns 1 if p and q represent the same point, 0 otherwise.
|
||||
func (p *P256Point) Equal(q *P256Point) int {
|
||||
pinf := p.z.IsZero()
|
||||
qinf := q.z.IsZero()
|
||||
bothinf := pinf & qinf
|
||||
noneinf := (1 - pinf) & (1 - qinf)
|
||||
px := new(fiat.P256Element).Mul(&p.x, &q.z)
|
||||
qx := new(fiat.P256Element).Mul(&q.x, &p.z)
|
||||
py := new(fiat.P256Element).Mul(&p.y, &q.z)
|
||||
qy := new(fiat.P256Element).Mul(&q.y, &p.z)
|
||||
return bothinf | (noneinf & px.Equal(qx) & py.Equal(qy))
|
||||
}
|
||||
5
extra_norace_test.go
Normal file
5
extra_norace_test.go
Normal file
@@ -0,0 +1,5 @@
|
||||
//go:build !race
|
||||
|
||||
package nistec_test
|
||||
|
||||
const raceEnabled = false
|
||||
5
extra_race_test.go
Normal file
5
extra_race_test.go
Normal file
@@ -0,0 +1,5 @@
|
||||
//go:build race
|
||||
|
||||
package nistec_test
|
||||
|
||||
const raceEnabled = true
|
||||
174
extra_test.go
Normal file
174
extra_test.go
Normal file
@@ -0,0 +1,174 @@
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package nistec_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/elliptic"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"sources.truenas.cloud/code/nistec"
|
||||
)
|
||||
|
||||
type nistPointExtra[T any] interface {
|
||||
Bytes() []byte
|
||||
SetGenerator() T
|
||||
SetBytes([]byte) (T, error)
|
||||
Set(T) T
|
||||
Add(T, T) T
|
||||
Double(T) T
|
||||
Negate(T) T
|
||||
ScalarMult(T, []byte) (T, error)
|
||||
ScalarBaseMult([]byte) (T, error)
|
||||
IsInfinity() int
|
||||
Equal(T) int
|
||||
}
|
||||
|
||||
func TestNegate(t *testing.T) {
|
||||
t.Run("P224", func(t *testing.T) {
|
||||
testNegate(t, nistec.NewP224Point, elliptic.P224())
|
||||
})
|
||||
t.Run("P256", func(t *testing.T) {
|
||||
testNegate(t, nistec.NewP256Point, elliptic.P256())
|
||||
})
|
||||
t.Run("P384", func(t *testing.T) {
|
||||
testNegate(t, nistec.NewP384Point, elliptic.P384())
|
||||
})
|
||||
t.Run("P521", func(t *testing.T) {
|
||||
testNegate(t, nistec.NewP521Point, elliptic.P521())
|
||||
})
|
||||
}
|
||||
|
||||
func testNegate[P nistPointExtra[P]](t *testing.T, newPoint func() P, c elliptic.Curve) {
|
||||
p := newPoint().SetGenerator()
|
||||
p.Add(p, p) // make a test point with z != 1
|
||||
|
||||
p1 := newPoint().Negate(p)
|
||||
|
||||
minusOne := new(big.Int).Sub(c.Params().N, big.NewInt(1)).Bytes()
|
||||
p2, err := newPoint().ScalarMult(p, minusOne)
|
||||
fatalIfErr(t, err)
|
||||
if !bytes.Equal(p1.Bytes(), p2.Bytes()) {
|
||||
t.Error("-P != [-1]P")
|
||||
}
|
||||
|
||||
p.Negate(p)
|
||||
if !bytes.Equal(p.Bytes(), p1.Bytes()) {
|
||||
t.Error("-P (aliasing) != -P")
|
||||
}
|
||||
}
|
||||
|
||||
func TestEqual(t *testing.T) {
|
||||
t.Run("P224", func(t *testing.T) {
|
||||
testEqual(t, nistec.NewP224Point, elliptic.P224())
|
||||
})
|
||||
t.Run("P256", func(t *testing.T) {
|
||||
testEqual(t, nistec.NewP256Point, elliptic.P256())
|
||||
})
|
||||
t.Run("P384", func(t *testing.T) {
|
||||
testEqual(t, nistec.NewP384Point, elliptic.P384())
|
||||
})
|
||||
t.Run("P521", func(t *testing.T) {
|
||||
testEqual(t, nistec.NewP521Point, elliptic.P521())
|
||||
})
|
||||
}
|
||||
|
||||
func testEqual[P nistPointExtra[P]](t *testing.T, newPoint func() P, c elliptic.Curve) {
|
||||
inf := newPoint()
|
||||
g := newPoint().SetGenerator()
|
||||
g.Add(g, g)
|
||||
if inf.Equal(inf) != 1 {
|
||||
t.Error("inf != inf")
|
||||
}
|
||||
if g.Equal(g) != 1 {
|
||||
t.Error("G != G")
|
||||
}
|
||||
if inf.Equal(g) != 0 || g.Equal(inf) != 0 {
|
||||
t.Error("G == inf")
|
||||
}
|
||||
p1 := newPoint().Set(g)
|
||||
p2 := newPoint()
|
||||
p3 := newPoint()
|
||||
sc := make([]byte, (c.Params().N.BitLen()+7)>>3)
|
||||
for i := 1; i < 30; i++ {
|
||||
sc[len(sc)-1] = byte(i)
|
||||
_, err := p2.ScalarMult(g, sc)
|
||||
fatalIfErr(t, err)
|
||||
sc[len(sc)-1] = byte(i * 2)
|
||||
_, err = p3.ScalarBaseMult(sc)
|
||||
fatalIfErr(t, err)
|
||||
if p1.Equal(p2) != 1 || p2.Equal(p1) != 1 {
|
||||
t.Error("n*G != n*G (1)")
|
||||
}
|
||||
if p1.Equal(p3) != 1 || p3.Equal(p1) != 1 {
|
||||
t.Error("n*G != n*G (2)")
|
||||
}
|
||||
if p2.Equal(p3) != 1 || p3.Equal(p2) != 1 {
|
||||
t.Error("n*G != n*G (3)")
|
||||
}
|
||||
p1.Add(p1, g)
|
||||
if p1.Equal(g) != 0 || g.Equal(p1) != 0 {
|
||||
t.Error("n*G == G")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInfinity(t *testing.T) {
|
||||
t.Run("P224", func(t *testing.T) {
|
||||
testInfinity(t, nistec.NewP224Point, elliptic.P224())
|
||||
})
|
||||
t.Run("P256", func(t *testing.T) {
|
||||
testInfinity(t, nistec.NewP256Point, elliptic.P256())
|
||||
})
|
||||
t.Run("P384", func(t *testing.T) {
|
||||
testInfinity(t, nistec.NewP384Point, elliptic.P384())
|
||||
})
|
||||
t.Run("P521", func(t *testing.T) {
|
||||
testInfinity(t, nistec.NewP521Point, elliptic.P521())
|
||||
})
|
||||
}
|
||||
|
||||
func testInfinity[P nistPointExtra[P]](t *testing.T, newPoint func() P, c elliptic.Curve) {
|
||||
inf := newPoint()
|
||||
g := newPoint().SetGenerator()
|
||||
g.Add(g, g)
|
||||
if inf.IsInfinity() != 1 {
|
||||
t.Error("inf != inf")
|
||||
}
|
||||
if g.IsInfinity() != 0 {
|
||||
t.Error("G == inf")
|
||||
}
|
||||
p1 := newPoint().Set(g)
|
||||
p2 := newPoint()
|
||||
sc := make([]byte, (c.Params().N.BitLen()+7)>>3)
|
||||
for i := 1; i < 30; i++ {
|
||||
sc[len(sc)-1] = byte(i)
|
||||
_, err := p2.ScalarMult(g, sc)
|
||||
fatalIfErr(t, err)
|
||||
if p2.IsInfinity() != 0 {
|
||||
t.Error("n*G == inf (1)")
|
||||
}
|
||||
p2.Negate(p2)
|
||||
if p2.IsInfinity() != 0 {
|
||||
t.Error("n*G == inf (2)")
|
||||
}
|
||||
p2.Add(p2, p1)
|
||||
if p2.IsInfinity() != 1 {
|
||||
t.Error("n*G - n*G != inf")
|
||||
}
|
||||
p1.Add(p1, g)
|
||||
if p1.IsInfinity() != 0 {
|
||||
t.Error("n*G == inf (3)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func fatalIfErr(t *testing.T, err error) {
|
||||
t.Helper()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
628
generate.go
Normal file
628
generate.go
Normal file
@@ -0,0 +1,628 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build ignore
|
||||
|
||||
package main
|
||||
|
||||
// Running this generator requires addchain v0.4.0, which can be installed with
|
||||
//
|
||||
// go install github.com/mmcloughlin/addchain/cmd/addchain@v0.4.0
|
||||
//
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/elliptic"
|
||||
"fmt"
|
||||
"go/format"
|
||||
"io"
|
||||
"log"
|
||||
"math/big"
|
||||
"os"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
var curves = []struct {
|
||||
P string
|
||||
Element string
|
||||
Params *elliptic.CurveParams
|
||||
}{
|
||||
{
|
||||
P: "P224",
|
||||
Element: "fiat.P224Element",
|
||||
Params: elliptic.P224().Params(),
|
||||
},
|
||||
{
|
||||
P: "P384",
|
||||
Element: "fiat.P384Element",
|
||||
Params: elliptic.P384().Params(),
|
||||
},
|
||||
{
|
||||
P: "P521",
|
||||
Element: "fiat.P521Element",
|
||||
Params: elliptic.P521().Params(),
|
||||
},
|
||||
}
|
||||
|
||||
func main() {
|
||||
t := template.Must(template.New("tmplNISTEC").Parse(tmplNISTEC))
|
||||
|
||||
tmplAddchainFile, err := os.CreateTemp("", "addchain-template")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.Remove(tmplAddchainFile.Name())
|
||||
if _, err := io.WriteString(tmplAddchainFile, tmplAddchain); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := tmplAddchainFile.Close(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, c := range curves {
|
||||
p := strings.ToLower(c.P)
|
||||
elementLen := (c.Params.BitSize + 7) / 8
|
||||
B := fmt.Sprintf("%#v", c.Params.B.FillBytes(make([]byte, elementLen)))
|
||||
Gx := fmt.Sprintf("%#v", c.Params.Gx.FillBytes(make([]byte, elementLen)))
|
||||
Gy := fmt.Sprintf("%#v", c.Params.Gy.FillBytes(make([]byte, elementLen)))
|
||||
|
||||
log.Printf("Generating %s.go...", p)
|
||||
f, err := os.Create(p + ".go")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
buf := &bytes.Buffer{}
|
||||
if err := t.Execute(buf, map[string]interface{}{
|
||||
"P": c.P, "p": p, "B": B, "Gx": Gx, "Gy": Gy,
|
||||
"Element": c.Element, "ElementLen": elementLen,
|
||||
}); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
out, err := format.Source(buf.Bytes())
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if _, err := f.Write(out); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// If p = 3 mod 4, implement modular square root by exponentiation.
|
||||
mod4 := new(big.Int).Mod(c.Params.P, big.NewInt(4))
|
||||
if mod4.Cmp(big.NewInt(3)) != 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
exp := new(big.Int).Add(c.Params.P, big.NewInt(1))
|
||||
exp.Div(exp, big.NewInt(4))
|
||||
|
||||
tmp, err := os.CreateTemp("", "addchain-"+p)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.Remove(tmp.Name())
|
||||
cmd := exec.Command("addchain", "search", fmt.Sprintf("%d", exp))
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stdout = tmp
|
||||
if err := cmd.Run(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := tmp.Close(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
cmd = exec.Command("addchain", "gen", "-tmpl", tmplAddchainFile.Name(), tmp.Name())
|
||||
cmd.Stderr = os.Stderr
|
||||
out, err = cmd.Output()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
out = bytes.Replace(out, []byte("Element"), []byte(c.Element), -1)
|
||||
out = bytes.Replace(out, []byte("sqrtCandidate"), []byte(p+"SqrtCandidate"), -1)
|
||||
out, err = format.Source(out)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if _, err := f.Write(out); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const tmplNISTEC = `// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Code generated by generate.go. DO NOT EDIT.
|
||||
|
||||
package nistec
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"filippo.io/nistec/internal/fiat"
|
||||
)
|
||||
|
||||
// {{.p}}ElementLength is the length of an element of the base or scalar field,
|
||||
// which have the same bytes length for all NIST P curves.
|
||||
const {{.p}}ElementLength = {{ .ElementLen }}
|
||||
|
||||
// {{.P}}Point is a {{.P}} point. The zero value is NOT valid.
|
||||
type {{.P}}Point struct {
|
||||
// The point is represented in projective coordinates (X:Y:Z),
|
||||
// where x = X/Z and y = Y/Z.
|
||||
x, y, z *{{.Element}}
|
||||
}
|
||||
|
||||
// New{{.P}}Point returns a new {{.P}}Point representing the point at infinity point.
|
||||
func New{{.P}}Point() *{{.P}}Point {
|
||||
return &{{.P}}Point{
|
||||
x: new({{.Element}}),
|
||||
y: new({{.Element}}).One(),
|
||||
z: new({{.Element}}),
|
||||
}
|
||||
}
|
||||
|
||||
// SetGenerator sets p to the canonical generator and returns p.
|
||||
func (p *{{.P}}Point) SetGenerator() *{{.P}}Point {
|
||||
p.x.SetBytes({{.Gx}})
|
||||
p.y.SetBytes({{.Gy}})
|
||||
p.z.One()
|
||||
return p
|
||||
}
|
||||
|
||||
// Set sets p = q and returns p.
|
||||
func (p *{{.P}}Point) Set(q *{{.P}}Point) *{{.P}}Point {
|
||||
p.x.Set(q.x)
|
||||
p.y.Set(q.y)
|
||||
p.z.Set(q.z)
|
||||
return p
|
||||
}
|
||||
|
||||
// SetBytes sets p to the compressed, uncompressed, or infinity value encoded in
|
||||
// b, as specified in SEC 1, Version 2.0, Section 2.3.4. If the point is not on
|
||||
// the curve, it returns nil and an error, and the receiver is unchanged.
|
||||
// Otherwise, it returns p.
|
||||
func (p *{{.P}}Point) SetBytes(b []byte) (*{{.P}}Point, error) {
|
||||
switch {
|
||||
// Point at infinity.
|
||||
case len(b) == 1 && b[0] == 0:
|
||||
return p.Set(New{{.P}}Point()), nil
|
||||
|
||||
// Uncompressed form.
|
||||
case len(b) == 1+2*{{.p}}ElementLength && b[0] == 4:
|
||||
x, err := new({{.Element}}).SetBytes(b[1 : 1+{{.p}}ElementLength])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
y, err := new({{.Element}}).SetBytes(b[1+{{.p}}ElementLength:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := {{.p}}CheckOnCurve(x, y); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.x.Set(x)
|
||||
p.y.Set(y)
|
||||
p.z.One()
|
||||
return p, nil
|
||||
|
||||
// Compressed form.
|
||||
case len(b) == 1+{{.p}}ElementLength && (b[0] == 2 || b[0] == 3):
|
||||
x, err := new({{.Element}}).SetBytes(b[1:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// y² = x³ - 3x + b
|
||||
y := {{.p}}Polynomial(new({{.Element}}), x)
|
||||
if !{{.p}}Sqrt(y, y) {
|
||||
return nil, errors.New("invalid {{.P}} compressed point encoding")
|
||||
}
|
||||
|
||||
// Select the positive or negative root, as indicated by the least
|
||||
// significant bit, based on the encoding type byte.
|
||||
otherRoot := new({{.Element}})
|
||||
otherRoot.Sub(otherRoot, y)
|
||||
cond := y.Bytes()[{{.p}}ElementLength-1]&1 ^ b[0]&1
|
||||
y.Select(otherRoot, y, int(cond))
|
||||
|
||||
p.x.Set(x)
|
||||
p.y.Set(y)
|
||||
p.z.One()
|
||||
return p, nil
|
||||
|
||||
default:
|
||||
return nil, errors.New("invalid {{.P}} point encoding")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var _{{.p}}B *{{.Element}}
|
||||
var _{{.p}}BOnce sync.Once
|
||||
|
||||
func {{.p}}B() *{{.Element}} {
|
||||
_{{.p}}BOnce.Do(func() {
|
||||
_{{.p}}B, _ = new({{.Element}}).SetBytes({{.B}})
|
||||
})
|
||||
return _{{.p}}B
|
||||
}
|
||||
|
||||
// {{.p}}Polynomial sets y2 to x³ - 3x + b, and returns y2.
|
||||
func {{.p}}Polynomial(y2, x *{{.Element}}) *{{.Element}} {
|
||||
y2.Square(x)
|
||||
y2.Mul(y2, x)
|
||||
|
||||
threeX := new({{.Element}}).Add(x, x)
|
||||
threeX.Add(threeX, x)
|
||||
y2.Sub(y2, threeX)
|
||||
|
||||
return y2.Add(y2, {{.p}}B())
|
||||
}
|
||||
|
||||
func {{.p}}CheckOnCurve(x, y *{{.Element}}) error {
|
||||
// y² = x³ - 3x + b
|
||||
rhs := {{.p}}Polynomial(new({{.Element}}), x)
|
||||
lhs := new({{.Element}}).Square(y)
|
||||
if rhs.Equal(lhs) != 1 {
|
||||
return errors.New("{{.P}} point not on curve")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Bytes returns the uncompressed or infinity encoding of p, as specified in
|
||||
// SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the point at
|
||||
// infinity is shorter than all other encodings.
|
||||
func (p *{{.P}}Point) Bytes() []byte {
|
||||
// This function is outlined to make the allocations inline in the caller
|
||||
// rather than happen on the heap.
|
||||
var out [1+2*{{.p}}ElementLength]byte
|
||||
return p.bytes(&out)
|
||||
}
|
||||
|
||||
func (p *{{.P}}Point) bytes(out *[1+2*{{.p}}ElementLength]byte) []byte {
|
||||
if p.z.IsZero() == 1 {
|
||||
return append(out[:0], 0)
|
||||
}
|
||||
|
||||
zinv := new({{.Element}}).Invert(p.z)
|
||||
x := new({{.Element}}).Mul(p.x, zinv)
|
||||
y := new({{.Element}}).Mul(p.y, zinv)
|
||||
|
||||
buf := append(out[:0], 4)
|
||||
buf = append(buf, x.Bytes()...)
|
||||
buf = append(buf, y.Bytes()...)
|
||||
return buf
|
||||
}
|
||||
|
||||
// BytesX returns the encoding of the x-coordinate of p, as specified in SEC 1,
|
||||
// Version 2.0, Section 2.3.5, or an error if p is the point at infinity.
|
||||
func (p *{{.P}}Point) BytesX() ([]byte, error) {
|
||||
// This function is outlined to make the allocations inline in the caller
|
||||
// rather than happen on the heap.
|
||||
var out [{{.p}}ElementLength]byte
|
||||
return p.bytesX(&out)
|
||||
}
|
||||
|
||||
func (p *{{.P}}Point) bytesX(out *[{{.p}}ElementLength]byte) ([]byte, error) {
|
||||
if p.z.IsZero() == 1 {
|
||||
return nil, errors.New("{{.P}} point is the point at infinity")
|
||||
}
|
||||
|
||||
zinv := new({{.Element}}).Invert(p.z)
|
||||
x := new({{.Element}}).Mul(p.x, zinv)
|
||||
|
||||
return append(out[:0], x.Bytes()...), nil
|
||||
}
|
||||
|
||||
// BytesCompressed returns the compressed or infinity encoding of p, as
|
||||
// specified in SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the
|
||||
// point at infinity is shorter than all other encodings.
|
||||
func (p *{{.P}}Point) BytesCompressed() []byte {
|
||||
// This function is outlined to make the allocations inline in the caller
|
||||
// rather than happen on the heap.
|
||||
var out [1 + {{.p}}ElementLength]byte
|
||||
return p.bytesCompressed(&out)
|
||||
}
|
||||
|
||||
func (p *{{.P}}Point) bytesCompressed(out *[1 + {{.p}}ElementLength]byte) []byte {
|
||||
if p.z.IsZero() == 1 {
|
||||
return append(out[:0], 0)
|
||||
}
|
||||
|
||||
zinv := new({{.Element}}).Invert(p.z)
|
||||
x := new({{.Element}}).Mul(p.x, zinv)
|
||||
y := new({{.Element}}).Mul(p.y, zinv)
|
||||
|
||||
// Encode the sign of the y coordinate (indicated by the least significant
|
||||
// bit) as the encoding type (2 or 3).
|
||||
buf := append(out[:0], 2)
|
||||
buf[0] |= y.Bytes()[{{.p}}ElementLength-1] & 1
|
||||
buf = append(buf, x.Bytes()...)
|
||||
return buf
|
||||
}
|
||||
|
||||
// Add sets q = p1 + p2, and returns q. The points may overlap.
|
||||
func (q *{{.P}}Point) Add(p1, p2 *{{.P}}Point) *{{.P}}Point {
|
||||
// Complete addition formula for a = -3 from "Complete addition formulas for
|
||||
// prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2.
|
||||
|
||||
t0 := new({{.Element}}).Mul(p1.x, p2.x) // t0 := X1 * X2
|
||||
t1 := new({{.Element}}).Mul(p1.y, p2.y) // t1 := Y1 * Y2
|
||||
t2 := new({{.Element}}).Mul(p1.z, p2.z) // t2 := Z1 * Z2
|
||||
t3 := new({{.Element}}).Add(p1.x, p1.y) // t3 := X1 + Y1
|
||||
t4 := new({{.Element}}).Add(p2.x, p2.y) // t4 := X2 + Y2
|
||||
t3.Mul(t3, t4) // t3 := t3 * t4
|
||||
t4.Add(t0, t1) // t4 := t0 + t1
|
||||
t3.Sub(t3, t4) // t3 := t3 - t4
|
||||
t4.Add(p1.y, p1.z) // t4 := Y1 + Z1
|
||||
x3 := new({{.Element}}).Add(p2.y, p2.z) // X3 := Y2 + Z2
|
||||
t4.Mul(t4, x3) // t4 := t4 * X3
|
||||
x3.Add(t1, t2) // X3 := t1 + t2
|
||||
t4.Sub(t4, x3) // t4 := t4 - X3
|
||||
x3.Add(p1.x, p1.z) // X3 := X1 + Z1
|
||||
y3 := new({{.Element}}).Add(p2.x, p2.z) // Y3 := X2 + Z2
|
||||
x3.Mul(x3, y3) // X3 := X3 * Y3
|
||||
y3.Add(t0, t2) // Y3 := t0 + t2
|
||||
y3.Sub(x3, y3) // Y3 := X3 - Y3
|
||||
z3 := new({{.Element}}).Mul({{.p}}B(), t2) // Z3 := b * t2
|
||||
x3.Sub(y3, z3) // X3 := Y3 - Z3
|
||||
z3.Add(x3, x3) // Z3 := X3 + X3
|
||||
x3.Add(x3, z3) // X3 := X3 + Z3
|
||||
z3.Sub(t1, x3) // Z3 := t1 - X3
|
||||
x3.Add(t1, x3) // X3 := t1 + X3
|
||||
y3.Mul({{.p}}B(), y3) // Y3 := b * Y3
|
||||
t1.Add(t2, t2) // t1 := t2 + t2
|
||||
t2.Add(t1, t2) // t2 := t1 + t2
|
||||
y3.Sub(y3, t2) // Y3 := Y3 - t2
|
||||
y3.Sub(y3, t0) // Y3 := Y3 - t0
|
||||
t1.Add(y3, y3) // t1 := Y3 + Y3
|
||||
y3.Add(t1, y3) // Y3 := t1 + Y3
|
||||
t1.Add(t0, t0) // t1 := t0 + t0
|
||||
t0.Add(t1, t0) // t0 := t1 + t0
|
||||
t0.Sub(t0, t2) // t0 := t0 - t2
|
||||
t1.Mul(t4, y3) // t1 := t4 * Y3
|
||||
t2.Mul(t0, y3) // t2 := t0 * Y3
|
||||
y3.Mul(x3, z3) // Y3 := X3 * Z3
|
||||
y3.Add(y3, t2) // Y3 := Y3 + t2
|
||||
x3.Mul(t3, x3) // X3 := t3 * X3
|
||||
x3.Sub(x3, t1) // X3 := X3 - t1
|
||||
z3.Mul(t4, z3) // Z3 := t4 * Z3
|
||||
t1.Mul(t3, t0) // t1 := t3 * t0
|
||||
z3.Add(z3, t1) // Z3 := Z3 + t1
|
||||
|
||||
q.x.Set(x3)
|
||||
q.y.Set(y3)
|
||||
q.z.Set(z3)
|
||||
return q
|
||||
}
|
||||
|
||||
// Double sets q = p + p, and returns q. The points may overlap.
|
||||
func (q *{{.P}}Point) Double(p *{{.P}}Point) *{{.P}}Point {
|
||||
// Complete addition formula for a = -3 from "Complete addition formulas for
|
||||
// prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2.
|
||||
|
||||
t0 := new({{.Element}}).Square(p.x) // t0 := X ^ 2
|
||||
t1 := new({{.Element}}).Square(p.y) // t1 := Y ^ 2
|
||||
t2 := new({{.Element}}).Square(p.z) // t2 := Z ^ 2
|
||||
t3 := new({{.Element}}).Mul(p.x, p.y) // t3 := X * Y
|
||||
t3.Add(t3, t3) // t3 := t3 + t3
|
||||
z3 := new({{.Element}}).Mul(p.x, p.z) // Z3 := X * Z
|
||||
z3.Add(z3, z3) // Z3 := Z3 + Z3
|
||||
y3 := new({{.Element}}).Mul({{.p}}B(), t2) // Y3 := b * t2
|
||||
y3.Sub(y3, z3) // Y3 := Y3 - Z3
|
||||
x3 := new({{.Element}}).Add(y3, y3) // X3 := Y3 + Y3
|
||||
y3.Add(x3, y3) // Y3 := X3 + Y3
|
||||
x3.Sub(t1, y3) // X3 := t1 - Y3
|
||||
y3.Add(t1, y3) // Y3 := t1 + Y3
|
||||
y3.Mul(x3, y3) // Y3 := X3 * Y3
|
||||
x3.Mul(x3, t3) // X3 := X3 * t3
|
||||
t3.Add(t2, t2) // t3 := t2 + t2
|
||||
t2.Add(t2, t3) // t2 := t2 + t3
|
||||
z3.Mul({{.p}}B(), z3) // Z3 := b * Z3
|
||||
z3.Sub(z3, t2) // Z3 := Z3 - t2
|
||||
z3.Sub(z3, t0) // Z3 := Z3 - t0
|
||||
t3.Add(z3, z3) // t3 := Z3 + Z3
|
||||
z3.Add(z3, t3) // Z3 := Z3 + t3
|
||||
t3.Add(t0, t0) // t3 := t0 + t0
|
||||
t0.Add(t3, t0) // t0 := t3 + t0
|
||||
t0.Sub(t0, t2) // t0 := t0 - t2
|
||||
t0.Mul(t0, z3) // t0 := t0 * Z3
|
||||
y3.Add(y3, t0) // Y3 := Y3 + t0
|
||||
t0.Mul(p.y, p.z) // t0 := Y * Z
|
||||
t0.Add(t0, t0) // t0 := t0 + t0
|
||||
z3.Mul(t0, z3) // Z3 := t0 * Z3
|
||||
x3.Sub(x3, z3) // X3 := X3 - Z3
|
||||
z3.Mul(t0, t1) // Z3 := t0 * t1
|
||||
z3.Add(z3, z3) // Z3 := Z3 + Z3
|
||||
z3.Add(z3, z3) // Z3 := Z3 + Z3
|
||||
|
||||
q.x.Set(x3)
|
||||
q.y.Set(y3)
|
||||
q.z.Set(z3)
|
||||
return q
|
||||
}
|
||||
|
||||
// Select sets q to p1 if cond == 1, and to p2 if cond == 0.
|
||||
func (q *{{.P}}Point) Select(p1, p2 *{{.P}}Point, cond int) *{{.P}}Point {
|
||||
q.x.Select(p1.x, p2.x, cond)
|
||||
q.y.Select(p1.y, p2.y, cond)
|
||||
q.z.Select(p1.z, p2.z, cond)
|
||||
return q
|
||||
}
|
||||
|
||||
// A {{.p}}Table holds the first 15 multiples of a point at offset -1, so [1]P
|
||||
// is at table[0], [15]P is at table[14], and [0]P is implicitly the identity
|
||||
// point.
|
||||
type {{.p}}Table [15]*{{.P}}Point
|
||||
|
||||
// Select selects the n-th multiple of the table base point into p. It works in
|
||||
// constant time by iterating over every entry of the table. n must be in [0, 15].
|
||||
func (table *{{.p}}Table) Select(p *{{.P}}Point, n uint8) {
|
||||
if n >= 16 {
|
||||
panic("nistec: internal error: {{.p}}Table called with out-of-bounds value")
|
||||
}
|
||||
p.Set(New{{.P}}Point())
|
||||
for i := uint8(1); i < 16; i++ {
|
||||
cond := subtle.ConstantTimeByteEq(i, n)
|
||||
p.Select(table[i-1], p, cond)
|
||||
}
|
||||
}
|
||||
|
||||
// ScalarMult sets p = scalar * q, and returns p.
|
||||
func (p *{{.P}}Point) ScalarMult(q *{{.P}}Point, scalar []byte) (*{{.P}}Point, error) {
|
||||
// Compute a {{.p}}Table for the base point q. The explicit New{{.P}}Point
|
||||
// calls get inlined, letting the allocations live on the stack.
|
||||
var table = {{.p}}Table{New{{.P}}Point(), New{{.P}}Point(), New{{.P}}Point(),
|
||||
New{{.P}}Point(), New{{.P}}Point(), New{{.P}}Point(), New{{.P}}Point(),
|
||||
New{{.P}}Point(), New{{.P}}Point(), New{{.P}}Point(), New{{.P}}Point(),
|
||||
New{{.P}}Point(), New{{.P}}Point(), New{{.P}}Point(), New{{.P}}Point()}
|
||||
table[0].Set(q)
|
||||
for i := 1; i < 15; i += 2 {
|
||||
table[i].Double(table[i/2])
|
||||
table[i+1].Add(table[i], q)
|
||||
}
|
||||
|
||||
// Instead of doing the classic double-and-add chain, we do it with a
|
||||
// four-bit window: we double four times, and then add [0-15]P.
|
||||
t := New{{.P}}Point()
|
||||
p.Set(New{{.P}}Point())
|
||||
for i, byte := range scalar {
|
||||
// No need to double on the first iteration, as p is the identity at
|
||||
// this point, and [N]∞ = ∞.
|
||||
if i != 0 {
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
}
|
||||
|
||||
windowValue := byte >> 4
|
||||
table.Select(t, windowValue)
|
||||
p.Add(p, t)
|
||||
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
|
||||
windowValue = byte & 0b1111
|
||||
table.Select(t, windowValue)
|
||||
p.Add(p, t)
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
var {{.p}}GeneratorTable *[{{.p}}ElementLength * 2]{{.p}}Table
|
||||
var {{.p}}GeneratorTableOnce sync.Once
|
||||
|
||||
// generatorTable returns a sequence of {{.p}}Tables. The first table contains
|
||||
// multiples of G. Each successive table is the previous table doubled four
|
||||
// times.
|
||||
func (p *{{.P}}Point) generatorTable() *[{{.p}}ElementLength * 2]{{.p}}Table {
|
||||
{{.p}}GeneratorTableOnce.Do(func() {
|
||||
{{.p}}GeneratorTable = new([{{.p}}ElementLength * 2]{{.p}}Table)
|
||||
base := New{{.P}}Point().SetGenerator()
|
||||
for i := 0; i < {{.p}}ElementLength*2; i++ {
|
||||
{{.p}}GeneratorTable[i][0] = New{{.P}}Point().Set(base)
|
||||
for j := 1; j < 15; j++ {
|
||||
{{.p}}GeneratorTable[i][j] = New{{.P}}Point().Add({{.p}}GeneratorTable[i][j-1], base)
|
||||
}
|
||||
base.Double(base)
|
||||
base.Double(base)
|
||||
base.Double(base)
|
||||
base.Double(base)
|
||||
}
|
||||
})
|
||||
return {{.p}}GeneratorTable
|
||||
}
|
||||
|
||||
// ScalarBaseMult sets p = scalar * B, where B is the canonical generator, and
|
||||
// returns p.
|
||||
func (p *{{.P}}Point) ScalarBaseMult(scalar []byte) (*{{.P}}Point, error) {
|
||||
if len(scalar) != {{.p}}ElementLength {
|
||||
return nil, errors.New("invalid scalar length")
|
||||
}
|
||||
tables := p.generatorTable()
|
||||
|
||||
// This is also a scalar multiplication with a four-bit window like in
|
||||
// ScalarMult, but in this case the doublings are precomputed. The value
|
||||
// [windowValue]G added at iteration k would normally get doubled
|
||||
// (totIterations-k)×4 times, but with a larger precomputation we can
|
||||
// instead add [2^((totIterations-k)×4)][windowValue]G and avoid the
|
||||
// doublings between iterations.
|
||||
t := New{{.P}}Point()
|
||||
p.Set(New{{.P}}Point())
|
||||
tableIndex := len(tables) - 1
|
||||
for _, byte := range scalar {
|
||||
windowValue := byte >> 4
|
||||
tables[tableIndex].Select(t, windowValue)
|
||||
p.Add(p, t)
|
||||
tableIndex--
|
||||
|
||||
windowValue = byte & 0b1111
|
||||
tables[tableIndex].Select(t, windowValue)
|
||||
p.Add(p, t)
|
||||
tableIndex--
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// {{.p}}Sqrt sets e to a square root of x. If x is not a square, {{.p}}Sqrt returns
|
||||
// false and e is unchanged. e and x can overlap.
|
||||
func {{.p}}Sqrt(e, x *{{ .Element }}) (isSquare bool) {
|
||||
candidate := new({{ .Element }})
|
||||
{{.p}}SqrtCandidate(candidate, x)
|
||||
square := new({{ .Element }}).Square(candidate)
|
||||
if square.Equal(x) != 1 {
|
||||
return false
|
||||
}
|
||||
e.Set(candidate)
|
||||
return true
|
||||
}
|
||||
`
|
||||
|
||||
const tmplAddchain = `
|
||||
// sqrtCandidate sets z to a square root candidate for x. z and x must not overlap.
|
||||
func sqrtCandidate(z, x *Element) {
|
||||
// Since p = 3 mod 4, exponentiation by (p + 1) / 4 yields a square root candidate.
|
||||
//
|
||||
// The sequence of {{ .Ops.Adds }} multiplications and {{ .Ops.Doubles }} squarings is derived from the
|
||||
// following addition chain generated with {{ .Meta.Module }} {{ .Meta.ReleaseTag }}.
|
||||
//
|
||||
{{- range lines (format .Script) }}
|
||||
// {{ . }}
|
||||
{{- end }}
|
||||
//
|
||||
|
||||
{{- range .Program.Temporaries }}
|
||||
var {{ . }} = new(Element)
|
||||
{{- end }}
|
||||
{{ range $i := .Program.Instructions -}}
|
||||
{{- with add $i.Op }}
|
||||
{{ $i.Output }}.Mul({{ .X }}, {{ .Y }})
|
||||
{{- end -}}
|
||||
|
||||
{{- with double $i.Op }}
|
||||
{{ $i.Output }}.Square({{ .X }})
|
||||
{{- end -}}
|
||||
|
||||
{{- with shift $i.Op -}}
|
||||
{{- $first := 0 -}}
|
||||
{{- if ne $i.Output.Identifier .X.Identifier }}
|
||||
{{ $i.Output }}.Square({{ .X }})
|
||||
{{- $first = 1 -}}
|
||||
{{- end }}
|
||||
for s := {{ $first }}; s < {{ .S }}; s++ {
|
||||
{{ $i.Output }}.Square({{ $i.Output }})
|
||||
}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
}
|
||||
`
|
||||
5
go.mod
Normal file
5
go.mod
Normal file
@@ -0,0 +1,5 @@
|
||||
module sources.truenas.cloud/code/nistec
|
||||
|
||||
go 1.24.0
|
||||
|
||||
require golang.org/x/sys v0.36.0
|
||||
2
go.sum
Normal file
2
go.sum
Normal file
@@ -0,0 +1,2 @@
|
||||
golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k=
|
||||
golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||
149
internal/byteorder/byteorder.go
Normal file
149
internal/byteorder/byteorder.go
Normal file
@@ -0,0 +1,149 @@
|
||||
// Copyright 2024 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package byteorder provides functions for decoding and encoding
|
||||
// little and big endian integer types from/to byte slices.
|
||||
package byteorder
|
||||
|
||||
func LEUint16(b []byte) uint16 {
|
||||
_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint16(b[0]) | uint16(b[1])<<8
|
||||
}
|
||||
|
||||
func LEPutUint16(b []byte, v uint16) {
|
||||
_ = b[1] // early bounds check to guarantee safety of writes below
|
||||
b[0] = byte(v)
|
||||
b[1] = byte(v >> 8)
|
||||
}
|
||||
|
||||
func LEAppendUint16(b []byte, v uint16) []byte {
|
||||
return append(b,
|
||||
byte(v),
|
||||
byte(v>>8),
|
||||
)
|
||||
}
|
||||
|
||||
func LEUint32(b []byte) uint32 {
|
||||
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint32(b[0]) | uint32(b[1])<<8 | uint32(b[2])<<16 | uint32(b[3])<<24
|
||||
}
|
||||
|
||||
func LEPutUint32(b []byte, v uint32) {
|
||||
_ = b[3] // early bounds check to guarantee safety of writes below
|
||||
b[0] = byte(v)
|
||||
b[1] = byte(v >> 8)
|
||||
b[2] = byte(v >> 16)
|
||||
b[3] = byte(v >> 24)
|
||||
}
|
||||
|
||||
func LEAppendUint32(b []byte, v uint32) []byte {
|
||||
return append(b,
|
||||
byte(v),
|
||||
byte(v>>8),
|
||||
byte(v>>16),
|
||||
byte(v>>24),
|
||||
)
|
||||
}
|
||||
|
||||
func LEUint64(b []byte) uint64 {
|
||||
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint64(b[0]) | uint64(b[1])<<8 | uint64(b[2])<<16 | uint64(b[3])<<24 |
|
||||
uint64(b[4])<<32 | uint64(b[5])<<40 | uint64(b[6])<<48 | uint64(b[7])<<56
|
||||
}
|
||||
|
||||
func LEPutUint64(b []byte, v uint64) {
|
||||
_ = b[7] // early bounds check to guarantee safety of writes below
|
||||
b[0] = byte(v)
|
||||
b[1] = byte(v >> 8)
|
||||
b[2] = byte(v >> 16)
|
||||
b[3] = byte(v >> 24)
|
||||
b[4] = byte(v >> 32)
|
||||
b[5] = byte(v >> 40)
|
||||
b[6] = byte(v >> 48)
|
||||
b[7] = byte(v >> 56)
|
||||
}
|
||||
|
||||
func LEAppendUint64(b []byte, v uint64) []byte {
|
||||
return append(b,
|
||||
byte(v),
|
||||
byte(v>>8),
|
||||
byte(v>>16),
|
||||
byte(v>>24),
|
||||
byte(v>>32),
|
||||
byte(v>>40),
|
||||
byte(v>>48),
|
||||
byte(v>>56),
|
||||
)
|
||||
}
|
||||
|
||||
func BEUint16(b []byte) uint16 {
|
||||
_ = b[1] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint16(b[1]) | uint16(b[0])<<8
|
||||
}
|
||||
|
||||
func BEPutUint16(b []byte, v uint16) {
|
||||
_ = b[1] // early bounds check to guarantee safety of writes below
|
||||
b[0] = byte(v >> 8)
|
||||
b[1] = byte(v)
|
||||
}
|
||||
|
||||
func BEAppendUint16(b []byte, v uint16) []byte {
|
||||
return append(b,
|
||||
byte(v>>8),
|
||||
byte(v),
|
||||
)
|
||||
}
|
||||
|
||||
func BEUint32(b []byte) uint32 {
|
||||
_ = b[3] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
|
||||
}
|
||||
|
||||
func BEPutUint32(b []byte, v uint32) {
|
||||
_ = b[3] // early bounds check to guarantee safety of writes below
|
||||
b[0] = byte(v >> 24)
|
||||
b[1] = byte(v >> 16)
|
||||
b[2] = byte(v >> 8)
|
||||
b[3] = byte(v)
|
||||
}
|
||||
|
||||
func BEAppendUint32(b []byte, v uint32) []byte {
|
||||
return append(b,
|
||||
byte(v>>24),
|
||||
byte(v>>16),
|
||||
byte(v>>8),
|
||||
byte(v),
|
||||
)
|
||||
}
|
||||
|
||||
func BEUint64(b []byte) uint64 {
|
||||
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
|
||||
return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
|
||||
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
|
||||
}
|
||||
|
||||
func BEPutUint64(b []byte, v uint64) {
|
||||
_ = b[7] // early bounds check to guarantee safety of writes below
|
||||
b[0] = byte(v >> 56)
|
||||
b[1] = byte(v >> 48)
|
||||
b[2] = byte(v >> 40)
|
||||
b[3] = byte(v >> 32)
|
||||
b[4] = byte(v >> 24)
|
||||
b[5] = byte(v >> 16)
|
||||
b[6] = byte(v >> 8)
|
||||
b[7] = byte(v)
|
||||
}
|
||||
|
||||
func BEAppendUint64(b []byte, v uint64) []byte {
|
||||
return append(b,
|
||||
byte(v>>56),
|
||||
byte(v>>48),
|
||||
byte(v>>40),
|
||||
byte(v>>32),
|
||||
byte(v>>24),
|
||||
byte(v>>16),
|
||||
byte(v>>8),
|
||||
byte(v),
|
||||
)
|
||||
}
|
||||
12
internal/fiat/Dockerfile
Normal file
12
internal/fiat/Dockerfile
Normal file
@@ -0,0 +1,12 @@
|
||||
# Copyright 2021 The Go Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
FROM coqorg/coq:8.13.2
|
||||
|
||||
RUN git clone https://github.com/mit-plv/fiat-crypto && cd fiat-crypto && \
|
||||
git checkout 23d2dbc4ab897d14bde4404f70cd6991635f9c01 && \
|
||||
git submodule update --init --recursive
|
||||
RUN cd fiat-crypto && eval $(opam env) && make -j4 standalone-ocaml SKIP_BEDROCK2=1
|
||||
|
||||
ENV PATH /home/coq/fiat-crypto/src/ExtractionOCaml:$PATH
|
||||
34
internal/fiat/README
Normal file
34
internal/fiat/README
Normal file
@@ -0,0 +1,34 @@
|
||||
The code in this package was autogenerated by the fiat-crypto project
|
||||
at version v0.0.9 from a formally verified model, and by the addchain
|
||||
project at a recent tip version.
|
||||
|
||||
docker build -t fiat-crypto:v0.0.9 .
|
||||
go install github.com/mmcloughlin/addchain/cmd/addchain@v0.3.1-0.20211027081849-6a7d3decbe08
|
||||
go run generate.go
|
||||
|
||||
fiat-crypto code comes under the following license.
|
||||
|
||||
Copyright (c) 2015-2020 The fiat-crypto Authors. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design,
|
||||
Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The authors are listed at
|
||||
|
||||
https://github.com/mit-plv/fiat-crypto/blob/master/AUTHORS
|
||||
65
internal/fiat/fiat_test.go
Normal file
65
internal/fiat/fiat_test.go
Normal file
@@ -0,0 +1,65 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package fiat_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"sources.truenas.cloud/code/nistec/internal/fiat"
|
||||
)
|
||||
|
||||
func BenchmarkMul(b *testing.B) {
|
||||
b.Run("P224", func(b *testing.B) {
|
||||
v := new(fiat.P224Element).One()
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
v.Mul(v, v)
|
||||
}
|
||||
})
|
||||
b.Run("P384", func(b *testing.B) {
|
||||
v := new(fiat.P384Element).One()
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
v.Mul(v, v)
|
||||
}
|
||||
})
|
||||
b.Run("P521", func(b *testing.B) {
|
||||
v := new(fiat.P521Element).One()
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
v.Mul(v, v)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkSquare(b *testing.B) {
|
||||
b.Run("P224", func(b *testing.B) {
|
||||
v := new(fiat.P224Element).One()
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
v.Square(v)
|
||||
}
|
||||
})
|
||||
b.Run("P384", func(b *testing.B) {
|
||||
v := new(fiat.P384Element).One()
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
v.Square(v)
|
||||
}
|
||||
})
|
||||
b.Run("P521", func(b *testing.B) {
|
||||
v := new(fiat.P521Element).One()
|
||||
b.ReportAllocs()
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
v.Square(v)
|
||||
}
|
||||
})
|
||||
}
|
||||
325
internal/fiat/generate.go
Normal file
325
internal/fiat/generate.go
Normal file
@@ -0,0 +1,325 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"go/format"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
var curves = []struct {
|
||||
Element string
|
||||
Prime string
|
||||
Prefix string
|
||||
FiatType string
|
||||
BytesLen int
|
||||
}{
|
||||
{
|
||||
Element: "P224Element",
|
||||
Prime: "2^224 - 2^96 + 1",
|
||||
Prefix: "p224",
|
||||
FiatType: "[4]uint64",
|
||||
BytesLen: 28,
|
||||
},
|
||||
// The P-256 fiat implementation is used only on 32-bit architectures, but
|
||||
// the uint32 fiat code is for some reason slower than the uint64 one. That
|
||||
// suggests there is a wide margin for improvement.
|
||||
{
|
||||
Element: "P256Element",
|
||||
Prime: "2^256 - 2^224 + 2^192 + 2^96 - 1",
|
||||
Prefix: "p256",
|
||||
FiatType: "[4]uint64",
|
||||
BytesLen: 32,
|
||||
},
|
||||
{
|
||||
Element: "P384Element",
|
||||
Prime: "2^384 - 2^128 - 2^96 + 2^32 - 1",
|
||||
Prefix: "p384",
|
||||
FiatType: "[6]uint64",
|
||||
BytesLen: 48,
|
||||
},
|
||||
// Note that unsaturated_solinas would be about 2x faster than
|
||||
// word_by_word_montgomery for P-521, but this curve is used rarely enough
|
||||
// that it's not worth carrying unsaturated_solinas support for it.
|
||||
{
|
||||
Element: "P521Element",
|
||||
Prime: "2^521 - 1",
|
||||
Prefix: "p521",
|
||||
FiatType: "[9]uint64",
|
||||
BytesLen: 66,
|
||||
},
|
||||
}
|
||||
|
||||
func main() {
|
||||
t := template.Must(template.New("montgomery").Parse(tmplWrapper))
|
||||
|
||||
tmplAddchainFile, err := os.CreateTemp("", "addchain-template")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.Remove(tmplAddchainFile.Name())
|
||||
if _, err := io.WriteString(tmplAddchainFile, tmplAddchain); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := tmplAddchainFile.Close(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
for _, c := range curves {
|
||||
log.Printf("Generating %s.go...", c.Prefix)
|
||||
f, err := os.Create(c.Prefix + ".go")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := t.Execute(f, c); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Printf("Generating %s_fiat64.go...", c.Prefix)
|
||||
cmd := exec.Command("docker", "run", "--rm", "--entrypoint", "word_by_word_montgomery",
|
||||
"fiat-crypto:v0.0.9", "--lang", "Go", "--no-wide-int", "--cmovznz-by-mul",
|
||||
"--relax-primitive-carry-to-bitwidth", "32,64", "--internal-static",
|
||||
"--public-function-case", "camelCase", "--public-type-case", "camelCase",
|
||||
"--private-function-case", "camelCase", "--private-type-case", "camelCase",
|
||||
"--doc-text-before-function-name", "", "--doc-newline-before-package-declaration",
|
||||
"--doc-prepend-header", "Code generated by Fiat Cryptography. DO NOT EDIT.",
|
||||
"--package-name", "fiat", "--no-prefix-fiat", c.Prefix, "64", c.Prime,
|
||||
"mul", "square", "add", "sub", "one", "from_montgomery", "to_montgomery",
|
||||
"selectznz", "to_bytes", "from_bytes")
|
||||
cmd.Stderr = os.Stderr
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
out, err = format.Source(out)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(c.Prefix+"_fiat64.go", out, 0644); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.Printf("Generating %s_invert.go...", c.Prefix)
|
||||
f, err = os.CreateTemp("", "addchain-"+c.Prefix)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer os.Remove(f.Name())
|
||||
cmd = exec.Command("addchain", "search", c.Prime+" - 2")
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Stdout = f
|
||||
if err := cmd.Run(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := f.Close(); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
cmd = exec.Command("addchain", "gen", "-tmpl", tmplAddchainFile.Name(), f.Name())
|
||||
cmd.Stderr = os.Stderr
|
||||
out, err = cmd.Output()
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
out = bytes.Replace(out, []byte("Element"), []byte(c.Element), -1)
|
||||
out, err = format.Source(out)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(c.Prefix+"_invert.go", out, 0644); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const tmplWrapper = `// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Code generated by generate.go. DO NOT EDIT.
|
||||
|
||||
package fiat
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// {{ .Element }} is an integer modulo {{ .Prime }}.
|
||||
//
|
||||
// The zero value is a valid zero element.
|
||||
type {{ .Element }} struct {
|
||||
// Values are represented internally always in the Montgomery domain, and
|
||||
// converted in Bytes and SetBytes.
|
||||
x {{ .Prefix }}MontgomeryDomainFieldElement
|
||||
}
|
||||
|
||||
const {{ .Prefix }}ElementLen = {{ .BytesLen }}
|
||||
|
||||
type {{ .Prefix }}UntypedFieldElement = {{ .FiatType }}
|
||||
|
||||
// One sets e = 1, and returns e.
|
||||
func (e *{{ .Element }}) One() *{{ .Element }} {
|
||||
{{ .Prefix }}SetOne(&e.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Equal returns 1 if e == t, and zero otherwise.
|
||||
func (e *{{ .Element }}) Equal(t *{{ .Element }}) int {
|
||||
eBytes := e.Bytes()
|
||||
tBytes := t.Bytes()
|
||||
return subtle.ConstantTimeCompare(eBytes, tBytes)
|
||||
}
|
||||
|
||||
// IsZero returns 1 if e == 0, and zero otherwise.
|
||||
func (e *{{ .Element }}) IsZero() int {
|
||||
zero := make([]byte, {{ .Prefix }}ElementLen)
|
||||
eBytes := e.Bytes()
|
||||
return subtle.ConstantTimeCompare(eBytes, zero)
|
||||
}
|
||||
|
||||
// Set sets e = t, and returns e.
|
||||
func (e *{{ .Element }}) Set(t *{{ .Element }}) *{{ .Element }} {
|
||||
e.x = t.x
|
||||
return e
|
||||
}
|
||||
|
||||
// Bytes returns the {{ .BytesLen }}-byte big-endian encoding of e.
|
||||
func (e *{{ .Element }}) Bytes() []byte {
|
||||
// This function is outlined to make the allocations inline in the caller
|
||||
// rather than happen on the heap.
|
||||
var out [{{ .Prefix }}ElementLen]byte
|
||||
return e.bytes(&out)
|
||||
}
|
||||
|
||||
func (e *{{ .Element }}) bytes(out *[{{ .Prefix }}ElementLen]byte) []byte {
|
||||
var tmp {{ .Prefix }}NonMontgomeryDomainFieldElement
|
||||
{{ .Prefix }}FromMontgomery(&tmp, &e.x)
|
||||
{{ .Prefix }}ToBytes(out, (*{{ .Prefix }}UntypedFieldElement)(&tmp))
|
||||
{{ .Prefix }}InvertEndianness(out[:])
|
||||
return out[:]
|
||||
}
|
||||
|
||||
// SetBytes sets e = v, where v is a big-endian {{ .BytesLen }}-byte encoding, and returns e.
|
||||
// If v is not {{ .BytesLen }} bytes or it encodes a value higher than {{ .Prime }},
|
||||
// SetBytes returns nil and an error, and e is unchanged.
|
||||
func (e *{{ .Element }}) SetBytes(v []byte) (*{{ .Element }}, error) {
|
||||
if len(v) != {{ .Prefix }}ElementLen {
|
||||
return nil, errors.New("invalid {{ .Element }} encoding")
|
||||
}
|
||||
|
||||
// Check for non-canonical encodings (p + k, 2p + k, etc.) by comparing to
|
||||
// the encoding of -1 mod p, so p - 1, the highest canonical encoding.
|
||||
var minusOneEncoding = new({{ .Element }}).Sub(
|
||||
new({{ .Element }}), new({{ .Element }}).One()).Bytes()
|
||||
if subtle.ConstantTimeLessOrEqBytes(v, minusOneEncoding) == 0 {
|
||||
return nil, errors.New("invalid {{ .Element }} encoding")
|
||||
}
|
||||
|
||||
var in [{{ .Prefix }}ElementLen]byte
|
||||
copy(in[:], v)
|
||||
{{ .Prefix }}InvertEndianness(in[:])
|
||||
var tmp {{ .Prefix }}NonMontgomeryDomainFieldElement
|
||||
{{ .Prefix }}FromBytes((*{{ .Prefix }}UntypedFieldElement)(&tmp), &in)
|
||||
{{ .Prefix }}ToMontgomery(&e.x, &tmp)
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// Add sets e = t1 + t2, and returns e.
|
||||
func (e *{{ .Element }}) Add(t1, t2 *{{ .Element }}) *{{ .Element }} {
|
||||
{{ .Prefix }}Add(&e.x, &t1.x, &t2.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Sub sets e = t1 - t2, and returns e.
|
||||
func (e *{{ .Element }}) Sub(t1, t2 *{{ .Element }}) *{{ .Element }} {
|
||||
{{ .Prefix }}Sub(&e.x, &t1.x, &t2.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Mul sets e = t1 * t2, and returns e.
|
||||
func (e *{{ .Element }}) Mul(t1, t2 *{{ .Element }}) *{{ .Element }} {
|
||||
{{ .Prefix }}Mul(&e.x, &t1.x, &t2.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Square sets e = t * t, and returns e.
|
||||
func (e *{{ .Element }}) Square(t *{{ .Element }}) *{{ .Element }} {
|
||||
{{ .Prefix }}Square(&e.x, &t.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Select sets v to a if cond == 1, and to b if cond == 0.
|
||||
func (v *{{ .Element }}) Select(a, b *{{ .Element }}, cond int) *{{ .Element }} {
|
||||
{{ .Prefix }}Selectznz((*{{ .Prefix }}UntypedFieldElement)(&v.x), {{ .Prefix }}Uint1(cond),
|
||||
(*{{ .Prefix }}UntypedFieldElement)(&b.x), (*{{ .Prefix }}UntypedFieldElement)(&a.x))
|
||||
return v
|
||||
}
|
||||
|
||||
func {{ .Prefix }}InvertEndianness(v []byte) {
|
||||
for i := 0; i < len(v)/2; i++ {
|
||||
v[i], v[len(v)-1-i] = v[len(v)-1-i], v[i]
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const tmplAddchain = `// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Code generated by {{ .Meta.Name }}. DO NOT EDIT.
|
||||
|
||||
package fiat
|
||||
|
||||
// Invert sets e = 1/x, and returns e.
|
||||
//
|
||||
// If x == 0, Invert returns e = 0.
|
||||
func (e *Element) Invert(x *Element) *Element {
|
||||
// Inversion is implemented as exponentiation with exponent p − 2.
|
||||
// The sequence of {{ .Ops.Adds }} multiplications and {{ .Ops.Doubles }} squarings is derived from the
|
||||
// following addition chain generated with {{ .Meta.Module }} {{ .Meta.ReleaseTag }}.
|
||||
//
|
||||
{{- range lines (format .Script) }}
|
||||
// {{ . }}
|
||||
{{- end }}
|
||||
//
|
||||
|
||||
var z = new(Element).Set(e)
|
||||
{{- range .Program.Temporaries }}
|
||||
var {{ . }} = new(Element)
|
||||
{{- end }}
|
||||
{{ range $i := .Program.Instructions -}}
|
||||
{{- with add $i.Op }}
|
||||
{{ $i.Output }}.Mul({{ .X }}, {{ .Y }})
|
||||
{{- end -}}
|
||||
|
||||
{{- with double $i.Op }}
|
||||
{{ $i.Output }}.Square({{ .X }})
|
||||
{{- end -}}
|
||||
|
||||
{{- with shift $i.Op -}}
|
||||
{{- $first := 0 -}}
|
||||
{{- if ne $i.Output.Identifier .X.Identifier }}
|
||||
{{ $i.Output }}.Square({{ .X }})
|
||||
{{- $first = 1 -}}
|
||||
{{- end }}
|
||||
for s := {{ $first }}; s < {{ .S }}; s++ {
|
||||
{{ $i.Output }}.Square({{ $i.Output }})
|
||||
}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
return e.Set(z)
|
||||
}
|
||||
`
|
||||
130
internal/fiat/p224.go
Normal file
130
internal/fiat/p224.go
Normal file
@@ -0,0 +1,130 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Code generated by generate.go. DO NOT EDIT.
|
||||
|
||||
package fiat
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"sources.truenas.cloud/code/nistec/internal/subtle"
|
||||
)
|
||||
|
||||
// P224Element is an integer modulo 2^224 - 2^96 + 1.
|
||||
//
|
||||
// The zero value is a valid zero element.
|
||||
type P224Element struct {
|
||||
// Values are represented internally always in the Montgomery domain, and
|
||||
// converted in Bytes and SetBytes.
|
||||
x p224MontgomeryDomainFieldElement
|
||||
}
|
||||
|
||||
const p224ElementLen = 28
|
||||
|
||||
type p224UntypedFieldElement = [4]uint64
|
||||
|
||||
// One sets e = 1, and returns e.
|
||||
func (e *P224Element) One() *P224Element {
|
||||
p224SetOne(&e.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Equal returns 1 if e == t, and zero otherwise.
|
||||
func (e *P224Element) Equal(t *P224Element) int {
|
||||
eBytes := e.Bytes()
|
||||
tBytes := t.Bytes()
|
||||
return subtle.ConstantTimeCompare(eBytes, tBytes)
|
||||
}
|
||||
|
||||
// IsZero returns 1 if e == 0, and zero otherwise.
|
||||
func (e *P224Element) IsZero() int {
|
||||
zero := make([]byte, p224ElementLen)
|
||||
eBytes := e.Bytes()
|
||||
return subtle.ConstantTimeCompare(eBytes, zero)
|
||||
}
|
||||
|
||||
// Set sets e = t, and returns e.
|
||||
func (e *P224Element) Set(t *P224Element) *P224Element {
|
||||
e.x = t.x
|
||||
return e
|
||||
}
|
||||
|
||||
// Bytes returns the 28-byte big-endian encoding of e.
|
||||
func (e *P224Element) Bytes() []byte {
|
||||
// This function is outlined to make the allocations inline in the caller
|
||||
// rather than happen on the heap.
|
||||
var out [p224ElementLen]byte
|
||||
return e.bytes(&out)
|
||||
}
|
||||
|
||||
func (e *P224Element) bytes(out *[p224ElementLen]byte) []byte {
|
||||
var tmp p224NonMontgomeryDomainFieldElement
|
||||
p224FromMontgomery(&tmp, &e.x)
|
||||
p224ToBytes(out, (*p224UntypedFieldElement)(&tmp))
|
||||
p224InvertEndianness(out[:])
|
||||
return out[:]
|
||||
}
|
||||
|
||||
// SetBytes sets e = v, where v is a big-endian 28-byte encoding, and returns e.
|
||||
// If v is not 28 bytes or it encodes a value higher than 2^224 - 2^96 + 1,
|
||||
// SetBytes returns nil and an error, and e is unchanged.
|
||||
func (e *P224Element) SetBytes(v []byte) (*P224Element, error) {
|
||||
if len(v) != p224ElementLen {
|
||||
return nil, errors.New("invalid P224Element encoding")
|
||||
}
|
||||
|
||||
// Check for non-canonical encodings (p + k, 2p + k, etc.) by comparing to
|
||||
// the encoding of -1 mod p, so p - 1, the highest canonical encoding.
|
||||
var minusOneEncoding = new(P224Element).Sub(
|
||||
new(P224Element), new(P224Element).One()).Bytes()
|
||||
if subtle.ConstantTimeLessOrEqBytes(v, minusOneEncoding) == 0 {
|
||||
return nil, errors.New("invalid P224Element encoding")
|
||||
}
|
||||
|
||||
var in [p224ElementLen]byte
|
||||
copy(in[:], v)
|
||||
p224InvertEndianness(in[:])
|
||||
var tmp p224NonMontgomeryDomainFieldElement
|
||||
p224FromBytes((*p224UntypedFieldElement)(&tmp), &in)
|
||||
p224ToMontgomery(&e.x, &tmp)
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// Add sets e = t1 + t2, and returns e.
|
||||
func (e *P224Element) Add(t1, t2 *P224Element) *P224Element {
|
||||
p224Add(&e.x, &t1.x, &t2.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Sub sets e = t1 - t2, and returns e.
|
||||
func (e *P224Element) Sub(t1, t2 *P224Element) *P224Element {
|
||||
p224Sub(&e.x, &t1.x, &t2.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Mul sets e = t1 * t2, and returns e.
|
||||
func (e *P224Element) Mul(t1, t2 *P224Element) *P224Element {
|
||||
p224Mul(&e.x, &t1.x, &t2.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Square sets e = t * t, and returns e.
|
||||
func (e *P224Element) Square(t *P224Element) *P224Element {
|
||||
p224Square(&e.x, &t.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Select sets v to a if cond == 1, and to b if cond == 0.
|
||||
func (v *P224Element) Select(a, b *P224Element, cond int) *P224Element {
|
||||
p224Selectznz((*p224UntypedFieldElement)(&v.x), p224Uint1(cond),
|
||||
(*p224UntypedFieldElement)(&b.x), (*p224UntypedFieldElement)(&a.x))
|
||||
return v
|
||||
}
|
||||
|
||||
func p224InvertEndianness(v []byte) {
|
||||
for i := 0; i < len(v)/2; i++ {
|
||||
v[i], v[len(v)-1-i] = v[len(v)-1-i], v[i]
|
||||
}
|
||||
}
|
||||
1461
internal/fiat/p224_fiat64.go
Normal file
1461
internal/fiat/p224_fiat64.go
Normal file
File diff suppressed because it is too large
Load Diff
87
internal/fiat/p224_invert.go
Normal file
87
internal/fiat/p224_invert.go
Normal file
@@ -0,0 +1,87 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Code generated by addchain. DO NOT EDIT.
|
||||
|
||||
package fiat
|
||||
|
||||
// Invert sets e = 1/x, and returns e.
|
||||
//
|
||||
// If x == 0, Invert returns e = 0.
|
||||
func (e *P224Element) Invert(x *P224Element) *P224Element {
|
||||
// Inversion is implemented as exponentiation with exponent p − 2.
|
||||
// The sequence of 11 multiplications and 223 squarings is derived from the
|
||||
// following addition chain generated with github.com/mmcloughlin/addchain v0.4.0.
|
||||
//
|
||||
// _10 = 2*1
|
||||
// _11 = 1 + _10
|
||||
// _110 = 2*_11
|
||||
// _111 = 1 + _110
|
||||
// _111000 = _111 << 3
|
||||
// _111111 = _111 + _111000
|
||||
// x12 = _111111 << 6 + _111111
|
||||
// x14 = x12 << 2 + _11
|
||||
// x17 = x14 << 3 + _111
|
||||
// x31 = x17 << 14 + x14
|
||||
// x48 = x31 << 17 + x17
|
||||
// x96 = x48 << 48 + x48
|
||||
// x127 = x96 << 31 + x31
|
||||
// return x127 << 97 + x96
|
||||
//
|
||||
|
||||
var z = new(P224Element).Set(e)
|
||||
var t0 = new(P224Element)
|
||||
var t1 = new(P224Element)
|
||||
var t2 = new(P224Element)
|
||||
|
||||
z.Square(x)
|
||||
t0.Mul(x, z)
|
||||
z.Square(t0)
|
||||
z.Mul(x, z)
|
||||
t1.Square(z)
|
||||
for s := 1; s < 3; s++ {
|
||||
t1.Square(t1)
|
||||
}
|
||||
t1.Mul(z, t1)
|
||||
t2.Square(t1)
|
||||
for s := 1; s < 6; s++ {
|
||||
t2.Square(t2)
|
||||
}
|
||||
t1.Mul(t1, t2)
|
||||
for s := 0; s < 2; s++ {
|
||||
t1.Square(t1)
|
||||
}
|
||||
t0.Mul(t0, t1)
|
||||
t1.Square(t0)
|
||||
for s := 1; s < 3; s++ {
|
||||
t1.Square(t1)
|
||||
}
|
||||
z.Mul(z, t1)
|
||||
t1.Square(z)
|
||||
for s := 1; s < 14; s++ {
|
||||
t1.Square(t1)
|
||||
}
|
||||
t0.Mul(t0, t1)
|
||||
t1.Square(t0)
|
||||
for s := 1; s < 17; s++ {
|
||||
t1.Square(t1)
|
||||
}
|
||||
z.Mul(z, t1)
|
||||
t1.Square(z)
|
||||
for s := 1; s < 48; s++ {
|
||||
t1.Square(t1)
|
||||
}
|
||||
z.Mul(z, t1)
|
||||
t1.Square(z)
|
||||
for s := 1; s < 31; s++ {
|
||||
t1.Square(t1)
|
||||
}
|
||||
t0.Mul(t0, t1)
|
||||
for s := 0; s < 97; s++ {
|
||||
t0.Square(t0)
|
||||
}
|
||||
z.Mul(z, t0)
|
||||
|
||||
return e.Set(z)
|
||||
}
|
||||
130
internal/fiat/p256.go
Normal file
130
internal/fiat/p256.go
Normal file
@@ -0,0 +1,130 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Code generated by generate.go. DO NOT EDIT.
|
||||
|
||||
package fiat
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"sources.truenas.cloud/code/nistec/internal/subtle"
|
||||
)
|
||||
|
||||
// P256Element is an integer modulo 2^256 - 2^224 + 2^192 + 2^96 - 1.
|
||||
//
|
||||
// The zero value is a valid zero element.
|
||||
type P256Element struct {
|
||||
// Values are represented internally always in the Montgomery domain, and
|
||||
// converted in Bytes and SetBytes.
|
||||
x p256MontgomeryDomainFieldElement
|
||||
}
|
||||
|
||||
const p256ElementLen = 32
|
||||
|
||||
type p256UntypedFieldElement = [4]uint64
|
||||
|
||||
// One sets e = 1, and returns e.
|
||||
func (e *P256Element) One() *P256Element {
|
||||
p256SetOne(&e.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Equal returns 1 if e == t, and zero otherwise.
|
||||
func (e *P256Element) Equal(t *P256Element) int {
|
||||
eBytes := e.Bytes()
|
||||
tBytes := t.Bytes()
|
||||
return subtle.ConstantTimeCompare(eBytes, tBytes)
|
||||
}
|
||||
|
||||
// IsZero returns 1 if e == 0, and zero otherwise.
|
||||
func (e *P256Element) IsZero() int {
|
||||
zero := make([]byte, p256ElementLen)
|
||||
eBytes := e.Bytes()
|
||||
return subtle.ConstantTimeCompare(eBytes, zero)
|
||||
}
|
||||
|
||||
// Set sets e = t, and returns e.
|
||||
func (e *P256Element) Set(t *P256Element) *P256Element {
|
||||
e.x = t.x
|
||||
return e
|
||||
}
|
||||
|
||||
// Bytes returns the 32-byte big-endian encoding of e.
|
||||
func (e *P256Element) Bytes() []byte {
|
||||
// This function is outlined to make the allocations inline in the caller
|
||||
// rather than happen on the heap.
|
||||
var out [p256ElementLen]byte
|
||||
return e.bytes(&out)
|
||||
}
|
||||
|
||||
func (e *P256Element) bytes(out *[p256ElementLen]byte) []byte {
|
||||
var tmp p256NonMontgomeryDomainFieldElement
|
||||
p256FromMontgomery(&tmp, &e.x)
|
||||
p256ToBytes(out, (*p256UntypedFieldElement)(&tmp))
|
||||
p256InvertEndianness(out[:])
|
||||
return out[:]
|
||||
}
|
||||
|
||||
// SetBytes sets e = v, where v is a big-endian 32-byte encoding, and returns e.
|
||||
// If v is not 32 bytes or it encodes a value higher than 2^256 - 2^224 + 2^192 + 2^96 - 1,
|
||||
// SetBytes returns nil and an error, and e is unchanged.
|
||||
func (e *P256Element) SetBytes(v []byte) (*P256Element, error) {
|
||||
if len(v) != p256ElementLen {
|
||||
return nil, errors.New("invalid P256Element encoding")
|
||||
}
|
||||
|
||||
// Check for non-canonical encodings (p + k, 2p + k, etc.) by comparing to
|
||||
// the encoding of -1 mod p, so p - 1, the highest canonical encoding.
|
||||
var minusOneEncoding = new(P256Element).Sub(
|
||||
new(P256Element), new(P256Element).One()).Bytes()
|
||||
if subtle.ConstantTimeLessOrEqBytes(v, minusOneEncoding) == 0 {
|
||||
return nil, errors.New("invalid P256Element encoding")
|
||||
}
|
||||
|
||||
var in [p256ElementLen]byte
|
||||
copy(in[:], v)
|
||||
p256InvertEndianness(in[:])
|
||||
var tmp p256NonMontgomeryDomainFieldElement
|
||||
p256FromBytes((*p256UntypedFieldElement)(&tmp), &in)
|
||||
p256ToMontgomery(&e.x, &tmp)
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// Add sets e = t1 + t2, and returns e.
|
||||
func (e *P256Element) Add(t1, t2 *P256Element) *P256Element {
|
||||
p256Add(&e.x, &t1.x, &t2.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Sub sets e = t1 - t2, and returns e.
|
||||
func (e *P256Element) Sub(t1, t2 *P256Element) *P256Element {
|
||||
p256Sub(&e.x, &t1.x, &t2.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Mul sets e = t1 * t2, and returns e.
|
||||
func (e *P256Element) Mul(t1, t2 *P256Element) *P256Element {
|
||||
p256Mul(&e.x, &t1.x, &t2.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Square sets e = t * t, and returns e.
|
||||
func (e *P256Element) Square(t *P256Element) *P256Element {
|
||||
p256Square(&e.x, &t.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Select sets v to a if cond == 1, and to b if cond == 0.
|
||||
func (v *P256Element) Select(a, b *P256Element, cond int) *P256Element {
|
||||
p256Selectznz((*p256UntypedFieldElement)(&v.x), p256Uint1(cond),
|
||||
(*p256UntypedFieldElement)(&b.x), (*p256UntypedFieldElement)(&a.x))
|
||||
return v
|
||||
}
|
||||
|
||||
func p256InvertEndianness(v []byte) {
|
||||
for i := 0; i < len(v)/2; i++ {
|
||||
v[i], v[len(v)-1-i] = v[len(v)-1-i], v[i]
|
||||
}
|
||||
}
|
||||
12
internal/fiat/p256_extra.go
Normal file
12
internal/fiat/p256_extra.go
Normal file
@@ -0,0 +1,12 @@
|
||||
// Copyright 2023 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package fiat
|
||||
|
||||
// Bits returns a reference to the underlying little-endian fully-reduced
|
||||
// Montgomery representation of e. Handle with care.
|
||||
func (e *P256Element) Bits() *[4]uint64 {
|
||||
var _ p256MontgomeryDomainFieldElement = e.x
|
||||
return (*[4]uint64)(&e.x)
|
||||
}
|
||||
1400
internal/fiat/p256_fiat64.go
Normal file
1400
internal/fiat/p256_fiat64.go
Normal file
File diff suppressed because it is too large
Load Diff
84
internal/fiat/p256_invert.go
Normal file
84
internal/fiat/p256_invert.go
Normal file
@@ -0,0 +1,84 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Code generated by addchain. DO NOT EDIT.
|
||||
|
||||
package fiat
|
||||
|
||||
// Invert sets e = 1/x, and returns e.
|
||||
//
|
||||
// If x == 0, Invert returns e = 0.
|
||||
func (e *P256Element) Invert(x *P256Element) *P256Element {
|
||||
// Inversion is implemented as exponentiation with exponent p − 2.
|
||||
// The sequence of 12 multiplications and 255 squarings is derived from the
|
||||
// following addition chain generated with github.com/mmcloughlin/addchain v0.4.0.
|
||||
//
|
||||
// _10 = 2*1
|
||||
// _11 = 1 + _10
|
||||
// _110 = 2*_11
|
||||
// _111 = 1 + _110
|
||||
// _111000 = _111 << 3
|
||||
// _111111 = _111 + _111000
|
||||
// x12 = _111111 << 6 + _111111
|
||||
// x15 = x12 << 3 + _111
|
||||
// x16 = 2*x15 + 1
|
||||
// x32 = x16 << 16 + x16
|
||||
// i53 = x32 << 15
|
||||
// x47 = x15 + i53
|
||||
// i263 = ((i53 << 17 + 1) << 143 + x47) << 47
|
||||
// return (x47 + i263) << 2 + 1
|
||||
//
|
||||
|
||||
var z = new(P256Element).Set(e)
|
||||
var t0 = new(P256Element)
|
||||
var t1 = new(P256Element)
|
||||
|
||||
z.Square(x)
|
||||
z.Mul(x, z)
|
||||
z.Square(z)
|
||||
z.Mul(x, z)
|
||||
t0.Square(z)
|
||||
for s := 1; s < 3; s++ {
|
||||
t0.Square(t0)
|
||||
}
|
||||
t0.Mul(z, t0)
|
||||
t1.Square(t0)
|
||||
for s := 1; s < 6; s++ {
|
||||
t1.Square(t1)
|
||||
}
|
||||
t0.Mul(t0, t1)
|
||||
for s := 0; s < 3; s++ {
|
||||
t0.Square(t0)
|
||||
}
|
||||
z.Mul(z, t0)
|
||||
t0.Square(z)
|
||||
t0.Mul(x, t0)
|
||||
t1.Square(t0)
|
||||
for s := 1; s < 16; s++ {
|
||||
t1.Square(t1)
|
||||
}
|
||||
t0.Mul(t0, t1)
|
||||
for s := 0; s < 15; s++ {
|
||||
t0.Square(t0)
|
||||
}
|
||||
z.Mul(z, t0)
|
||||
for s := 0; s < 17; s++ {
|
||||
t0.Square(t0)
|
||||
}
|
||||
t0.Mul(x, t0)
|
||||
for s := 0; s < 143; s++ {
|
||||
t0.Square(t0)
|
||||
}
|
||||
t0.Mul(z, t0)
|
||||
for s := 0; s < 47; s++ {
|
||||
t0.Square(t0)
|
||||
}
|
||||
z.Mul(z, t0)
|
||||
for s := 0; s < 2; s++ {
|
||||
z.Square(z)
|
||||
}
|
||||
z.Mul(x, z)
|
||||
|
||||
return e.Set(z)
|
||||
}
|
||||
130
internal/fiat/p384.go
Normal file
130
internal/fiat/p384.go
Normal file
@@ -0,0 +1,130 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Code generated by generate.go. DO NOT EDIT.
|
||||
|
||||
package fiat
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"sources.truenas.cloud/code/nistec/internal/subtle"
|
||||
)
|
||||
|
||||
// P384Element is an integer modulo 2^384 - 2^128 - 2^96 + 2^32 - 1.
|
||||
//
|
||||
// The zero value is a valid zero element.
|
||||
type P384Element struct {
|
||||
// Values are represented internally always in the Montgomery domain, and
|
||||
// converted in Bytes and SetBytes.
|
||||
x p384MontgomeryDomainFieldElement
|
||||
}
|
||||
|
||||
const p384ElementLen = 48
|
||||
|
||||
type p384UntypedFieldElement = [6]uint64
|
||||
|
||||
// One sets e = 1, and returns e.
|
||||
func (e *P384Element) One() *P384Element {
|
||||
p384SetOne(&e.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Equal returns 1 if e == t, and zero otherwise.
|
||||
func (e *P384Element) Equal(t *P384Element) int {
|
||||
eBytes := e.Bytes()
|
||||
tBytes := t.Bytes()
|
||||
return subtle.ConstantTimeCompare(eBytes, tBytes)
|
||||
}
|
||||
|
||||
// IsZero returns 1 if e == 0, and zero otherwise.
|
||||
func (e *P384Element) IsZero() int {
|
||||
zero := make([]byte, p384ElementLen)
|
||||
eBytes := e.Bytes()
|
||||
return subtle.ConstantTimeCompare(eBytes, zero)
|
||||
}
|
||||
|
||||
// Set sets e = t, and returns e.
|
||||
func (e *P384Element) Set(t *P384Element) *P384Element {
|
||||
e.x = t.x
|
||||
return e
|
||||
}
|
||||
|
||||
// Bytes returns the 48-byte big-endian encoding of e.
|
||||
func (e *P384Element) Bytes() []byte {
|
||||
// This function is outlined to make the allocations inline in the caller
|
||||
// rather than happen on the heap.
|
||||
var out [p384ElementLen]byte
|
||||
return e.bytes(&out)
|
||||
}
|
||||
|
||||
func (e *P384Element) bytes(out *[p384ElementLen]byte) []byte {
|
||||
var tmp p384NonMontgomeryDomainFieldElement
|
||||
p384FromMontgomery(&tmp, &e.x)
|
||||
p384ToBytes(out, (*p384UntypedFieldElement)(&tmp))
|
||||
p384InvertEndianness(out[:])
|
||||
return out[:]
|
||||
}
|
||||
|
||||
// SetBytes sets e = v, where v is a big-endian 48-byte encoding, and returns e.
|
||||
// If v is not 48 bytes or it encodes a value higher than 2^384 - 2^128 - 2^96 + 2^32 - 1,
|
||||
// SetBytes returns nil and an error, and e is unchanged.
|
||||
func (e *P384Element) SetBytes(v []byte) (*P384Element, error) {
|
||||
if len(v) != p384ElementLen {
|
||||
return nil, errors.New("invalid P384Element encoding")
|
||||
}
|
||||
|
||||
// Check for non-canonical encodings (p + k, 2p + k, etc.) by comparing to
|
||||
// the encoding of -1 mod p, so p - 1, the highest canonical encoding.
|
||||
var minusOneEncoding = new(P384Element).Sub(
|
||||
new(P384Element), new(P384Element).One()).Bytes()
|
||||
if subtle.ConstantTimeLessOrEqBytes(v, minusOneEncoding) == 0 {
|
||||
return nil, errors.New("invalid P384Element encoding")
|
||||
}
|
||||
|
||||
var in [p384ElementLen]byte
|
||||
copy(in[:], v)
|
||||
p384InvertEndianness(in[:])
|
||||
var tmp p384NonMontgomeryDomainFieldElement
|
||||
p384FromBytes((*p384UntypedFieldElement)(&tmp), &in)
|
||||
p384ToMontgomery(&e.x, &tmp)
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// Add sets e = t1 + t2, and returns e.
|
||||
func (e *P384Element) Add(t1, t2 *P384Element) *P384Element {
|
||||
p384Add(&e.x, &t1.x, &t2.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Sub sets e = t1 - t2, and returns e.
|
||||
func (e *P384Element) Sub(t1, t2 *P384Element) *P384Element {
|
||||
p384Sub(&e.x, &t1.x, &t2.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Mul sets e = t1 * t2, and returns e.
|
||||
func (e *P384Element) Mul(t1, t2 *P384Element) *P384Element {
|
||||
p384Mul(&e.x, &t1.x, &t2.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Square sets e = t * t, and returns e.
|
||||
func (e *P384Element) Square(t *P384Element) *P384Element {
|
||||
p384Square(&e.x, &t.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Select sets v to a if cond == 1, and to b if cond == 0.
|
||||
func (v *P384Element) Select(a, b *P384Element, cond int) *P384Element {
|
||||
p384Selectznz((*p384UntypedFieldElement)(&v.x), p384Uint1(cond),
|
||||
(*p384UntypedFieldElement)(&b.x), (*p384UntypedFieldElement)(&a.x))
|
||||
return v
|
||||
}
|
||||
|
||||
func p384InvertEndianness(v []byte) {
|
||||
for i := 0; i < len(v)/2; i++ {
|
||||
v[i], v[len(v)-1-i] = v[len(v)-1-i], v[i]
|
||||
}
|
||||
}
|
||||
3036
internal/fiat/p384_fiat64.go
Normal file
3036
internal/fiat/p384_fiat64.go
Normal file
File diff suppressed because it is too large
Load Diff
102
internal/fiat/p384_invert.go
Normal file
102
internal/fiat/p384_invert.go
Normal file
@@ -0,0 +1,102 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Code generated by addchain. DO NOT EDIT.
|
||||
|
||||
package fiat
|
||||
|
||||
// Invert sets e = 1/x, and returns e.
|
||||
//
|
||||
// If x == 0, Invert returns e = 0.
|
||||
func (e *P384Element) Invert(x *P384Element) *P384Element {
|
||||
// Inversion is implemented as exponentiation with exponent p − 2.
|
||||
// The sequence of 15 multiplications and 383 squarings is derived from the
|
||||
// following addition chain generated with github.com/mmcloughlin/addchain v0.4.0.
|
||||
//
|
||||
// _10 = 2*1
|
||||
// _11 = 1 + _10
|
||||
// _110 = 2*_11
|
||||
// _111 = 1 + _110
|
||||
// _111000 = _111 << 3
|
||||
// _111111 = _111 + _111000
|
||||
// x12 = _111111 << 6 + _111111
|
||||
// x24 = x12 << 12 + x12
|
||||
// x30 = x24 << 6 + _111111
|
||||
// x31 = 2*x30 + 1
|
||||
// x32 = 2*x31 + 1
|
||||
// x63 = x32 << 31 + x31
|
||||
// x126 = x63 << 63 + x63
|
||||
// x252 = x126 << 126 + x126
|
||||
// x255 = x252 << 3 + _111
|
||||
// i397 = ((x255 << 33 + x32) << 94 + x30) << 2
|
||||
// return 1 + i397
|
||||
//
|
||||
|
||||
var z = new(P384Element).Set(e)
|
||||
var t0 = new(P384Element)
|
||||
var t1 = new(P384Element)
|
||||
var t2 = new(P384Element)
|
||||
var t3 = new(P384Element)
|
||||
|
||||
z.Square(x)
|
||||
z.Mul(x, z)
|
||||
z.Square(z)
|
||||
t1.Mul(x, z)
|
||||
z.Square(t1)
|
||||
for s := 1; s < 3; s++ {
|
||||
z.Square(z)
|
||||
}
|
||||
z.Mul(t1, z)
|
||||
t0.Square(z)
|
||||
for s := 1; s < 6; s++ {
|
||||
t0.Square(t0)
|
||||
}
|
||||
t0.Mul(z, t0)
|
||||
t2.Square(t0)
|
||||
for s := 1; s < 12; s++ {
|
||||
t2.Square(t2)
|
||||
}
|
||||
t0.Mul(t0, t2)
|
||||
for s := 0; s < 6; s++ {
|
||||
t0.Square(t0)
|
||||
}
|
||||
z.Mul(z, t0)
|
||||
t0.Square(z)
|
||||
t2.Mul(x, t0)
|
||||
t0.Square(t2)
|
||||
t0.Mul(x, t0)
|
||||
t3.Square(t0)
|
||||
for s := 1; s < 31; s++ {
|
||||
t3.Square(t3)
|
||||
}
|
||||
t2.Mul(t2, t3)
|
||||
t3.Square(t2)
|
||||
for s := 1; s < 63; s++ {
|
||||
t3.Square(t3)
|
||||
}
|
||||
t2.Mul(t2, t3)
|
||||
t3.Square(t2)
|
||||
for s := 1; s < 126; s++ {
|
||||
t3.Square(t3)
|
||||
}
|
||||
t2.Mul(t2, t3)
|
||||
for s := 0; s < 3; s++ {
|
||||
t2.Square(t2)
|
||||
}
|
||||
t1.Mul(t1, t2)
|
||||
for s := 0; s < 33; s++ {
|
||||
t1.Square(t1)
|
||||
}
|
||||
t0.Mul(t0, t1)
|
||||
for s := 0; s < 94; s++ {
|
||||
t0.Square(t0)
|
||||
}
|
||||
z.Mul(z, t0)
|
||||
for s := 0; s < 2; s++ {
|
||||
z.Square(z)
|
||||
}
|
||||
z.Mul(x, z)
|
||||
|
||||
return e.Set(z)
|
||||
}
|
||||
130
internal/fiat/p521.go
Normal file
130
internal/fiat/p521.go
Normal file
@@ -0,0 +1,130 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Code generated by generate.go. DO NOT EDIT.
|
||||
|
||||
package fiat
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"sources.truenas.cloud/code/nistec/internal/subtle"
|
||||
)
|
||||
|
||||
// P521Element is an integer modulo 2^521 - 1.
|
||||
//
|
||||
// The zero value is a valid zero element.
|
||||
type P521Element struct {
|
||||
// Values are represented internally always in the Montgomery domain, and
|
||||
// converted in Bytes and SetBytes.
|
||||
x p521MontgomeryDomainFieldElement
|
||||
}
|
||||
|
||||
const p521ElementLen = 66
|
||||
|
||||
type p521UntypedFieldElement = [9]uint64
|
||||
|
||||
// One sets e = 1, and returns e.
|
||||
func (e *P521Element) One() *P521Element {
|
||||
p521SetOne(&e.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Equal returns 1 if e == t, and zero otherwise.
|
||||
func (e *P521Element) Equal(t *P521Element) int {
|
||||
eBytes := e.Bytes()
|
||||
tBytes := t.Bytes()
|
||||
return subtle.ConstantTimeCompare(eBytes, tBytes)
|
||||
}
|
||||
|
||||
// IsZero returns 1 if e == 0, and zero otherwise.
|
||||
func (e *P521Element) IsZero() int {
|
||||
zero := make([]byte, p521ElementLen)
|
||||
eBytes := e.Bytes()
|
||||
return subtle.ConstantTimeCompare(eBytes, zero)
|
||||
}
|
||||
|
||||
// Set sets e = t, and returns e.
|
||||
func (e *P521Element) Set(t *P521Element) *P521Element {
|
||||
e.x = t.x
|
||||
return e
|
||||
}
|
||||
|
||||
// Bytes returns the 66-byte big-endian encoding of e.
|
||||
func (e *P521Element) Bytes() []byte {
|
||||
// This function is outlined to make the allocations inline in the caller
|
||||
// rather than happen on the heap.
|
||||
var out [p521ElementLen]byte
|
||||
return e.bytes(&out)
|
||||
}
|
||||
|
||||
func (e *P521Element) bytes(out *[p521ElementLen]byte) []byte {
|
||||
var tmp p521NonMontgomeryDomainFieldElement
|
||||
p521FromMontgomery(&tmp, &e.x)
|
||||
p521ToBytes(out, (*p521UntypedFieldElement)(&tmp))
|
||||
p521InvertEndianness(out[:])
|
||||
return out[:]
|
||||
}
|
||||
|
||||
// SetBytes sets e = v, where v is a big-endian 66-byte encoding, and returns e.
|
||||
// If v is not 66 bytes or it encodes a value higher than 2^521 - 1,
|
||||
// SetBytes returns nil and an error, and e is unchanged.
|
||||
func (e *P521Element) SetBytes(v []byte) (*P521Element, error) {
|
||||
if len(v) != p521ElementLen {
|
||||
return nil, errors.New("invalid P521Element encoding")
|
||||
}
|
||||
|
||||
// Check for non-canonical encodings (p + k, 2p + k, etc.) by comparing to
|
||||
// the encoding of -1 mod p, so p - 1, the highest canonical encoding.
|
||||
var minusOneEncoding = new(P521Element).Sub(
|
||||
new(P521Element), new(P521Element).One()).Bytes()
|
||||
if subtle.ConstantTimeLessOrEqBytes(v, minusOneEncoding) == 0 {
|
||||
return nil, errors.New("invalid P521Element encoding")
|
||||
}
|
||||
|
||||
var in [p521ElementLen]byte
|
||||
copy(in[:], v)
|
||||
p521InvertEndianness(in[:])
|
||||
var tmp p521NonMontgomeryDomainFieldElement
|
||||
p521FromBytes((*p521UntypedFieldElement)(&tmp), &in)
|
||||
p521ToMontgomery(&e.x, &tmp)
|
||||
return e, nil
|
||||
}
|
||||
|
||||
// Add sets e = t1 + t2, and returns e.
|
||||
func (e *P521Element) Add(t1, t2 *P521Element) *P521Element {
|
||||
p521Add(&e.x, &t1.x, &t2.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Sub sets e = t1 - t2, and returns e.
|
||||
func (e *P521Element) Sub(t1, t2 *P521Element) *P521Element {
|
||||
p521Sub(&e.x, &t1.x, &t2.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Mul sets e = t1 * t2, and returns e.
|
||||
func (e *P521Element) Mul(t1, t2 *P521Element) *P521Element {
|
||||
p521Mul(&e.x, &t1.x, &t2.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Square sets e = t * t, and returns e.
|
||||
func (e *P521Element) Square(t *P521Element) *P521Element {
|
||||
p521Square(&e.x, &t.x)
|
||||
return e
|
||||
}
|
||||
|
||||
// Select sets v to a if cond == 1, and to b if cond == 0.
|
||||
func (v *P521Element) Select(a, b *P521Element, cond int) *P521Element {
|
||||
p521Selectznz((*p521UntypedFieldElement)(&v.x), p521Uint1(cond),
|
||||
(*p521UntypedFieldElement)(&b.x), (*p521UntypedFieldElement)(&a.x))
|
||||
return v
|
||||
}
|
||||
|
||||
func p521InvertEndianness(v []byte) {
|
||||
for i := 0; i < len(v)/2; i++ {
|
||||
v[i], v[len(v)-1-i] = v[len(v)-1-i], v[i]
|
||||
}
|
||||
}
|
||||
5541
internal/fiat/p521_fiat64.go
Normal file
5541
internal/fiat/p521_fiat64.go
Normal file
File diff suppressed because it is too large
Load Diff
89
internal/fiat/p521_invert.go
Normal file
89
internal/fiat/p521_invert.go
Normal file
@@ -0,0 +1,89 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Code generated by addchain. DO NOT EDIT.
|
||||
|
||||
package fiat
|
||||
|
||||
// Invert sets e = 1/x, and returns e.
|
||||
//
|
||||
// If x == 0, Invert returns e = 0.
|
||||
func (e *P521Element) Invert(x *P521Element) *P521Element {
|
||||
// Inversion is implemented as exponentiation with exponent p − 2.
|
||||
// The sequence of 13 multiplications and 520 squarings is derived from the
|
||||
// following addition chain generated with github.com/mmcloughlin/addchain v0.4.0.
|
||||
//
|
||||
// _10 = 2*1
|
||||
// _11 = 1 + _10
|
||||
// _1100 = _11 << 2
|
||||
// _1111 = _11 + _1100
|
||||
// _11110000 = _1111 << 4
|
||||
// _11111111 = _1111 + _11110000
|
||||
// x16 = _11111111 << 8 + _11111111
|
||||
// x32 = x16 << 16 + x16
|
||||
// x64 = x32 << 32 + x32
|
||||
// x65 = 2*x64 + 1
|
||||
// x129 = x65 << 64 + x64
|
||||
// x130 = 2*x129 + 1
|
||||
// x259 = x130 << 129 + x129
|
||||
// x260 = 2*x259 + 1
|
||||
// x519 = x260 << 259 + x259
|
||||
// return x519 << 2 + 1
|
||||
//
|
||||
|
||||
var z = new(P521Element).Set(e)
|
||||
var t0 = new(P521Element)
|
||||
|
||||
z.Square(x)
|
||||
z.Mul(x, z)
|
||||
t0.Square(z)
|
||||
for s := 1; s < 2; s++ {
|
||||
t0.Square(t0)
|
||||
}
|
||||
z.Mul(z, t0)
|
||||
t0.Square(z)
|
||||
for s := 1; s < 4; s++ {
|
||||
t0.Square(t0)
|
||||
}
|
||||
z.Mul(z, t0)
|
||||
t0.Square(z)
|
||||
for s := 1; s < 8; s++ {
|
||||
t0.Square(t0)
|
||||
}
|
||||
z.Mul(z, t0)
|
||||
t0.Square(z)
|
||||
for s := 1; s < 16; s++ {
|
||||
t0.Square(t0)
|
||||
}
|
||||
z.Mul(z, t0)
|
||||
t0.Square(z)
|
||||
for s := 1; s < 32; s++ {
|
||||
t0.Square(t0)
|
||||
}
|
||||
z.Mul(z, t0)
|
||||
t0.Square(z)
|
||||
t0.Mul(x, t0)
|
||||
for s := 0; s < 64; s++ {
|
||||
t0.Square(t0)
|
||||
}
|
||||
z.Mul(z, t0)
|
||||
t0.Square(z)
|
||||
t0.Mul(x, t0)
|
||||
for s := 0; s < 129; s++ {
|
||||
t0.Square(t0)
|
||||
}
|
||||
z.Mul(z, t0)
|
||||
t0.Square(z)
|
||||
t0.Mul(x, t0)
|
||||
for s := 0; s < 259; s++ {
|
||||
t0.Square(t0)
|
||||
}
|
||||
z.Mul(z, t0)
|
||||
for s := 0; s < 2; s++ {
|
||||
z.Square(z)
|
||||
}
|
||||
z.Mul(x, z)
|
||||
|
||||
return e.Set(z)
|
||||
}
|
||||
47
internal/subtle/subtle.go
Normal file
47
internal/subtle/subtle.go
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright 2009 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package subtle
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"math/bits"
|
||||
|
||||
"sources.truenas.cloud/code/nistec/internal/byteorder"
|
||||
)
|
||||
|
||||
func ConstantTimeCompare(x, y []byte) int {
|
||||
return subtle.ConstantTimeCompare(x, y)
|
||||
}
|
||||
|
||||
// ConstantTimeLessOrEqBytes returns 1 if x <= y and 0 otherwise. The comparison
|
||||
// is lexigraphical, or big-endian. The time taken is a function of the length of
|
||||
// the slices and is independent of the contents. If the lengths of x and y do not
|
||||
// match it returns 0 immediately.
|
||||
func ConstantTimeLessOrEqBytes(x, y []byte) int {
|
||||
if len(x) != len(y) {
|
||||
return 0
|
||||
}
|
||||
|
||||
// Do a constant time subtraction chain y - x.
|
||||
// If there is no borrow at the end, then x <= y.
|
||||
var b uint64
|
||||
for len(x) > 8 {
|
||||
x0 := byteorder.BEUint64(x[len(x)-8:])
|
||||
y0 := byteorder.BEUint64(y[len(y)-8:])
|
||||
_, b = bits.Sub64(y0, x0, b)
|
||||
x = x[:len(x)-8]
|
||||
y = y[:len(y)-8]
|
||||
}
|
||||
if len(x) > 0 {
|
||||
xb := make([]byte, 8)
|
||||
yb := make([]byte, 8)
|
||||
copy(xb[8-len(x):], x)
|
||||
copy(yb[8-len(y):], y)
|
||||
x0 := byteorder.BEUint64(xb)
|
||||
y0 := byteorder.BEUint64(yb)
|
||||
_, b = bits.Sub64(y0, x0, b)
|
||||
}
|
||||
return int(b ^ 1)
|
||||
}
|
||||
15
nistec.go
Normal file
15
nistec.go
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package nistec implements the elliptic curves from NIST SP 800-186.
|
||||
//
|
||||
// This package uses fiat-crypto or specialized assembly and Go code for its
|
||||
// backend field arithmetic (not math/big) and exposes constant-time, heap
|
||||
// allocation-free, byte slice-based safe APIs. Group operations use modern and
|
||||
// safe complete addition formulas where possible. The point at infinity is
|
||||
// handled and encoded according to SEC 1, Version 2.0, and invalid curve points
|
||||
// can't be represented.
|
||||
package nistec
|
||||
|
||||
//go:generate go run generate.go
|
||||
255
nistec_test.go
Normal file
255
nistec_test.go
Normal file
@@ -0,0 +1,255 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package nistec_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"sources.truenas.cloud/code/nistec"
|
||||
)
|
||||
|
||||
func TestNISTECAllocations(t *testing.T) {
|
||||
if raceEnabled {
|
||||
t.Skip("skipping allocation test in -race mode")
|
||||
}
|
||||
t.Run("P224", func(t *testing.T) {
|
||||
if allocs := testing.AllocsPerRun(10, func() {
|
||||
p := nistec.NewP224Point().SetGenerator()
|
||||
scalar := make([]byte, 28)
|
||||
rand.Read(scalar)
|
||||
p.ScalarBaseMult(scalar)
|
||||
p.ScalarMult(p, scalar)
|
||||
out := p.Bytes()
|
||||
if _, err := nistec.NewP224Point().SetBytes(out); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
out = p.BytesCompressed()
|
||||
if _, err := p.SetBytes(out); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}); allocs > 0 {
|
||||
t.Errorf("expected zero allocations, got %0.1f", allocs)
|
||||
}
|
||||
})
|
||||
t.Run("P256", func(t *testing.T) {
|
||||
if allocs := testing.AllocsPerRun(10, func() {
|
||||
p := nistec.NewP256Point().SetGenerator()
|
||||
scalar := make([]byte, 32)
|
||||
rand.Read(scalar)
|
||||
p.ScalarBaseMult(scalar)
|
||||
p.ScalarMult(p, scalar)
|
||||
out := p.Bytes()
|
||||
if _, err := nistec.NewP256Point().SetBytes(out); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
out = p.BytesCompressed()
|
||||
if _, err := p.SetBytes(out); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}); allocs > 0 {
|
||||
t.Errorf("expected zero allocations, got %0.1f", allocs)
|
||||
}
|
||||
})
|
||||
t.Run("P384", func(t *testing.T) {
|
||||
if allocs := testing.AllocsPerRun(10, func() {
|
||||
p := nistec.NewP384Point().SetGenerator()
|
||||
scalar := make([]byte, 48)
|
||||
rand.Read(scalar)
|
||||
p.ScalarBaseMult(scalar)
|
||||
p.ScalarMult(p, scalar)
|
||||
out := p.Bytes()
|
||||
if _, err := nistec.NewP384Point().SetBytes(out); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
out = p.BytesCompressed()
|
||||
if _, err := p.SetBytes(out); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}); allocs > 0 {
|
||||
t.Errorf("expected zero allocations, got %0.1f", allocs)
|
||||
}
|
||||
})
|
||||
t.Run("P521", func(t *testing.T) {
|
||||
if allocs := testing.AllocsPerRun(10, func() {
|
||||
p := nistec.NewP521Point().SetGenerator()
|
||||
scalar := make([]byte, 66)
|
||||
rand.Read(scalar)
|
||||
p.ScalarBaseMult(scalar)
|
||||
p.ScalarMult(p, scalar)
|
||||
out := p.Bytes()
|
||||
if _, err := nistec.NewP521Point().SetBytes(out); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
out = p.BytesCompressed()
|
||||
if _, err := p.SetBytes(out); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}); allocs > 0 {
|
||||
t.Errorf("expected zero allocations, got %0.1f", allocs)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type nistPoint[T any] interface {
|
||||
Bytes() []byte
|
||||
SetGenerator() T
|
||||
SetBytes([]byte) (T, error)
|
||||
Add(T, T) T
|
||||
Double(T) T
|
||||
ScalarMult(T, []byte) (T, error)
|
||||
ScalarBaseMult([]byte) (T, error)
|
||||
}
|
||||
|
||||
func TestEquivalents(t *testing.T) {
|
||||
t.Run("P224", func(t *testing.T) {
|
||||
testEquivalents(t, nistec.NewP224Point, elliptic.P224())
|
||||
})
|
||||
t.Run("P256", func(t *testing.T) {
|
||||
testEquivalents(t, nistec.NewP256Point, elliptic.P256())
|
||||
})
|
||||
t.Run("P384", func(t *testing.T) {
|
||||
testEquivalents(t, nistec.NewP384Point, elliptic.P384())
|
||||
})
|
||||
t.Run("P521", func(t *testing.T) {
|
||||
testEquivalents(t, nistec.NewP521Point, elliptic.P521())
|
||||
})
|
||||
}
|
||||
|
||||
func testEquivalents[P nistPoint[P]](t *testing.T, newPoint func() P, c elliptic.Curve) {
|
||||
p := newPoint().SetGenerator()
|
||||
|
||||
elementSize := (c.Params().BitSize + 7) / 8
|
||||
two := make([]byte, elementSize)
|
||||
two[len(two)-1] = 2
|
||||
nPlusTwo := make([]byte, elementSize)
|
||||
new(big.Int).Add(c.Params().N, big.NewInt(2)).FillBytes(nPlusTwo)
|
||||
|
||||
p1 := newPoint().Double(p)
|
||||
p2 := newPoint().Add(p, p)
|
||||
p3, err := newPoint().ScalarMult(p, two)
|
||||
fatalIfErr(t, err)
|
||||
p4, err := newPoint().ScalarBaseMult(two)
|
||||
fatalIfErr(t, err)
|
||||
p5, err := newPoint().ScalarMult(p, nPlusTwo)
|
||||
fatalIfErr(t, err)
|
||||
p6, err := newPoint().ScalarBaseMult(nPlusTwo)
|
||||
fatalIfErr(t, err)
|
||||
|
||||
if !bytes.Equal(p1.Bytes(), p2.Bytes()) {
|
||||
t.Error("P+P != 2*P")
|
||||
}
|
||||
if !bytes.Equal(p1.Bytes(), p3.Bytes()) {
|
||||
t.Error("P+P != [2]P")
|
||||
}
|
||||
if !bytes.Equal(p1.Bytes(), p4.Bytes()) {
|
||||
t.Error("G+G != [2]G")
|
||||
}
|
||||
if !bytes.Equal(p1.Bytes(), p5.Bytes()) {
|
||||
t.Error("P+P != [N+2]P")
|
||||
}
|
||||
if !bytes.Equal(p1.Bytes(), p6.Bytes()) {
|
||||
t.Error("G+G != [N+2]G")
|
||||
}
|
||||
}
|
||||
|
||||
func TestScalarMult(t *testing.T) {
|
||||
t.Run("P224", func(t *testing.T) {
|
||||
testScalarMult(t, nistec.NewP224Point, elliptic.P224())
|
||||
})
|
||||
t.Run("P256", func(t *testing.T) {
|
||||
testScalarMult(t, nistec.NewP256Point, elliptic.P256())
|
||||
})
|
||||
t.Run("P384", func(t *testing.T) {
|
||||
testScalarMult(t, nistec.NewP384Point, elliptic.P384())
|
||||
})
|
||||
t.Run("P521", func(t *testing.T) {
|
||||
testScalarMult(t, nistec.NewP521Point, elliptic.P521())
|
||||
})
|
||||
}
|
||||
|
||||
func testScalarMult[P nistPoint[P]](t *testing.T, newPoint func() P, c elliptic.Curve) {
|
||||
G := newPoint().SetGenerator()
|
||||
checkScalar := func(t *testing.T, scalar []byte) {
|
||||
p1, err := newPoint().ScalarBaseMult(scalar)
|
||||
fatalIfErr(t, err)
|
||||
p2, err := newPoint().ScalarMult(G, scalar)
|
||||
fatalIfErr(t, err)
|
||||
if !bytes.Equal(p1.Bytes(), p2.Bytes()) {
|
||||
t.Error("[k]G != ScalarBaseMult(k)")
|
||||
}
|
||||
|
||||
expectInfinity := new(big.Int).Mod(new(big.Int).SetBytes(scalar), c.Params().N).Sign() == 0
|
||||
if expectInfinity {
|
||||
if !bytes.Equal(p1.Bytes(), newPoint().Bytes()) {
|
||||
t.Error("ScalarBaseMult(k) != ∞")
|
||||
}
|
||||
if !bytes.Equal(p2.Bytes(), newPoint().Bytes()) {
|
||||
t.Error("[k]G != ∞")
|
||||
}
|
||||
} else {
|
||||
if bytes.Equal(p1.Bytes(), newPoint().Bytes()) {
|
||||
t.Error("ScalarBaseMult(k) == ∞")
|
||||
}
|
||||
if bytes.Equal(p2.Bytes(), newPoint().Bytes()) {
|
||||
t.Error("[k]G == ∞")
|
||||
}
|
||||
}
|
||||
|
||||
d := new(big.Int).SetBytes(scalar)
|
||||
d.Sub(c.Params().N, d)
|
||||
d.Mod(d, c.Params().N)
|
||||
g1, err := newPoint().ScalarBaseMult(d.FillBytes(make([]byte, len(scalar))))
|
||||
fatalIfErr(t, err)
|
||||
g1.Add(g1, p1)
|
||||
if !bytes.Equal(g1.Bytes(), newPoint().Bytes()) {
|
||||
t.Error("[N - k]G + [k]G != ∞")
|
||||
}
|
||||
}
|
||||
|
||||
byteLen := len(c.Params().N.Bytes())
|
||||
bitLen := c.Params().N.BitLen()
|
||||
t.Run("0", func(t *testing.T) { checkScalar(t, make([]byte, byteLen)) })
|
||||
t.Run("1", func(t *testing.T) {
|
||||
checkScalar(t, big.NewInt(1).FillBytes(make([]byte, byteLen)))
|
||||
})
|
||||
t.Run("N-1", func(t *testing.T) {
|
||||
checkScalar(t, new(big.Int).Sub(c.Params().N, big.NewInt(1)).Bytes())
|
||||
})
|
||||
t.Run("N", func(t *testing.T) { checkScalar(t, c.Params().N.Bytes()) })
|
||||
t.Run("N+1", func(t *testing.T) {
|
||||
checkScalar(t, new(big.Int).Add(c.Params().N, big.NewInt(1)).Bytes())
|
||||
})
|
||||
t.Run("all1s", func(t *testing.T) {
|
||||
s := new(big.Int).Lsh(big.NewInt(1), uint(bitLen))
|
||||
s.Sub(s, big.NewInt(1))
|
||||
checkScalar(t, s.Bytes())
|
||||
})
|
||||
if testing.Short() {
|
||||
return
|
||||
}
|
||||
for i := 0; i < bitLen; i++ {
|
||||
t.Run(fmt.Sprintf("1<<%d", i), func(t *testing.T) {
|
||||
s := new(big.Int).Lsh(big.NewInt(1), uint(i))
|
||||
checkScalar(t, s.FillBytes(make([]byte, byteLen)))
|
||||
})
|
||||
}
|
||||
for i := 0; i <= 64; i++ {
|
||||
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
|
||||
checkScalar(t, big.NewInt(int64(i)).FillBytes(make([]byte, byteLen)))
|
||||
})
|
||||
}
|
||||
// Test N-64...N+64 since they risk overlapping with precomputed table values
|
||||
// in the final additions.
|
||||
for i := int64(-64); i <= 64; i++ {
|
||||
t.Run(fmt.Sprintf("N%+d", i), func(t *testing.T) {
|
||||
checkScalar(t, new(big.Int).Add(c.Params().N, big.NewInt(i)).Bytes())
|
||||
})
|
||||
}
|
||||
}
|
||||
454
p224.go
Normal file
454
p224.go
Normal file
@@ -0,0 +1,454 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Code generated by generate.go. DO NOT EDIT.
|
||||
|
||||
package nistec
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"sources.truenas.cloud/code/nistec/internal/fiat"
|
||||
)
|
||||
|
||||
// p224ElementLength is the length of an element of the base or scalar field,
|
||||
// which have the same bytes length for all NIST P curves.
|
||||
const p224ElementLength = 28
|
||||
|
||||
// P224Point is a P224 point. The zero value is NOT valid.
|
||||
type P224Point struct {
|
||||
// The point is represented in projective coordinates (X:Y:Z),
|
||||
// where x = X/Z and y = Y/Z.
|
||||
x, y, z *fiat.P224Element
|
||||
}
|
||||
|
||||
// NewP224Point returns a new P224Point representing the point at infinity point.
|
||||
func NewP224Point() *P224Point {
|
||||
return &P224Point{
|
||||
x: new(fiat.P224Element),
|
||||
y: new(fiat.P224Element).One(),
|
||||
z: new(fiat.P224Element),
|
||||
}
|
||||
}
|
||||
|
||||
// SetGenerator sets p to the canonical generator and returns p.
|
||||
func (p *P224Point) SetGenerator() *P224Point {
|
||||
p.x.SetBytes([]byte{0xb7, 0xe, 0xc, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f, 0x32, 0x13, 0x90, 0xb9, 0x4a, 0x3, 0xc1, 0xd3, 0x56, 0xc2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xd6, 0x11, 0x5c, 0x1d, 0x21})
|
||||
p.y.SetBytes([]byte{0xbd, 0x37, 0x63, 0x88, 0xb5, 0xf7, 0x23, 0xfb, 0x4c, 0x22, 0xdf, 0xe6, 0xcd, 0x43, 0x75, 0xa0, 0x5a, 0x7, 0x47, 0x64, 0x44, 0xd5, 0x81, 0x99, 0x85, 0x0, 0x7e, 0x34})
|
||||
p.z.One()
|
||||
return p
|
||||
}
|
||||
|
||||
// Set sets p = q and returns p.
|
||||
func (p *P224Point) Set(q *P224Point) *P224Point {
|
||||
p.x.Set(q.x)
|
||||
p.y.Set(q.y)
|
||||
p.z.Set(q.z)
|
||||
return p
|
||||
}
|
||||
|
||||
// SetBytes sets p to the compressed, uncompressed, or infinity value encoded in
|
||||
// b, as specified in SEC 1, Version 2.0, Section 2.3.4. If the point is not on
|
||||
// the curve, it returns nil and an error, and the receiver is unchanged.
|
||||
// Otherwise, it returns p.
|
||||
func (p *P224Point) SetBytes(b []byte) (*P224Point, error) {
|
||||
switch {
|
||||
// Point at infinity.
|
||||
case len(b) == 1 && b[0] == 0:
|
||||
return p.Set(NewP224Point()), nil
|
||||
|
||||
// Uncompressed form.
|
||||
case len(b) == 1+2*p224ElementLength && b[0] == 4:
|
||||
x, err := new(fiat.P224Element).SetBytes(b[1 : 1+p224ElementLength])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
y, err := new(fiat.P224Element).SetBytes(b[1+p224ElementLength:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := p224CheckOnCurve(x, y); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.x.Set(x)
|
||||
p.y.Set(y)
|
||||
p.z.One()
|
||||
return p, nil
|
||||
|
||||
// Compressed form.
|
||||
case len(b) == 1+p224ElementLength && (b[0] == 2 || b[0] == 3):
|
||||
x, err := new(fiat.P224Element).SetBytes(b[1:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// y² = x³ - 3x + b
|
||||
y := p224Polynomial(new(fiat.P224Element), x)
|
||||
if !p224Sqrt(y, y) {
|
||||
return nil, errors.New("invalid P224 compressed point encoding")
|
||||
}
|
||||
|
||||
// Select the positive or negative root, as indicated by the least
|
||||
// significant bit, based on the encoding type byte.
|
||||
otherRoot := new(fiat.P224Element)
|
||||
otherRoot.Sub(otherRoot, y)
|
||||
cond := y.Bytes()[p224ElementLength-1]&1 ^ b[0]&1
|
||||
y.Select(otherRoot, y, int(cond))
|
||||
|
||||
p.x.Set(x)
|
||||
p.y.Set(y)
|
||||
p.z.One()
|
||||
return p, nil
|
||||
|
||||
default:
|
||||
return nil, errors.New("invalid P224 point encoding")
|
||||
}
|
||||
}
|
||||
|
||||
var _p224B *fiat.P224Element
|
||||
var _p224BOnce sync.Once
|
||||
|
||||
func p224B() *fiat.P224Element {
|
||||
_p224BOnce.Do(func() {
|
||||
_p224B, _ = new(fiat.P224Element).SetBytes([]byte{0xb4, 0x5, 0xa, 0x85, 0xc, 0x4, 0xb3, 0xab, 0xf5, 0x41, 0x32, 0x56, 0x50, 0x44, 0xb0, 0xb7, 0xd7, 0xbf, 0xd8, 0xba, 0x27, 0xb, 0x39, 0x43, 0x23, 0x55, 0xff, 0xb4})
|
||||
})
|
||||
return _p224B
|
||||
}
|
||||
|
||||
// p224Polynomial sets y2 to x³ - 3x + b, and returns y2.
|
||||
func p224Polynomial(y2, x *fiat.P224Element) *fiat.P224Element {
|
||||
y2.Square(x)
|
||||
y2.Mul(y2, x)
|
||||
|
||||
threeX := new(fiat.P224Element).Add(x, x)
|
||||
threeX.Add(threeX, x)
|
||||
y2.Sub(y2, threeX)
|
||||
|
||||
return y2.Add(y2, p224B())
|
||||
}
|
||||
|
||||
func p224CheckOnCurve(x, y *fiat.P224Element) error {
|
||||
// y² = x³ - 3x + b
|
||||
rhs := p224Polynomial(new(fiat.P224Element), x)
|
||||
lhs := new(fiat.P224Element).Square(y)
|
||||
if rhs.Equal(lhs) != 1 {
|
||||
return errors.New("P224 point not on curve")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Bytes returns the uncompressed or infinity encoding of p, as specified in
|
||||
// SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the point at
|
||||
// infinity is shorter than all other encodings.
|
||||
func (p *P224Point) Bytes() []byte {
|
||||
// This function is outlined to make the allocations inline in the caller
|
||||
// rather than happen on the heap.
|
||||
var out [1 + 2*p224ElementLength]byte
|
||||
return p.bytes(&out)
|
||||
}
|
||||
|
||||
func (p *P224Point) bytes(out *[1 + 2*p224ElementLength]byte) []byte {
|
||||
if p.z.IsZero() == 1 {
|
||||
return append(out[:0], 0)
|
||||
}
|
||||
|
||||
zinv := new(fiat.P224Element).Invert(p.z)
|
||||
x := new(fiat.P224Element).Mul(p.x, zinv)
|
||||
y := new(fiat.P224Element).Mul(p.y, zinv)
|
||||
|
||||
buf := append(out[:0], 4)
|
||||
buf = append(buf, x.Bytes()...)
|
||||
buf = append(buf, y.Bytes()...)
|
||||
return buf
|
||||
}
|
||||
|
||||
// BytesX returns the encoding of the x-coordinate of p, as specified in SEC 1,
|
||||
// Version 2.0, Section 2.3.5, or an error if p is the point at infinity.
|
||||
func (p *P224Point) BytesX() ([]byte, error) {
|
||||
// This function is outlined to make the allocations inline in the caller
|
||||
// rather than happen on the heap.
|
||||
var out [p224ElementLength]byte
|
||||
return p.bytesX(&out)
|
||||
}
|
||||
|
||||
func (p *P224Point) bytesX(out *[p224ElementLength]byte) ([]byte, error) {
|
||||
if p.z.IsZero() == 1 {
|
||||
return nil, errors.New("P224 point is the point at infinity")
|
||||
}
|
||||
|
||||
zinv := new(fiat.P224Element).Invert(p.z)
|
||||
x := new(fiat.P224Element).Mul(p.x, zinv)
|
||||
|
||||
return append(out[:0], x.Bytes()...), nil
|
||||
}
|
||||
|
||||
// BytesCompressed returns the compressed or infinity encoding of p, as
|
||||
// specified in SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the
|
||||
// point at infinity is shorter than all other encodings.
|
||||
func (p *P224Point) BytesCompressed() []byte {
|
||||
// This function is outlined to make the allocations inline in the caller
|
||||
// rather than happen on the heap.
|
||||
var out [1 + p224ElementLength]byte
|
||||
return p.bytesCompressed(&out)
|
||||
}
|
||||
|
||||
func (p *P224Point) bytesCompressed(out *[1 + p224ElementLength]byte) []byte {
|
||||
if p.z.IsZero() == 1 {
|
||||
return append(out[:0], 0)
|
||||
}
|
||||
|
||||
zinv := new(fiat.P224Element).Invert(p.z)
|
||||
x := new(fiat.P224Element).Mul(p.x, zinv)
|
||||
y := new(fiat.P224Element).Mul(p.y, zinv)
|
||||
|
||||
// Encode the sign of the y coordinate (indicated by the least significant
|
||||
// bit) as the encoding type (2 or 3).
|
||||
buf := append(out[:0], 2)
|
||||
buf[0] |= y.Bytes()[p224ElementLength-1] & 1
|
||||
buf = append(buf, x.Bytes()...)
|
||||
return buf
|
||||
}
|
||||
|
||||
// Add sets q = p1 + p2, and returns q. The points may overlap.
|
||||
func (q *P224Point) Add(p1, p2 *P224Point) *P224Point {
|
||||
// Complete addition formula for a = -3 from "Complete addition formulas for
|
||||
// prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2.
|
||||
|
||||
t0 := new(fiat.P224Element).Mul(p1.x, p2.x) // t0 := X1 * X2
|
||||
t1 := new(fiat.P224Element).Mul(p1.y, p2.y) // t1 := Y1 * Y2
|
||||
t2 := new(fiat.P224Element).Mul(p1.z, p2.z) // t2 := Z1 * Z2
|
||||
t3 := new(fiat.P224Element).Add(p1.x, p1.y) // t3 := X1 + Y1
|
||||
t4 := new(fiat.P224Element).Add(p2.x, p2.y) // t4 := X2 + Y2
|
||||
t3.Mul(t3, t4) // t3 := t3 * t4
|
||||
t4.Add(t0, t1) // t4 := t0 + t1
|
||||
t3.Sub(t3, t4) // t3 := t3 - t4
|
||||
t4.Add(p1.y, p1.z) // t4 := Y1 + Z1
|
||||
x3 := new(fiat.P224Element).Add(p2.y, p2.z) // X3 := Y2 + Z2
|
||||
t4.Mul(t4, x3) // t4 := t4 * X3
|
||||
x3.Add(t1, t2) // X3 := t1 + t2
|
||||
t4.Sub(t4, x3) // t4 := t4 - X3
|
||||
x3.Add(p1.x, p1.z) // X3 := X1 + Z1
|
||||
y3 := new(fiat.P224Element).Add(p2.x, p2.z) // Y3 := X2 + Z2
|
||||
x3.Mul(x3, y3) // X3 := X3 * Y3
|
||||
y3.Add(t0, t2) // Y3 := t0 + t2
|
||||
y3.Sub(x3, y3) // Y3 := X3 - Y3
|
||||
z3 := new(fiat.P224Element).Mul(p224B(), t2) // Z3 := b * t2
|
||||
x3.Sub(y3, z3) // X3 := Y3 - Z3
|
||||
z3.Add(x3, x3) // Z3 := X3 + X3
|
||||
x3.Add(x3, z3) // X3 := X3 + Z3
|
||||
z3.Sub(t1, x3) // Z3 := t1 - X3
|
||||
x3.Add(t1, x3) // X3 := t1 + X3
|
||||
y3.Mul(p224B(), y3) // Y3 := b * Y3
|
||||
t1.Add(t2, t2) // t1 := t2 + t2
|
||||
t2.Add(t1, t2) // t2 := t1 + t2
|
||||
y3.Sub(y3, t2) // Y3 := Y3 - t2
|
||||
y3.Sub(y3, t0) // Y3 := Y3 - t0
|
||||
t1.Add(y3, y3) // t1 := Y3 + Y3
|
||||
y3.Add(t1, y3) // Y3 := t1 + Y3
|
||||
t1.Add(t0, t0) // t1 := t0 + t0
|
||||
t0.Add(t1, t0) // t0 := t1 + t0
|
||||
t0.Sub(t0, t2) // t0 := t0 - t2
|
||||
t1.Mul(t4, y3) // t1 := t4 * Y3
|
||||
t2.Mul(t0, y3) // t2 := t0 * Y3
|
||||
y3.Mul(x3, z3) // Y3 := X3 * Z3
|
||||
y3.Add(y3, t2) // Y3 := Y3 + t2
|
||||
x3.Mul(t3, x3) // X3 := t3 * X3
|
||||
x3.Sub(x3, t1) // X3 := X3 - t1
|
||||
z3.Mul(t4, z3) // Z3 := t4 * Z3
|
||||
t1.Mul(t3, t0) // t1 := t3 * t0
|
||||
z3.Add(z3, t1) // Z3 := Z3 + t1
|
||||
|
||||
q.x.Set(x3)
|
||||
q.y.Set(y3)
|
||||
q.z.Set(z3)
|
||||
return q
|
||||
}
|
||||
|
||||
// Double sets q = p + p, and returns q. The points may overlap.
|
||||
func (q *P224Point) Double(p *P224Point) *P224Point {
|
||||
// Complete addition formula for a = -3 from "Complete addition formulas for
|
||||
// prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2.
|
||||
|
||||
t0 := new(fiat.P224Element).Square(p.x) // t0 := X ^ 2
|
||||
t1 := new(fiat.P224Element).Square(p.y) // t1 := Y ^ 2
|
||||
t2 := new(fiat.P224Element).Square(p.z) // t2 := Z ^ 2
|
||||
t3 := new(fiat.P224Element).Mul(p.x, p.y) // t3 := X * Y
|
||||
t3.Add(t3, t3) // t3 := t3 + t3
|
||||
z3 := new(fiat.P224Element).Mul(p.x, p.z) // Z3 := X * Z
|
||||
z3.Add(z3, z3) // Z3 := Z3 + Z3
|
||||
y3 := new(fiat.P224Element).Mul(p224B(), t2) // Y3 := b * t2
|
||||
y3.Sub(y3, z3) // Y3 := Y3 - Z3
|
||||
x3 := new(fiat.P224Element).Add(y3, y3) // X3 := Y3 + Y3
|
||||
y3.Add(x3, y3) // Y3 := X3 + Y3
|
||||
x3.Sub(t1, y3) // X3 := t1 - Y3
|
||||
y3.Add(t1, y3) // Y3 := t1 + Y3
|
||||
y3.Mul(x3, y3) // Y3 := X3 * Y3
|
||||
x3.Mul(x3, t3) // X3 := X3 * t3
|
||||
t3.Add(t2, t2) // t3 := t2 + t2
|
||||
t2.Add(t2, t3) // t2 := t2 + t3
|
||||
z3.Mul(p224B(), z3) // Z3 := b * Z3
|
||||
z3.Sub(z3, t2) // Z3 := Z3 - t2
|
||||
z3.Sub(z3, t0) // Z3 := Z3 - t0
|
||||
t3.Add(z3, z3) // t3 := Z3 + Z3
|
||||
z3.Add(z3, t3) // Z3 := Z3 + t3
|
||||
t3.Add(t0, t0) // t3 := t0 + t0
|
||||
t0.Add(t3, t0) // t0 := t3 + t0
|
||||
t0.Sub(t0, t2) // t0 := t0 - t2
|
||||
t0.Mul(t0, z3) // t0 := t0 * Z3
|
||||
y3.Add(y3, t0) // Y3 := Y3 + t0
|
||||
t0.Mul(p.y, p.z) // t0 := Y * Z
|
||||
t0.Add(t0, t0) // t0 := t0 + t0
|
||||
z3.Mul(t0, z3) // Z3 := t0 * Z3
|
||||
x3.Sub(x3, z3) // X3 := X3 - Z3
|
||||
z3.Mul(t0, t1) // Z3 := t0 * t1
|
||||
z3.Add(z3, z3) // Z3 := Z3 + Z3
|
||||
z3.Add(z3, z3) // Z3 := Z3 + Z3
|
||||
|
||||
q.x.Set(x3)
|
||||
q.y.Set(y3)
|
||||
q.z.Set(z3)
|
||||
return q
|
||||
}
|
||||
|
||||
// Select sets q to p1 if cond == 1, and to p2 if cond == 0.
|
||||
func (q *P224Point) Select(p1, p2 *P224Point, cond int) *P224Point {
|
||||
q.x.Select(p1.x, p2.x, cond)
|
||||
q.y.Select(p1.y, p2.y, cond)
|
||||
q.z.Select(p1.z, p2.z, cond)
|
||||
return q
|
||||
}
|
||||
|
||||
// A p224Table holds the first 15 multiples of a point at offset -1, so [1]P
|
||||
// is at table[0], [15]P is at table[14], and [0]P is implicitly the identity
|
||||
// point.
|
||||
type p224Table [15]*P224Point
|
||||
|
||||
// Select selects the n-th multiple of the table base point into p. It works in
|
||||
// constant time by iterating over every entry of the table. n must be in [0, 15].
|
||||
func (table *p224Table) Select(p *P224Point, n uint8) {
|
||||
if n >= 16 {
|
||||
panic("nistec: internal error: p224Table called with out-of-bounds value")
|
||||
}
|
||||
p.Set(NewP224Point())
|
||||
for i := uint8(1); i < 16; i++ {
|
||||
cond := subtle.ConstantTimeByteEq(i, n)
|
||||
p.Select(table[i-1], p, cond)
|
||||
}
|
||||
}
|
||||
|
||||
// ScalarMult sets p = scalar * q, and returns p.
|
||||
func (p *P224Point) ScalarMult(q *P224Point, scalar []byte) (*P224Point, error) {
|
||||
// Compute a p224Table for the base point q. The explicit NewP224Point
|
||||
// calls get inlined, letting the allocations live on the stack.
|
||||
var table = p224Table{NewP224Point(), NewP224Point(), NewP224Point(),
|
||||
NewP224Point(), NewP224Point(), NewP224Point(), NewP224Point(),
|
||||
NewP224Point(), NewP224Point(), NewP224Point(), NewP224Point(),
|
||||
NewP224Point(), NewP224Point(), NewP224Point(), NewP224Point()}
|
||||
table[0].Set(q)
|
||||
for i := 1; i < 15; i += 2 {
|
||||
table[i].Double(table[i/2])
|
||||
table[i+1].Add(table[i], q)
|
||||
}
|
||||
|
||||
// Instead of doing the classic double-and-add chain, we do it with a
|
||||
// four-bit window: we double four times, and then add [0-15]P.
|
||||
t := NewP224Point()
|
||||
p.Set(NewP224Point())
|
||||
for i, byte := range scalar {
|
||||
// No need to double on the first iteration, as p is the identity at
|
||||
// this point, and [N]∞ = ∞.
|
||||
if i != 0 {
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
}
|
||||
|
||||
windowValue := byte >> 4
|
||||
table.Select(t, windowValue)
|
||||
p.Add(p, t)
|
||||
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
|
||||
windowValue = byte & 0b1111
|
||||
table.Select(t, windowValue)
|
||||
p.Add(p, t)
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
var p224GeneratorTable *[p224ElementLength * 2]p224Table
|
||||
var p224GeneratorTableOnce sync.Once
|
||||
|
||||
// generatorTable returns a sequence of p224Tables. The first table contains
|
||||
// multiples of G. Each successive table is the previous table doubled four
|
||||
// times.
|
||||
func (p *P224Point) generatorTable() *[p224ElementLength * 2]p224Table {
|
||||
p224GeneratorTableOnce.Do(func() {
|
||||
p224GeneratorTable = new([p224ElementLength * 2]p224Table)
|
||||
base := NewP224Point().SetGenerator()
|
||||
for i := 0; i < p224ElementLength*2; i++ {
|
||||
p224GeneratorTable[i][0] = NewP224Point().Set(base)
|
||||
for j := 1; j < 15; j++ {
|
||||
p224GeneratorTable[i][j] = NewP224Point().Add(p224GeneratorTable[i][j-1], base)
|
||||
}
|
||||
base.Double(base)
|
||||
base.Double(base)
|
||||
base.Double(base)
|
||||
base.Double(base)
|
||||
}
|
||||
})
|
||||
return p224GeneratorTable
|
||||
}
|
||||
|
||||
// ScalarBaseMult sets p = scalar * B, where B is the canonical generator, and
|
||||
// returns p.
|
||||
func (p *P224Point) ScalarBaseMult(scalar []byte) (*P224Point, error) {
|
||||
if len(scalar) != p224ElementLength {
|
||||
return nil, errors.New("invalid scalar length")
|
||||
}
|
||||
tables := p.generatorTable()
|
||||
|
||||
// This is also a scalar multiplication with a four-bit window like in
|
||||
// ScalarMult, but in this case the doublings are precomputed. The value
|
||||
// [windowValue]G added at iteration k would normally get doubled
|
||||
// (totIterations-k)×4 times, but with a larger precomputation we can
|
||||
// instead add [2^((totIterations-k)×4)][windowValue]G and avoid the
|
||||
// doublings between iterations.
|
||||
t := NewP224Point()
|
||||
p.Set(NewP224Point())
|
||||
tableIndex := len(tables) - 1
|
||||
for _, byte := range scalar {
|
||||
windowValue := byte >> 4
|
||||
tables[tableIndex].Select(t, windowValue)
|
||||
p.Add(p, t)
|
||||
tableIndex--
|
||||
|
||||
windowValue = byte & 0b1111
|
||||
tables[tableIndex].Select(t, windowValue)
|
||||
p.Add(p, t)
|
||||
tableIndex--
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// p224Sqrt sets e to a square root of x. If x is not a square, p224Sqrt returns
|
||||
// false and e is unchanged. e and x can overlap.
|
||||
func p224Sqrt(e, x *fiat.P224Element) (isSquare bool) {
|
||||
candidate := new(fiat.P224Element)
|
||||
p224SqrtCandidate(candidate, x)
|
||||
square := new(fiat.P224Element).Square(candidate)
|
||||
if square.Equal(x) != 1 {
|
||||
return false
|
||||
}
|
||||
e.Set(candidate)
|
||||
return true
|
||||
}
|
||||
133
p224_sqrt.go
Normal file
133
p224_sqrt.go
Normal file
@@ -0,0 +1,133 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package nistec
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"sources.truenas.cloud/code/nistec/internal/fiat"
|
||||
)
|
||||
|
||||
var p224GG *[96]fiat.P224Element
|
||||
var p224GGOnce sync.Once
|
||||
|
||||
// p224SqrtCandidate sets r to a square root candidate for x. r and x must not overlap.
|
||||
func p224SqrtCandidate(r, x *fiat.P224Element) {
|
||||
// Since p = 1 mod 4, we can't use the exponentiation by (p + 1) / 4 like
|
||||
// for the other primes. Instead, implement a variation of Tonelli–Shanks.
|
||||
// The constant-time implementation is adapted from Thomas Pornin's ecGFp5.
|
||||
//
|
||||
// https://github.com/pornin/ecgfp5/blob/82325b965/rust/src/field.rs#L337-L385
|
||||
|
||||
// p = q*2^n + 1 with q odd -> q = 2^128 - 1 and n = 96
|
||||
// g^(2^n) = 1 -> g = 11 ^ q (where 11 is the smallest non-square)
|
||||
// GG[j] = g^(2^j) for j = 0 to n-1
|
||||
|
||||
p224GGOnce.Do(func() {
|
||||
p224GG = new([96]fiat.P224Element)
|
||||
for i := range p224GG {
|
||||
if i == 0 {
|
||||
p224GG[i].SetBytes([]byte{0x6a, 0x0f, 0xec, 0x67,
|
||||
0x85, 0x98, 0xa7, 0x92, 0x0c, 0x55, 0xb2, 0xd4,
|
||||
0x0b, 0x2d, 0x6f, 0xfb, 0xbe, 0xa3, 0xd8, 0xce,
|
||||
0xf3, 0xfb, 0x36, 0x32, 0xdc, 0x69, 0x1b, 0x74})
|
||||
} else {
|
||||
p224GG[i].Square(&p224GG[i-1])
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// r <- x^((q+1)/2) = x^(2^127)
|
||||
// v <- x^q = x^(2^128-1)
|
||||
|
||||
// Compute x^(2^127-1) first.
|
||||
//
|
||||
// The sequence of 10 multiplications and 126 squarings is derived from the
|
||||
// following addition chain generated with github.com/mmcloughlin/addchain v0.4.0.
|
||||
//
|
||||
// _10 = 2*1
|
||||
// _11 = 1 + _10
|
||||
// _110 = 2*_11
|
||||
// _111 = 1 + _110
|
||||
// _111000 = _111 << 3
|
||||
// _111111 = _111 + _111000
|
||||
// _1111110 = 2*_111111
|
||||
// _1111111 = 1 + _1111110
|
||||
// x12 = _1111110 << 5 + _111111
|
||||
// x24 = x12 << 12 + x12
|
||||
// i36 = x24 << 7
|
||||
// x31 = _1111111 + i36
|
||||
// x48 = i36 << 17 + x24
|
||||
// x96 = x48 << 48 + x48
|
||||
// return x96 << 31 + x31
|
||||
//
|
||||
var t0 = new(fiat.P224Element)
|
||||
var t1 = new(fiat.P224Element)
|
||||
|
||||
r.Square(x)
|
||||
r.Mul(x, r)
|
||||
r.Square(r)
|
||||
r.Mul(x, r)
|
||||
t0.Square(r)
|
||||
for s := 1; s < 3; s++ {
|
||||
t0.Square(t0)
|
||||
}
|
||||
t0.Mul(r, t0)
|
||||
t1.Square(t0)
|
||||
r.Mul(x, t1)
|
||||
for s := 0; s < 5; s++ {
|
||||
t1.Square(t1)
|
||||
}
|
||||
t0.Mul(t0, t1)
|
||||
t1.Square(t0)
|
||||
for s := 1; s < 12; s++ {
|
||||
t1.Square(t1)
|
||||
}
|
||||
t0.Mul(t0, t1)
|
||||
t1.Square(t0)
|
||||
for s := 1; s < 7; s++ {
|
||||
t1.Square(t1)
|
||||
}
|
||||
r.Mul(r, t1)
|
||||
for s := 0; s < 17; s++ {
|
||||
t1.Square(t1)
|
||||
}
|
||||
t0.Mul(t0, t1)
|
||||
t1.Square(t0)
|
||||
for s := 1; s < 48; s++ {
|
||||
t1.Square(t1)
|
||||
}
|
||||
t0.Mul(t0, t1)
|
||||
for s := 0; s < 31; s++ {
|
||||
t0.Square(t0)
|
||||
}
|
||||
r.Mul(r, t0)
|
||||
|
||||
// v = x^(2^127-1)^2 * x
|
||||
v := new(fiat.P224Element).Square(r)
|
||||
v.Mul(v, x)
|
||||
|
||||
// r = x^(2^127-1) * x
|
||||
r.Mul(r, x)
|
||||
|
||||
// for i = n-1 down to 1:
|
||||
// w = v^(2^(i-1))
|
||||
// if w == -1 then:
|
||||
// v <- v*GG[n-i]
|
||||
// r <- r*GG[n-i-1]
|
||||
|
||||
var p224MinusOne = new(fiat.P224Element).Sub(
|
||||
new(fiat.P224Element), new(fiat.P224Element).One())
|
||||
|
||||
for i := 96 - 1; i >= 1; i-- {
|
||||
w := new(fiat.P224Element).Set(v)
|
||||
for j := 0; j < i-1; j++ {
|
||||
w.Square(w)
|
||||
}
|
||||
cond := w.Equal(p224MinusOne)
|
||||
v.Select(t0.Mul(v, &p224GG[96-i]), v, cond)
|
||||
r.Select(t0.Mul(r, &p224GG[96-i-1]), r, cond)
|
||||
}
|
||||
}
|
||||
706
p256.go
Normal file
706
p256.go
Normal file
@@ -0,0 +1,706 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build (!amd64 && !arm64 && !ppc64le && !s390x) || purego
|
||||
|
||||
package nistec
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
"math/bits"
|
||||
"sync"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/cpu"
|
||||
"sources.truenas.cloud/code/nistec/internal/byteorder"
|
||||
"sources.truenas.cloud/code/nistec/internal/fiat"
|
||||
)
|
||||
|
||||
// P256Point is a P-256 point. The zero value is NOT valid.
|
||||
type P256Point struct {
|
||||
// The point is represented in projective coordinates (X:Y:Z), where x = X/Z
|
||||
// and y = Y/Z. Infinity is (0:1:0).
|
||||
//
|
||||
// fiat.P256Element is a base field element in [0, P-1] in the Montgomery
|
||||
// domain (with R 2²⁵⁶ and P 2²⁵⁶ - 2²²⁴ + 2¹⁹² + 2⁹⁶ - 1) as four limbs in
|
||||
// little-endian order value.
|
||||
x, y, z fiat.P256Element
|
||||
}
|
||||
|
||||
// NewP256Point returns a new P256Point representing the point at infinity point.
|
||||
func NewP256Point() *P256Point {
|
||||
p := &P256Point{}
|
||||
p.y.One()
|
||||
return p
|
||||
}
|
||||
|
||||
// SetGenerator sets p to the canonical generator and returns p.
|
||||
func (p *P256Point) SetGenerator() *P256Point {
|
||||
p.x.SetBytes([]byte{0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x3, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96})
|
||||
p.y.SetBytes([]byte{0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0xf, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5})
|
||||
p.z.One()
|
||||
return p
|
||||
}
|
||||
|
||||
// Set sets p = q and returns p.
|
||||
func (p *P256Point) Set(q *P256Point) *P256Point {
|
||||
p.x.Set(&q.x)
|
||||
p.y.Set(&q.y)
|
||||
p.z.Set(&q.z)
|
||||
return p
|
||||
}
|
||||
|
||||
const p256ElementLength = 32
|
||||
const p256UncompressedLength = 1 + 2*p256ElementLength
|
||||
const p256CompressedLength = 1 + p256ElementLength
|
||||
|
||||
// SetBytes sets p to the compressed, uncompressed, or infinity value encoded in
|
||||
// b, as specified in SEC 1, Version 2.0, Section 2.3.4. If the point is not on
|
||||
// the curve, it returns nil and an error, and the receiver is unchanged.
|
||||
// Otherwise, it returns p.
|
||||
func (p *P256Point) SetBytes(b []byte) (*P256Point, error) {
|
||||
switch {
|
||||
// Point at infinity.
|
||||
case len(b) == 1 && b[0] == 0:
|
||||
return p.Set(NewP256Point()), nil
|
||||
|
||||
// Uncompressed form.
|
||||
case len(b) == p256UncompressedLength && b[0] == 4:
|
||||
x, err := new(fiat.P256Element).SetBytes(b[1 : 1+p256ElementLength])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
y, err := new(fiat.P256Element).SetBytes(b[1+p256ElementLength:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := p256CheckOnCurve(x, y); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.x.Set(x)
|
||||
p.y.Set(y)
|
||||
p.z.One()
|
||||
return p, nil
|
||||
|
||||
// Compressed form.
|
||||
case len(b) == p256CompressedLength && (b[0] == 2 || b[0] == 3):
|
||||
x, err := new(fiat.P256Element).SetBytes(b[1:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// y² = x³ - 3x + b
|
||||
y := p256Polynomial(new(fiat.P256Element), x)
|
||||
if !p256Sqrt(y, y) {
|
||||
return nil, errors.New("invalid P256 compressed point encoding")
|
||||
}
|
||||
|
||||
// Select the positive or negative root, as indicated by the least
|
||||
// significant bit, based on the encoding type byte.
|
||||
otherRoot := new(fiat.P256Element)
|
||||
otherRoot.Sub(otherRoot, y)
|
||||
cond := y.Bytes()[p256ElementLength-1]&1 ^ b[0]&1
|
||||
y.Select(otherRoot, y, int(cond))
|
||||
|
||||
p.x.Set(x)
|
||||
p.y.Set(y)
|
||||
p.z.One()
|
||||
return p, nil
|
||||
|
||||
default:
|
||||
return nil, errors.New("invalid P256 point encoding")
|
||||
}
|
||||
}
|
||||
|
||||
var _p256B *fiat.P256Element
|
||||
var _p256BOnce sync.Once
|
||||
|
||||
func p256B() *fiat.P256Element {
|
||||
_p256BOnce.Do(func() {
|
||||
_p256B, _ = new(fiat.P256Element).SetBytes([]byte{0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb, 0xbd, 0x55, 0x76, 0x98, 0x86, 0xbc, 0x65, 0x1d, 0x6, 0xb0, 0xcc, 0x53, 0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b})
|
||||
})
|
||||
return _p256B
|
||||
}
|
||||
|
||||
// p256Polynomial sets y2 to x³ - 3x + b, and returns y2.
|
||||
func p256Polynomial(y2, x *fiat.P256Element) *fiat.P256Element {
|
||||
y2.Square(x)
|
||||
y2.Mul(y2, x)
|
||||
|
||||
threeX := new(fiat.P256Element).Add(x, x)
|
||||
threeX.Add(threeX, x)
|
||||
y2.Sub(y2, threeX)
|
||||
|
||||
return y2.Add(y2, p256B())
|
||||
}
|
||||
|
||||
func p256CheckOnCurve(x, y *fiat.P256Element) error {
|
||||
// y² = x³ - 3x + b
|
||||
rhs := p256Polynomial(new(fiat.P256Element), x)
|
||||
lhs := new(fiat.P256Element).Square(y)
|
||||
if rhs.Equal(lhs) != 1 {
|
||||
return errors.New("P256 point not on curve")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Bytes returns the uncompressed or infinity encoding of p, as specified in
|
||||
// SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the point at
|
||||
// infinity is shorter than all other encodings.
|
||||
func (p *P256Point) Bytes() []byte {
|
||||
// This function is outlined to make the allocations inline in the caller
|
||||
// rather than happen on the heap.
|
||||
var out [p256UncompressedLength]byte
|
||||
return p.bytes(&out)
|
||||
}
|
||||
|
||||
func (p *P256Point) bytes(out *[p256UncompressedLength]byte) []byte {
|
||||
// The SEC 1 representation of the point at infinity is a single zero byte,
|
||||
// and only infinity has z = 0.
|
||||
if p.z.IsZero() == 1 {
|
||||
return append(out[:0], 0)
|
||||
}
|
||||
|
||||
zinv := new(fiat.P256Element).Invert(&p.z)
|
||||
x := new(fiat.P256Element).Mul(&p.x, zinv)
|
||||
y := new(fiat.P256Element).Mul(&p.y, zinv)
|
||||
|
||||
buf := append(out[:0], 4)
|
||||
buf = append(buf, x.Bytes()...)
|
||||
buf = append(buf, y.Bytes()...)
|
||||
return buf
|
||||
}
|
||||
|
||||
// BytesX returns the encoding of the x-coordinate of p, as specified in SEC 1,
|
||||
// Version 2.0, Section 2.3.5, or an error if p is the point at infinity.
|
||||
func (p *P256Point) BytesX() ([]byte, error) {
|
||||
// This function is outlined to make the allocations inline in the caller
|
||||
// rather than happen on the heap.
|
||||
var out [p256ElementLength]byte
|
||||
return p.bytesX(&out)
|
||||
}
|
||||
|
||||
func (p *P256Point) bytesX(out *[p256ElementLength]byte) ([]byte, error) {
|
||||
if p.z.IsZero() == 1 {
|
||||
return nil, errors.New("P256 point is the point at infinity")
|
||||
}
|
||||
|
||||
zinv := new(fiat.P256Element).Invert(&p.z)
|
||||
x := new(fiat.P256Element).Mul(&p.x, zinv)
|
||||
|
||||
return append(out[:0], x.Bytes()...), nil
|
||||
}
|
||||
|
||||
// BytesCompressed returns the compressed or infinity encoding of p, as
|
||||
// specified in SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the
|
||||
// point at infinity is shorter than all other encodings.
|
||||
func (p *P256Point) BytesCompressed() []byte {
|
||||
// This function is outlined to make the allocations inline in the caller
|
||||
// rather than happen on the heap.
|
||||
var out [p256CompressedLength]byte
|
||||
return p.bytesCompressed(&out)
|
||||
}
|
||||
|
||||
func (p *P256Point) bytesCompressed(out *[p256CompressedLength]byte) []byte {
|
||||
if p.z.IsZero() == 1 {
|
||||
return append(out[:0], 0)
|
||||
}
|
||||
|
||||
zinv := new(fiat.P256Element).Invert(&p.z)
|
||||
x := new(fiat.P256Element).Mul(&p.x, zinv)
|
||||
y := new(fiat.P256Element).Mul(&p.y, zinv)
|
||||
|
||||
// Encode the sign of the y coordinate (indicated by the least significant
|
||||
// bit) as the encoding type (2 or 3).
|
||||
buf := append(out[:0], 2)
|
||||
buf[0] |= y.Bytes()[p256ElementLength-1] & 1
|
||||
buf = append(buf, x.Bytes()...)
|
||||
return buf
|
||||
}
|
||||
|
||||
// Add sets q = p1 + p2, and returns q. The points may overlap.
|
||||
func (q *P256Point) Add(p1, p2 *P256Point) *P256Point {
|
||||
// Complete addition formula for a = -3 from "Complete addition formulas for
|
||||
// prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2.
|
||||
|
||||
t0 := new(fiat.P256Element).Mul(&p1.x, &p2.x) // t0 := X1 * X2
|
||||
t1 := new(fiat.P256Element).Mul(&p1.y, &p2.y) // t1 := Y1 * Y2
|
||||
t2 := new(fiat.P256Element).Mul(&p1.z, &p2.z) // t2 := Z1 * Z2
|
||||
t3 := new(fiat.P256Element).Add(&p1.x, &p1.y) // t3 := X1 + Y1
|
||||
t4 := new(fiat.P256Element).Add(&p2.x, &p2.y) // t4 := X2 + Y2
|
||||
t3.Mul(t3, t4) // t3 := t3 * t4
|
||||
t4.Add(t0, t1) // t4 := t0 + t1
|
||||
t3.Sub(t3, t4) // t3 := t3 - t4
|
||||
t4.Add(&p1.y, &p1.z) // t4 := Y1 + Z1
|
||||
x3 := new(fiat.P256Element).Add(&p2.y, &p2.z) // X3 := Y2 + Z2
|
||||
t4.Mul(t4, x3) // t4 := t4 * X3
|
||||
x3.Add(t1, t2) // X3 := t1 + t2
|
||||
t4.Sub(t4, x3) // t4 := t4 - X3
|
||||
x3.Add(&p1.x, &p1.z) // X3 := X1 + Z1
|
||||
y3 := new(fiat.P256Element).Add(&p2.x, &p2.z) // Y3 := X2 + Z2
|
||||
x3.Mul(x3, y3) // X3 := X3 * Y3
|
||||
y3.Add(t0, t2) // Y3 := t0 + t2
|
||||
y3.Sub(x3, y3) // Y3 := X3 - Y3
|
||||
z3 := new(fiat.P256Element).Mul(p256B(), t2) // Z3 := b * t2
|
||||
x3.Sub(y3, z3) // X3 := Y3 - Z3
|
||||
z3.Add(x3, x3) // Z3 := X3 + X3
|
||||
x3.Add(x3, z3) // X3 := X3 + Z3
|
||||
z3.Sub(t1, x3) // Z3 := t1 - X3
|
||||
x3.Add(t1, x3) // X3 := t1 + X3
|
||||
y3.Mul(p256B(), y3) // Y3 := b * Y3
|
||||
t1.Add(t2, t2) // t1 := t2 + t2
|
||||
t2.Add(t1, t2) // t2 := t1 + t2
|
||||
y3.Sub(y3, t2) // Y3 := Y3 - t2
|
||||
y3.Sub(y3, t0) // Y3 := Y3 - t0
|
||||
t1.Add(y3, y3) // t1 := Y3 + Y3
|
||||
y3.Add(t1, y3) // Y3 := t1 + Y3
|
||||
t1.Add(t0, t0) // t1 := t0 + t0
|
||||
t0.Add(t1, t0) // t0 := t1 + t0
|
||||
t0.Sub(t0, t2) // t0 := t0 - t2
|
||||
t1.Mul(t4, y3) // t1 := t4 * Y3
|
||||
t2.Mul(t0, y3) // t2 := t0 * Y3
|
||||
y3.Mul(x3, z3) // Y3 := X3 * Z3
|
||||
y3.Add(y3, t2) // Y3 := Y3 + t2
|
||||
x3.Mul(t3, x3) // X3 := t3 * X3
|
||||
x3.Sub(x3, t1) // X3 := X3 - t1
|
||||
z3.Mul(t4, z3) // Z3 := t4 * Z3
|
||||
t1.Mul(t3, t0) // t1 := t3 * t0
|
||||
z3.Add(z3, t1) // Z3 := Z3 + t1
|
||||
|
||||
q.x.Set(x3)
|
||||
q.y.Set(y3)
|
||||
q.z.Set(z3)
|
||||
return q
|
||||
}
|
||||
|
||||
// Double sets q = p + p, and returns q. The points may overlap.
|
||||
func (q *P256Point) Double(p *P256Point) *P256Point {
|
||||
// Complete addition formula for a = -3 from "Complete addition formulas for
|
||||
// prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2.
|
||||
|
||||
t0 := new(fiat.P256Element).Square(&p.x) // t0 := X ^ 2
|
||||
t1 := new(fiat.P256Element).Square(&p.y) // t1 := Y ^ 2
|
||||
t2 := new(fiat.P256Element).Square(&p.z) // t2 := Z ^ 2
|
||||
t3 := new(fiat.P256Element).Mul(&p.x, &p.y) // t3 := X * Y
|
||||
t3.Add(t3, t3) // t3 := t3 + t3
|
||||
z3 := new(fiat.P256Element).Mul(&p.x, &p.z) // Z3 := X * Z
|
||||
z3.Add(z3, z3) // Z3 := Z3 + Z3
|
||||
y3 := new(fiat.P256Element).Mul(p256B(), t2) // Y3 := b * t2
|
||||
y3.Sub(y3, z3) // Y3 := Y3 - Z3
|
||||
x3 := new(fiat.P256Element).Add(y3, y3) // X3 := Y3 + Y3
|
||||
y3.Add(x3, y3) // Y3 := X3 + Y3
|
||||
x3.Sub(t1, y3) // X3 := t1 - Y3
|
||||
y3.Add(t1, y3) // Y3 := t1 + Y3
|
||||
y3.Mul(x3, y3) // Y3 := X3 * Y3
|
||||
x3.Mul(x3, t3) // X3 := X3 * t3
|
||||
t3.Add(t2, t2) // t3 := t2 + t2
|
||||
t2.Add(t2, t3) // t2 := t2 + t3
|
||||
z3.Mul(p256B(), z3) // Z3 := b * Z3
|
||||
z3.Sub(z3, t2) // Z3 := Z3 - t2
|
||||
z3.Sub(z3, t0) // Z3 := Z3 - t0
|
||||
t3.Add(z3, z3) // t3 := Z3 + Z3
|
||||
z3.Add(z3, t3) // Z3 := Z3 + t3
|
||||
t3.Add(t0, t0) // t3 := t0 + t0
|
||||
t0.Add(t3, t0) // t0 := t3 + t0
|
||||
t0.Sub(t0, t2) // t0 := t0 - t2
|
||||
t0.Mul(t0, z3) // t0 := t0 * Z3
|
||||
y3.Add(y3, t0) // Y3 := Y3 + t0
|
||||
t0.Mul(&p.y, &p.z) // t0 := Y * Z
|
||||
t0.Add(t0, t0) // t0 := t0 + t0
|
||||
z3.Mul(t0, z3) // Z3 := t0 * Z3
|
||||
x3.Sub(x3, z3) // X3 := X3 - Z3
|
||||
z3.Mul(t0, t1) // Z3 := t0 * t1
|
||||
z3.Add(z3, z3) // Z3 := Z3 + Z3
|
||||
z3.Add(z3, z3) // Z3 := Z3 + Z3
|
||||
|
||||
q.x.Set(x3)
|
||||
q.y.Set(y3)
|
||||
q.z.Set(z3)
|
||||
return q
|
||||
}
|
||||
|
||||
// p256AffinePoint is a point in affine coordinates (x, y). x and y are still
|
||||
// Montgomery domain elements. The point can't be the point at infinity.
|
||||
type p256AffinePoint struct {
|
||||
x, y fiat.P256Element
|
||||
}
|
||||
|
||||
func (p *p256AffinePoint) Projective() *P256Point {
|
||||
pp := &P256Point{x: p.x, y: p.y}
|
||||
pp.z.One()
|
||||
return pp
|
||||
}
|
||||
|
||||
// AddAffine sets q = p1 + p2, if infinity == 0, and to p1 if infinity == 1.
|
||||
// p2 can't be the point at infinity as it can't be represented in affine
|
||||
// coordinates, instead callers can set p2 to an arbitrary point and set
|
||||
// infinity to 1.
|
||||
func (q *P256Point) AddAffine(p1 *P256Point, p2 *p256AffinePoint, infinity int) *P256Point {
|
||||
// Complete mixed addition formula for a = -3 from "Complete addition
|
||||
// formulas for prime order elliptic curves"
|
||||
// (https://eprint.iacr.org/2015/1060), Algorithm 5.
|
||||
|
||||
t0 := new(fiat.P256Element).Mul(&p1.x, &p2.x) // t0 ← X1 · X2
|
||||
t1 := new(fiat.P256Element).Mul(&p1.y, &p2.y) // t1 ← Y1 · Y2
|
||||
t3 := new(fiat.P256Element).Add(&p2.x, &p2.y) // t3 ← X2 + Y2
|
||||
t4 := new(fiat.P256Element).Add(&p1.x, &p1.y) // t4 ← X1 + Y1
|
||||
t3.Mul(t3, t4) // t3 ← t3 · t4
|
||||
t4.Add(t0, t1) // t4 ← t0 + t1
|
||||
t3.Sub(t3, t4) // t3 ← t3 − t4
|
||||
t4.Mul(&p2.y, &p1.z) // t4 ← Y2 · Z1
|
||||
t4.Add(t4, &p1.y) // t4 ← t4 + Y1
|
||||
y3 := new(fiat.P256Element).Mul(&p2.x, &p1.z) // Y3 ← X2 · Z1
|
||||
y3.Add(y3, &p1.x) // Y3 ← Y3 + X1
|
||||
z3 := new(fiat.P256Element).Mul(p256B(), &p1.z) // Z3 ← b · Z1
|
||||
x3 := new(fiat.P256Element).Sub(y3, z3) // X3 ← Y3 − Z3
|
||||
z3.Add(x3, x3) // Z3 ← X3 + X3
|
||||
x3.Add(x3, z3) // X3 ← X3 + Z3
|
||||
z3.Sub(t1, x3) // Z3 ← t1 − X3
|
||||
x3.Add(t1, x3) // X3 ← t1 + X3
|
||||
y3.Mul(p256B(), y3) // Y3 ← b · Y3
|
||||
t1.Add(&p1.z, &p1.z) // t1 ← Z1 + Z1
|
||||
t2 := new(fiat.P256Element).Add(t1, &p1.z) // t2 ← t1 + Z1
|
||||
y3.Sub(y3, t2) // Y3 ← Y3 − t2
|
||||
y3.Sub(y3, t0) // Y3 ← Y3 − t0
|
||||
t1.Add(y3, y3) // t1 ← Y3 + Y3
|
||||
y3.Add(t1, y3) // Y3 ← t1 + Y3
|
||||
t1.Add(t0, t0) // t1 ← t0 + t0
|
||||
t0.Add(t1, t0) // t0 ← t1 + t0
|
||||
t0.Sub(t0, t2) // t0 ← t0 − t2
|
||||
t1.Mul(t4, y3) // t1 ← t4 · Y3
|
||||
t2.Mul(t0, y3) // t2 ← t0 · Y3
|
||||
y3.Mul(x3, z3) // Y3 ← X3 · Z3
|
||||
y3.Add(y3, t2) // Y3 ← Y3 + t2
|
||||
x3.Mul(t3, x3) // X3 ← t3 · X3
|
||||
x3.Sub(x3, t1) // X3 ← X3 − t1
|
||||
z3.Mul(t4, z3) // Z3 ← t4 · Z3
|
||||
t1.Mul(t3, t0) // t1 ← t3 · t0
|
||||
z3.Add(z3, t1) // Z3 ← Z3 + t1
|
||||
|
||||
q.x.Select(&p1.x, x3, infinity)
|
||||
q.y.Select(&p1.y, y3, infinity)
|
||||
q.z.Select(&p1.z, z3, infinity)
|
||||
return q
|
||||
}
|
||||
|
||||
// Select sets q to p1 if cond == 1, and to p2 if cond == 0.
|
||||
func (q *P256Point) Select(p1, p2 *P256Point, cond int) *P256Point {
|
||||
q.x.Select(&p1.x, &p2.x, cond)
|
||||
q.y.Select(&p1.y, &p2.y, cond)
|
||||
q.z.Select(&p1.z, &p2.z, cond)
|
||||
return q
|
||||
}
|
||||
|
||||
// p256OrdElement is a P-256 scalar field element in [0, ord(G)-1] in the
|
||||
// Montgomery domain (with R 2²⁵⁶) as four uint64 limbs in little-endian order.
|
||||
type p256OrdElement [4]uint64
|
||||
|
||||
// SetBytes sets s to the big-endian value of x, reducing it as necessary.
|
||||
func (s *p256OrdElement) SetBytes(x []byte) (*p256OrdElement, error) {
|
||||
if len(x) != 32 {
|
||||
return nil, errors.New("invalid scalar length")
|
||||
}
|
||||
|
||||
s[0] = byteorder.BEUint64(x[24:])
|
||||
s[1] = byteorder.BEUint64(x[16:])
|
||||
s[2] = byteorder.BEUint64(x[8:])
|
||||
s[3] = byteorder.BEUint64(x[:])
|
||||
|
||||
// Ensure s is in the range [0, ord(G)-1]. Since 2 * ord(G) > 2²⁵⁶, we can
|
||||
// just conditionally subtract ord(G), keeping the result if it doesn't
|
||||
// underflow.
|
||||
t0, b := bits.Sub64(s[0], 0xf3b9cac2fc632551, 0)
|
||||
t1, b := bits.Sub64(s[1], 0xbce6faada7179e84, b)
|
||||
t2, b := bits.Sub64(s[2], 0xffffffffffffffff, b)
|
||||
t3, b := bits.Sub64(s[3], 0xffffffff00000000, b)
|
||||
tMask := b - 1 // zero if subtraction underflowed
|
||||
s[0] ^= (t0 ^ s[0]) & tMask
|
||||
s[1] ^= (t1 ^ s[1]) & tMask
|
||||
s[2] ^= (t2 ^ s[2]) & tMask
|
||||
s[3] ^= (t3 ^ s[3]) & tMask
|
||||
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *p256OrdElement) Bytes() []byte {
|
||||
var out [32]byte
|
||||
byteorder.BEPutUint64(out[24:], s[0])
|
||||
byteorder.BEPutUint64(out[16:], s[1])
|
||||
byteorder.BEPutUint64(out[8:], s[2])
|
||||
byteorder.BEPutUint64(out[:], s[3])
|
||||
return out[:]
|
||||
}
|
||||
|
||||
// Rsh returns the 64 least significant bits of x >> n. n must be lower
|
||||
// than 256. The value of n leaks through timing side-channels.
|
||||
func (s *p256OrdElement) Rsh(n int) uint64 {
|
||||
i := n / 64
|
||||
n = n % 64
|
||||
res := s[i] >> n
|
||||
// Shift in the more significant limb, if present.
|
||||
if i := i + 1; i < len(s) {
|
||||
res |= s[i] << (64 - n)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// p256Table is a table of the first 16 multiples of a point. Points are stored
|
||||
// at an index offset of -1 so [8]P is at index 7, P is at 0, and [16]P is at 15.
|
||||
// [0]P is the point at infinity and it's not stored.
|
||||
type p256Table [16]P256Point
|
||||
|
||||
// Select selects the n-th multiple of the table base point into p. It works in
|
||||
// constant time. n must be in [0, 16]. If n is 0, p is set to the identity point.
|
||||
func (table *p256Table) Select(p *P256Point, n uint8) {
|
||||
if n > 16 {
|
||||
panic("nistec: internal error: p256Table called with out-of-bounds value")
|
||||
}
|
||||
p.Set(NewP256Point())
|
||||
for i := uint8(1); i <= 16; i++ {
|
||||
cond := subtle.ConstantTimeByteEq(i, n)
|
||||
p.Select(&table[i-1], p, cond)
|
||||
}
|
||||
}
|
||||
|
||||
// Compute populates the table to the first 16 multiples of q.
|
||||
func (table *p256Table) Compute(q *P256Point) *p256Table {
|
||||
table[0].Set(q)
|
||||
for i := 1; i < 16; i += 2 {
|
||||
table[i].Double(&table[i/2])
|
||||
if i+1 < 16 {
|
||||
table[i+1].Add(&table[i], q)
|
||||
}
|
||||
}
|
||||
return table
|
||||
}
|
||||
|
||||
func boothW5(in uint64) (uint8, int) {
|
||||
s := ^((in >> 5) - 1)
|
||||
d := (1 << 6) - in - 1
|
||||
d = (d & s) | (in & (^s))
|
||||
d = (d >> 1) + (d & 1)
|
||||
return uint8(d), int(s & 1)
|
||||
}
|
||||
|
||||
// ScalarMult sets r = scalar * q, where scalar is a 32-byte big endian value,
|
||||
// and returns r. If scalar is not 32 bytes long, ScalarMult returns an error
|
||||
// and the receiver is unchanged.
|
||||
func (p *P256Point) ScalarMult(q *P256Point, scalar []byte) (*P256Point, error) {
|
||||
s, err := new(p256OrdElement).SetBytes(scalar)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Start scanning the window from the most significant bits. We move by
|
||||
// 5 bits at a time and need to finish at -1, so -1 + 5 * 51 = 254.
|
||||
index := 254
|
||||
|
||||
sel, sign := boothW5(s.Rsh(index))
|
||||
// sign is always zero because the boothW5 input here is at
|
||||
// most two bits long, so the top bit is never set.
|
||||
_ = sign
|
||||
|
||||
// Neither Select nor Add have exceptions for the point at infinity /
|
||||
// selector zero, so we don't need to check for it here or in the loop.
|
||||
table := new(p256Table).Compute(q)
|
||||
table.Select(p, sel)
|
||||
|
||||
t := NewP256Point()
|
||||
for index >= 4 {
|
||||
index -= 5
|
||||
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
|
||||
if index >= 0 {
|
||||
sel, sign = boothW5(s.Rsh(index) & 0b111111)
|
||||
} else {
|
||||
// Booth encoding considers a virtual zero bit at index -1,
|
||||
// so we shift left the least significant limb.
|
||||
wvalue := (s[0] << 1) & 0b111111
|
||||
sel, sign = boothW5(wvalue)
|
||||
}
|
||||
|
||||
table.Select(t, sel)
|
||||
p256Negate(t, sign)
|
||||
p.Add(p, t)
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// Negate sets p to -p, if cond == 1, and to p if cond == 0.
|
||||
func p256Negate(p *P256Point, cond int) *P256Point {
|
||||
negY := new(fiat.P256Element)
|
||||
negY.Sub(negY, &p.y)
|
||||
p.y.Select(negY, &p.y, cond)
|
||||
return p
|
||||
}
|
||||
|
||||
// p256AffineTable is a table of the first 32 multiples of a point. Points are
|
||||
// stored at an index offset of -1 like in p256Table, and [0]P is not stored.
|
||||
type p256AffineTable [32]p256AffinePoint
|
||||
|
||||
// Select selects the n-th multiple of the table base point into p. It works in
|
||||
// constant time. n can be in [0, 32], but (unlike p256Table.Select) if n is 0,
|
||||
// p is set to an undefined value.
|
||||
func (table *p256AffineTable) Select(p *p256AffinePoint, n uint8) {
|
||||
if n > 32 {
|
||||
panic("nistec: internal error: p256AffineTable.Select called with out-of-bounds value")
|
||||
}
|
||||
for i := uint8(1); i <= 32; i++ {
|
||||
cond := subtle.ConstantTimeByteEq(i, n)
|
||||
p.x.Select(&table[i-1].x, &p.x, cond)
|
||||
p.y.Select(&table[i-1].y, &p.y, cond)
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
// aliases into p256PrecomputedEmbed.
|
||||
var p256GeneratorTables *[43]p256AffineTable
|
||||
|
||||
func init() {
|
||||
p256GeneratorTablesPtr := unsafe.Pointer(&p256PrecomputedEmbed)
|
||||
if cpu.IsBigEndian {
|
||||
var newTable [43 * 32 * 2 * 4]uint64
|
||||
for i, x := range (*[43 * 32 * 2 * 4][8]byte)(p256GeneratorTablesPtr) {
|
||||
newTable[i] = byteorder.LEUint64(x[:])
|
||||
}
|
||||
p256GeneratorTablesPtr = unsafe.Pointer(&newTable)
|
||||
}
|
||||
p256GeneratorTables = (*[43]p256AffineTable)(p256GeneratorTablesPtr)
|
||||
}
|
||||
|
||||
func boothW6(in uint64) (uint8, int) {
|
||||
s := ^((in >> 6) - 1)
|
||||
d := (1 << 7) - in - 1
|
||||
d = (d & s) | (in & (^s))
|
||||
d = (d >> 1) + (d & 1)
|
||||
return uint8(d), int(s & 1)
|
||||
}
|
||||
|
||||
// ScalarBaseMult sets p = scalar * generator, where scalar is a 32-byte big
|
||||
// endian value, and returns r. If scalar is not 32 bytes long, ScalarBaseMult
|
||||
// returns an error and the receiver is unchanged.
|
||||
func (p *P256Point) ScalarBaseMult(scalar []byte) (*P256Point, error) {
|
||||
// This function works like ScalarMult above, but the table is fixed and
|
||||
// "pre-doubled" for each iteration, so instead of doubling we move to the
|
||||
// next table at each iteration.
|
||||
|
||||
s, err := new(p256OrdElement).SetBytes(scalar)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Start scanning the window from the most significant bits. We move by
|
||||
// 6 bits at a time and need to finish at -1, so -1 + 6 * 42 = 251.
|
||||
index := 251
|
||||
|
||||
sel, sign := boothW6(s.Rsh(index))
|
||||
// sign is always zero because the boothW6 input here is at
|
||||
// most five bits long, so the top bit is never set.
|
||||
_ = sign
|
||||
|
||||
t := &p256AffinePoint{}
|
||||
table := &p256GeneratorTables[(index+1)/6]
|
||||
table.Select(t, sel)
|
||||
|
||||
// Select's output is undefined if the selector is zero, when it should be
|
||||
// the point at infinity (because infinity can't be represented in affine
|
||||
// coordinates). Here we conditionally set p to the infinity if sel is zero.
|
||||
// In the loop, that's handled by AddAffine.
|
||||
selIsZero := subtle.ConstantTimeByteEq(sel, 0)
|
||||
p.Select(NewP256Point(), t.Projective(), selIsZero)
|
||||
|
||||
for index >= 5 {
|
||||
index -= 6
|
||||
|
||||
if index >= 0 {
|
||||
sel, sign = boothW6(s.Rsh(index) & 0b1111111)
|
||||
} else {
|
||||
// Booth encoding considers a virtual zero bit at index -1,
|
||||
// so we shift left the least significant limb.
|
||||
wvalue := (s[0] << 1) & 0b1111111
|
||||
sel, sign = boothW6(wvalue)
|
||||
}
|
||||
|
||||
table := &p256GeneratorTables[(index+1)/6]
|
||||
table.Select(t, sel)
|
||||
t.Negate(sign)
|
||||
selIsZero := subtle.ConstantTimeByteEq(sel, 0)
|
||||
p.AddAffine(p, t, selIsZero)
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// Negate sets p to -p, if cond == 1, and to p if cond == 0.
|
||||
func (p *p256AffinePoint) Negate(cond int) *p256AffinePoint {
|
||||
negY := new(fiat.P256Element)
|
||||
negY.Sub(negY, &p.y)
|
||||
p.y.Select(negY, &p.y, cond)
|
||||
return p
|
||||
}
|
||||
|
||||
// p256Sqrt sets e to a square root of x. If x is not a square, p256Sqrt returns
|
||||
// false and e is unchanged. e and x can overlap.
|
||||
func p256Sqrt(e, x *fiat.P256Element) (isSquare bool) {
|
||||
t0, t1 := new(fiat.P256Element), new(fiat.P256Element)
|
||||
|
||||
// Since p = 3 mod 4, exponentiation by (p + 1) / 4 yields a square root candidate.
|
||||
//
|
||||
// The sequence of 7 multiplications and 253 squarings is derived from the
|
||||
// following addition chain generated with github.com/mmcloughlin/addchain v0.4.0.
|
||||
//
|
||||
// _10 = 2*1
|
||||
// _11 = 1 + _10
|
||||
// _1100 = _11 << 2
|
||||
// _1111 = _11 + _1100
|
||||
// _11110000 = _1111 << 4
|
||||
// _11111111 = _1111 + _11110000
|
||||
// x16 = _11111111 << 8 + _11111111
|
||||
// x32 = x16 << 16 + x16
|
||||
// return ((x32 << 32 + 1) << 96 + 1) << 94
|
||||
//
|
||||
p256Square(t0, x, 1)
|
||||
t0.Mul(x, t0)
|
||||
p256Square(t1, t0, 2)
|
||||
t0.Mul(t0, t1)
|
||||
p256Square(t1, t0, 4)
|
||||
t0.Mul(t0, t1)
|
||||
p256Square(t1, t0, 8)
|
||||
t0.Mul(t0, t1)
|
||||
p256Square(t1, t0, 16)
|
||||
t0.Mul(t0, t1)
|
||||
p256Square(t0, t0, 32)
|
||||
t0.Mul(x, t0)
|
||||
p256Square(t0, t0, 96)
|
||||
t0.Mul(x, t0)
|
||||
p256Square(t0, t0, 94)
|
||||
|
||||
// Check if the candidate t0 is indeed a square root of x.
|
||||
t1.Square(t0)
|
||||
if t1.Equal(x) != 1 {
|
||||
return false
|
||||
}
|
||||
e.Set(t0)
|
||||
return true
|
||||
}
|
||||
|
||||
// p256Square sets e to the square of x, repeated n times > 1.
|
||||
func p256Square(e, x *fiat.P256Element, n int) {
|
||||
e.Square(x)
|
||||
for i := 1; i < n; i++ {
|
||||
e.Square(e)
|
||||
}
|
||||
}
|
||||
758
p256_asm.go
Normal file
758
p256_asm.go
Normal file
@@ -0,0 +1,758 @@
|
||||
// Copyright 2015 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This file contains the Go wrapper for the constant-time, 64-bit assembly
|
||||
// implementation of P256. The optimizations performed here are described in
|
||||
// detail in:
|
||||
// S.Gueron and V.Krasnov, "Fast prime field elliptic-curve cryptography with
|
||||
// 256-bit primes"
|
||||
// https://link.springer.com/article/10.1007%2Fs13389-014-0090-x
|
||||
// https://eprint.iacr.org/2013/816.pdf
|
||||
|
||||
//go:build (amd64 || arm64 || ppc64le || s390x) && !purego
|
||||
|
||||
package nistec
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/bits"
|
||||
"runtime"
|
||||
"unsafe"
|
||||
|
||||
"sources.truenas.cloud/code/nistec/internal/byteorder"
|
||||
)
|
||||
|
||||
// p256Element is a P-256 base field element in [0, P-1] in the Montgomery
|
||||
// domain (with R 2²⁵⁶) as four limbs in little-endian order value.
|
||||
type p256Element [4]uint64
|
||||
|
||||
// p256One is one in the Montgomery domain.
|
||||
var p256One = p256Element{0x0000000000000001, 0xffffffff00000000,
|
||||
0xffffffffffffffff, 0x00000000fffffffe}
|
||||
|
||||
var p256Zero = p256Element{}
|
||||
|
||||
// p256P is 2²⁵⁶ - 2²²⁴ + 2¹⁹² + 2⁹⁶ - 1 in the Montgomery domain.
|
||||
var p256P = p256Element{0xffffffffffffffff, 0x00000000ffffffff,
|
||||
0x0000000000000000, 0xffffffff00000001}
|
||||
|
||||
// P256Point is a P-256 point. The zero value should not be assumed to be valid
|
||||
// (although it is in this implementation).
|
||||
type P256Point struct {
|
||||
// (X:Y:Z) are Jacobian coordinates where x = X/Z² and y = Y/Z³. The point
|
||||
// at infinity can be represented by any set of coordinates with Z = 0.
|
||||
x, y, z p256Element
|
||||
}
|
||||
|
||||
// NewP256Point returns a new P256Point representing the point at infinity.
|
||||
func NewP256Point() *P256Point {
|
||||
return &P256Point{
|
||||
x: p256One, y: p256One, z: p256Zero,
|
||||
}
|
||||
}
|
||||
|
||||
// SetGenerator sets p to the canonical generator and returns p.
|
||||
func (p *P256Point) SetGenerator() *P256Point {
|
||||
p.x = p256Element{0x79e730d418a9143c, 0x75ba95fc5fedb601,
|
||||
0x79fb732b77622510, 0x18905f76a53755c6}
|
||||
p.y = p256Element{0xddf25357ce95560a, 0x8b4ab8e4ba19e45c,
|
||||
0xd2e88688dd21f325, 0x8571ff1825885d85}
|
||||
p.z = p256One
|
||||
return p
|
||||
}
|
||||
|
||||
// Set sets p = q and returns p.
|
||||
func (p *P256Point) Set(q *P256Point) *P256Point {
|
||||
p.x, p.y, p.z = q.x, q.y, q.z
|
||||
return p
|
||||
}
|
||||
|
||||
const p256ElementLength = 32
|
||||
const p256UncompressedLength = 1 + 2*p256ElementLength
|
||||
const p256CompressedLength = 1 + p256ElementLength
|
||||
|
||||
// SetBytes sets p to the compressed, uncompressed, or infinity value encoded in
|
||||
// b, as specified in SEC 1, Version 2.0, Section 2.3.4. If the point is not on
|
||||
// the curve, it returns nil and an error, and the receiver is unchanged.
|
||||
// Otherwise, it returns p.
|
||||
func (p *P256Point) SetBytes(b []byte) (*P256Point, error) {
|
||||
// p256Mul operates in the Montgomery domain with R = 2²⁵⁶ mod p. Thus rr
|
||||
// here is R in the Montgomery domain, or R×R mod p. See comment in
|
||||
// P256OrdInverse about how this is used.
|
||||
rr := p256Element{0x0000000000000003, 0xfffffffbffffffff,
|
||||
0xfffffffffffffffe, 0x00000004fffffffd}
|
||||
|
||||
switch {
|
||||
// Point at infinity.
|
||||
case len(b) == 1 && b[0] == 0:
|
||||
return p.Set(NewP256Point()), nil
|
||||
|
||||
// Uncompressed form.
|
||||
case len(b) == p256UncompressedLength && b[0] == 4:
|
||||
var r P256Point
|
||||
p256BigToLittle(&r.x, (*[32]byte)(b[1:33]))
|
||||
p256BigToLittle(&r.y, (*[32]byte)(b[33:65]))
|
||||
if p256LessThanP(&r.x) == 0 || p256LessThanP(&r.y) == 0 {
|
||||
return nil, errors.New("invalid P256 element encoding")
|
||||
}
|
||||
p256Mul(&r.x, &r.x, &rr)
|
||||
p256Mul(&r.y, &r.y, &rr)
|
||||
if err := p256CheckOnCurve(&r.x, &r.y); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r.z = p256One
|
||||
return p.Set(&r), nil
|
||||
|
||||
// Compressed form.
|
||||
case len(b) == p256CompressedLength && (b[0] == 2 || b[0] == 3):
|
||||
var r P256Point
|
||||
p256BigToLittle(&r.x, (*[32]byte)(b[1:33]))
|
||||
if p256LessThanP(&r.x) == 0 {
|
||||
return nil, errors.New("invalid P256 element encoding")
|
||||
}
|
||||
p256Mul(&r.x, &r.x, &rr)
|
||||
|
||||
// y² = x³ - 3x + b
|
||||
p256Polynomial(&r.y, &r.x)
|
||||
if !p256Sqrt(&r.y, &r.y) {
|
||||
return nil, errors.New("invalid P256 compressed point encoding")
|
||||
}
|
||||
|
||||
// Select the positive or negative root, as indicated by the least
|
||||
// significant bit, based on the encoding type byte.
|
||||
yy := new(p256Element)
|
||||
p256FromMont(yy, &r.y)
|
||||
cond := int(yy[0]&1) ^ int(b[0]&1)
|
||||
p256NegCond(&r.y, cond)
|
||||
|
||||
r.z = p256One
|
||||
return p.Set(&r), nil
|
||||
|
||||
default:
|
||||
return nil, errors.New("invalid P256 point encoding")
|
||||
}
|
||||
}
|
||||
|
||||
// p256Polynomial sets y2 to x³ - 3x + b, and returns y2.
|
||||
func p256Polynomial(y2, x *p256Element) *p256Element {
|
||||
x3 := new(p256Element)
|
||||
p256Sqr(x3, x, 1)
|
||||
p256Mul(x3, x3, x)
|
||||
|
||||
threeX := new(p256Element)
|
||||
p256Add(threeX, x, x)
|
||||
p256Add(threeX, threeX, x)
|
||||
p256NegCond(threeX, 1)
|
||||
|
||||
p256B := &p256Element{0xd89cdf6229c4bddf, 0xacf005cd78843090,
|
||||
0xe5a220abf7212ed6, 0xdc30061d04874834}
|
||||
|
||||
p256Add(x3, x3, threeX)
|
||||
p256Add(x3, x3, p256B)
|
||||
|
||||
*y2 = *x3
|
||||
return y2
|
||||
}
|
||||
|
||||
func p256CheckOnCurve(x, y *p256Element) error {
|
||||
// y² = x³ - 3x + b
|
||||
rhs := p256Polynomial(new(p256Element), x)
|
||||
lhs := new(p256Element)
|
||||
p256Sqr(lhs, y, 1)
|
||||
if p256Equal(lhs, rhs) != 1 {
|
||||
return errors.New("P256 point not on curve")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// p256LessThanP returns 1 if x < p, and 0 otherwise. Note that a p256Element is
|
||||
// not allowed to be equal to or greater than p, so if this function returns 0
|
||||
// then x is invalid.
|
||||
func p256LessThanP(x *p256Element) int {
|
||||
var b uint64
|
||||
_, b = bits.Sub64(x[0], p256P[0], b)
|
||||
_, b = bits.Sub64(x[1], p256P[1], b)
|
||||
_, b = bits.Sub64(x[2], p256P[2], b)
|
||||
_, b = bits.Sub64(x[3], p256P[3], b)
|
||||
return int(b)
|
||||
}
|
||||
|
||||
func p256BigToLittle(l *p256Element, b *[32]byte) {
|
||||
bytesToLimbs((*[4]uint64)(l), b)
|
||||
}
|
||||
|
||||
func bytesToLimbs(l *[4]uint64, b *[32]byte) {
|
||||
l[0] = byteorder.BEUint64(b[24:])
|
||||
l[1] = byteorder.BEUint64(b[16:])
|
||||
l[2] = byteorder.BEUint64(b[8:])
|
||||
l[3] = byteorder.BEUint64(b[:])
|
||||
}
|
||||
|
||||
func p256LittleToBig(b *[32]byte, l *p256Element) {
|
||||
limbsToBytes(b, (*[4]uint64)(l))
|
||||
}
|
||||
|
||||
func limbsToBytes(b *[32]byte, l *[4]uint64) {
|
||||
byteorder.BEPutUint64(b[24:], l[0])
|
||||
byteorder.BEPutUint64(b[16:], l[1])
|
||||
byteorder.BEPutUint64(b[8:], l[2])
|
||||
byteorder.BEPutUint64(b[:], l[3])
|
||||
}
|
||||
|
||||
// p256Add sets res = x + y.
|
||||
func p256Add(res, x, y *p256Element) {
|
||||
var c, b uint64
|
||||
t1 := make([]uint64, 4)
|
||||
t1[0], c = bits.Add64(x[0], y[0], 0)
|
||||
t1[1], c = bits.Add64(x[1], y[1], c)
|
||||
t1[2], c = bits.Add64(x[2], y[2], c)
|
||||
t1[3], c = bits.Add64(x[3], y[3], c)
|
||||
t2 := make([]uint64, 4)
|
||||
t2[0], b = bits.Sub64(t1[0], p256P[0], 0)
|
||||
t2[1], b = bits.Sub64(t1[1], p256P[1], b)
|
||||
t2[2], b = bits.Sub64(t1[2], p256P[2], b)
|
||||
t2[3], b = bits.Sub64(t1[3], p256P[3], b)
|
||||
// Three options:
|
||||
// - a+b < p
|
||||
// then c is 0, b is 1, and t1 is correct
|
||||
// - p <= a+b < 2^256
|
||||
// then c is 0, b is 0, and t2 is correct
|
||||
// - 2^256 <= a+b
|
||||
// then c is 1, b is 1, and t2 is correct
|
||||
t2Mask := (c ^ b) - 1
|
||||
res[0] = (t1[0] & ^t2Mask) | (t2[0] & t2Mask)
|
||||
res[1] = (t1[1] & ^t2Mask) | (t2[1] & t2Mask)
|
||||
res[2] = (t1[2] & ^t2Mask) | (t2[2] & t2Mask)
|
||||
res[3] = (t1[3] & ^t2Mask) | (t2[3] & t2Mask)
|
||||
}
|
||||
|
||||
// p256Sqrt sets e to a square root of x. If x is not a square, p256Sqrt returns
|
||||
// false and e is unchanged. e and x can overlap.
|
||||
func p256Sqrt(e, x *p256Element) (isSquare bool) {
|
||||
t0, t1 := new(p256Element), new(p256Element)
|
||||
|
||||
// Since p = 3 mod 4, exponentiation by (p + 1) / 4 yields a square root candidate.
|
||||
//
|
||||
// The sequence of 7 multiplications and 253 squarings is derived from the
|
||||
// following addition chain generated with github.com/mmcloughlin/addchain v0.4.0.
|
||||
//
|
||||
// _10 = 2*1
|
||||
// _11 = 1 + _10
|
||||
// _1100 = _11 << 2
|
||||
// _1111 = _11 + _1100
|
||||
// _11110000 = _1111 << 4
|
||||
// _11111111 = _1111 + _11110000
|
||||
// x16 = _11111111 << 8 + _11111111
|
||||
// x32 = x16 << 16 + x16
|
||||
// return ((x32 << 32 + 1) << 96 + 1) << 94
|
||||
//
|
||||
p256Sqr(t0, x, 1)
|
||||
p256Mul(t0, x, t0)
|
||||
p256Sqr(t1, t0, 2)
|
||||
p256Mul(t0, t0, t1)
|
||||
p256Sqr(t1, t0, 4)
|
||||
p256Mul(t0, t0, t1)
|
||||
p256Sqr(t1, t0, 8)
|
||||
p256Mul(t0, t0, t1)
|
||||
p256Sqr(t1, t0, 16)
|
||||
p256Mul(t0, t0, t1)
|
||||
p256Sqr(t0, t0, 32)
|
||||
p256Mul(t0, x, t0)
|
||||
p256Sqr(t0, t0, 96)
|
||||
p256Mul(t0, x, t0)
|
||||
p256Sqr(t0, t0, 94)
|
||||
|
||||
p256Sqr(t1, t0, 1)
|
||||
if p256Equal(t1, x) != 1 {
|
||||
return false
|
||||
}
|
||||
*e = *t0
|
||||
return true
|
||||
}
|
||||
|
||||
// The following assembly functions are implemented in p256_asm_*.s
|
||||
|
||||
// Montgomery multiplication. Sets res = in1 * in2 * R⁻¹ mod p.
|
||||
//
|
||||
//go:noescape
|
||||
func p256Mul(res, in1, in2 *p256Element)
|
||||
|
||||
// Montgomery square, repeated n times (n >= 1).
|
||||
//
|
||||
//go:noescape
|
||||
func p256Sqr(res, in *p256Element, n int)
|
||||
|
||||
// Montgomery multiplication by R⁻¹, or 1 outside the domain.
|
||||
// Sets res = in * R⁻¹, bringing res out of the Montgomery domain.
|
||||
//
|
||||
//go:noescape
|
||||
func p256FromMont(res, in *p256Element)
|
||||
|
||||
// If cond is not 0, sets val = -val mod p.
|
||||
//
|
||||
//go:noescape
|
||||
func p256NegCond(val *p256Element, cond int)
|
||||
|
||||
// If cond is 0, sets res = b, otherwise sets res = a.
|
||||
//
|
||||
//go:noescape
|
||||
func p256MovCond(res, a, b *P256Point, cond int)
|
||||
|
||||
// p256Table is a table of the first 16 multiples of a point. Points are stored
|
||||
// at an index offset of -1 so [8]P is at index 7, P is at 0, and [16]P is at 15.
|
||||
// [0]P is the point at infinity and it's not stored.
|
||||
type p256Table [16]P256Point
|
||||
|
||||
// p256Select sets res to the point at index idx in the table.
|
||||
// idx must be in [0, 15]. It executes in constant time.
|
||||
//
|
||||
//go:noescape
|
||||
func p256Select(res *P256Point, table *p256Table, idx int)
|
||||
|
||||
// p256AffinePoint is a point in affine coordinates (x, y). x and y are still
|
||||
// Montgomery domain elements. The point can't be the point at infinity.
|
||||
type p256AffinePoint struct {
|
||||
x, y p256Element
|
||||
}
|
||||
|
||||
// p256AffineTable is a table of the first 32 multiples of a point. Points are
|
||||
// stored at an index offset of -1 like in p256Table, and [0]P is not stored.
|
||||
type p256AffineTable [32]p256AffinePoint
|
||||
|
||||
// p256Precomputed 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 p256ScalarBaseMult, and having each table already
|
||||
// pre-doubled lets us avoid the doublings between windows entirely. This table
|
||||
// aliases into p256PrecomputedEmbed.
|
||||
var p256Precomputed *[43]p256AffineTable
|
||||
|
||||
func init() {
|
||||
p256PrecomputedPtr := unsafe.Pointer(&p256PrecomputedEmbed)
|
||||
if runtime.GOARCH == "s390x" {
|
||||
var newTable [43 * 32 * 2 * 4]uint64
|
||||
for i, x := range (*[43 * 32 * 2 * 4][8]byte)(p256PrecomputedPtr) {
|
||||
newTable[i] = byteorder.LEUint64(x[:])
|
||||
}
|
||||
p256PrecomputedPtr = unsafe.Pointer(&newTable)
|
||||
}
|
||||
p256Precomputed = (*[43]p256AffineTable)(p256PrecomputedPtr)
|
||||
}
|
||||
|
||||
// p256SelectAffine sets res to the point at index idx in the table.
|
||||
// idx must be in [0, 31]. It executes in constant time.
|
||||
//
|
||||
//go:noescape
|
||||
func p256SelectAffine(res *p256AffinePoint, table *p256AffineTable, idx int)
|
||||
|
||||
// Point addition with an affine point and constant time conditions.
|
||||
// If zero is 0, sets res = in2. If sel is 0, sets res = in1.
|
||||
// If sign is not 0, sets res = in1 + -in2. Otherwise, sets res = in1 + in2
|
||||
//
|
||||
//go:noescape
|
||||
func p256PointAddAffineAsm(res, in1 *P256Point, in2 *p256AffinePoint, sign, sel, zero int)
|
||||
|
||||
// Point addition. Sets res = in1 + in2. Returns one if the two input points
|
||||
// were equal and zero otherwise. If in1 or in2 are the point at infinity, res
|
||||
// and the return value are undefined.
|
||||
//
|
||||
//go:noescape
|
||||
func p256PointAddAsm(res, in1, in2 *P256Point) int
|
||||
|
||||
// Point doubling. Sets res = in + in. in can be the point at infinity.
|
||||
//
|
||||
//go:noescape
|
||||
func p256PointDoubleAsm(res, in *P256Point)
|
||||
|
||||
// p256OrdElement is a P-256 scalar field element in [0, ord(G)-1] in the
|
||||
// Montgomery domain (with R 2²⁵⁶) as four uint64 limbs in little-endian order.
|
||||
type p256OrdElement [4]uint64
|
||||
|
||||
// p256OrdReduce ensures s is in the range [0, ord(G)-1].
|
||||
func p256OrdReduce(s *p256OrdElement) {
|
||||
// Since 2 * ord(G) > 2²⁵⁶, we can just conditionally subtract ord(G),
|
||||
// keeping the result if it doesn't underflow.
|
||||
t0, b := bits.Sub64(s[0], 0xf3b9cac2fc632551, 0)
|
||||
t1, b := bits.Sub64(s[1], 0xbce6faada7179e84, b)
|
||||
t2, b := bits.Sub64(s[2], 0xffffffffffffffff, b)
|
||||
t3, b := bits.Sub64(s[3], 0xffffffff00000000, b)
|
||||
tMask := b - 1 // zero if subtraction underflowed
|
||||
s[0] ^= (t0 ^ s[0]) & tMask
|
||||
s[1] ^= (t1 ^ s[1]) & tMask
|
||||
s[2] ^= (t2 ^ s[2]) & tMask
|
||||
s[3] ^= (t3 ^ s[3]) & tMask
|
||||
}
|
||||
|
||||
func p256OrdLittleToBig(b *[32]byte, l *p256OrdElement) {
|
||||
limbsToBytes(b, (*[4]uint64)(l))
|
||||
}
|
||||
|
||||
func p256OrdBigToLittle(l *p256OrdElement, b *[32]byte) {
|
||||
bytesToLimbs((*[4]uint64)(l), b)
|
||||
}
|
||||
|
||||
// Add sets q = p1 + p2, and returns q. The points may overlap.
|
||||
func (q *P256Point) Add(r1, r2 *P256Point) *P256Point {
|
||||
var sum, double P256Point
|
||||
r1IsInfinity := r1.isInfinity()
|
||||
r2IsInfinity := r2.isInfinity()
|
||||
pointsEqual := p256PointAddAsm(&sum, r1, r2)
|
||||
p256PointDoubleAsm(&double, r1)
|
||||
p256MovCond(&sum, &double, &sum, pointsEqual)
|
||||
p256MovCond(&sum, r1, &sum, r2IsInfinity)
|
||||
p256MovCond(&sum, r2, &sum, r1IsInfinity)
|
||||
return q.Set(&sum)
|
||||
}
|
||||
|
||||
// Double sets q = p + p, and returns q. The points may overlap.
|
||||
func (q *P256Point) Double(p *P256Point) *P256Point {
|
||||
var double P256Point
|
||||
p256PointDoubleAsm(&double, p)
|
||||
return q.Set(&double)
|
||||
}
|
||||
|
||||
// ScalarBaseMult sets r = scalar * generator, where scalar is a 32-byte big
|
||||
// endian value, and returns r. If scalar is not 32 bytes long, ScalarBaseMult
|
||||
// returns an error and the receiver is unchanged.
|
||||
func (r *P256Point) ScalarBaseMult(scalar []byte) (*P256Point, error) {
|
||||
if len(scalar) != 32 {
|
||||
return nil, errors.New("invalid scalar length")
|
||||
}
|
||||
scalarReversed := new(p256OrdElement)
|
||||
p256OrdBigToLittle(scalarReversed, (*[32]byte)(scalar))
|
||||
p256OrdReduce(scalarReversed)
|
||||
|
||||
r.p256BaseMult(scalarReversed)
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// ScalarMult sets r = scalar * q, where scalar is a 32-byte big endian value,
|
||||
// and returns r. If scalar is not 32 bytes long, ScalarBaseMult returns an
|
||||
// error and the receiver is unchanged.
|
||||
func (r *P256Point) ScalarMult(q *P256Point, scalar []byte) (*P256Point, error) {
|
||||
if len(scalar) != 32 {
|
||||
return nil, errors.New("invalid scalar length")
|
||||
}
|
||||
scalarReversed := new(p256OrdElement)
|
||||
p256OrdBigToLittle(scalarReversed, (*[32]byte)(scalar))
|
||||
p256OrdReduce(scalarReversed)
|
||||
|
||||
r.Set(q).p256ScalarMult(scalarReversed)
|
||||
return r, nil
|
||||
}
|
||||
|
||||
// uint64IsZero returns 1 if x is zero and zero otherwise.
|
||||
func uint64IsZero(x uint64) int {
|
||||
x = ^x
|
||||
x &= x >> 32
|
||||
x &= x >> 16
|
||||
x &= x >> 8
|
||||
x &= x >> 4
|
||||
x &= x >> 2
|
||||
x &= x >> 1
|
||||
return int(x & 1)
|
||||
}
|
||||
|
||||
// p256Equal returns 1 if a and b are equal and 0 otherwise.
|
||||
func p256Equal(a, b *p256Element) int {
|
||||
var acc uint64
|
||||
for i := range a {
|
||||
acc |= a[i] ^ b[i]
|
||||
}
|
||||
return uint64IsZero(acc)
|
||||
}
|
||||
|
||||
// isInfinity returns 1 if p is the point at infinity and 0 otherwise.
|
||||
func (p *P256Point) isInfinity() int {
|
||||
return p256Equal(&p.z, &p256Zero)
|
||||
}
|
||||
|
||||
// Bytes returns the uncompressed or infinity encoding of p, as specified in
|
||||
// SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the point at
|
||||
// infinity is shorter than all other encodings.
|
||||
func (p *P256Point) Bytes() []byte {
|
||||
// This function is outlined to make the allocations inline in the caller
|
||||
// rather than happen on the heap.
|
||||
var out [p256UncompressedLength]byte
|
||||
return p.bytes(&out)
|
||||
}
|
||||
|
||||
func (p *P256Point) bytes(out *[p256UncompressedLength]byte) []byte {
|
||||
// The proper representation of the point at infinity is a single zero byte.
|
||||
if p.isInfinity() == 1 {
|
||||
return append(out[:0], 0)
|
||||
}
|
||||
|
||||
x, y := new(p256Element), new(p256Element)
|
||||
p.affineFromMont(x, y)
|
||||
|
||||
out[0] = 4 // Uncompressed form.
|
||||
p256LittleToBig((*[32]byte)(out[1:33]), x)
|
||||
p256LittleToBig((*[32]byte)(out[33:65]), y)
|
||||
|
||||
return out[:]
|
||||
}
|
||||
|
||||
// affineFromMont sets (x, y) to the affine coordinates of p, converted out of the
|
||||
// Montgomery domain.
|
||||
func (p *P256Point) affineFromMont(x, y *p256Element) {
|
||||
p256Inverse(y, &p.z)
|
||||
p256Sqr(x, y, 1)
|
||||
p256Mul(y, y, x)
|
||||
|
||||
p256Mul(x, &p.x, x)
|
||||
p256Mul(y, &p.y, y)
|
||||
|
||||
p256FromMont(x, x)
|
||||
p256FromMont(y, y)
|
||||
}
|
||||
|
||||
// BytesX returns the encoding of the x-coordinate of p, as specified in SEC 1,
|
||||
// Version 2.0, Section 2.3.5, or an error if p is the point at infinity.
|
||||
func (p *P256Point) BytesX() ([]byte, error) {
|
||||
// This function is outlined to make the allocations inline in the caller
|
||||
// rather than happen on the heap.
|
||||
var out [p256ElementLength]byte
|
||||
return p.bytesX(&out)
|
||||
}
|
||||
|
||||
func (p *P256Point) bytesX(out *[p256ElementLength]byte) ([]byte, error) {
|
||||
if p.isInfinity() == 1 {
|
||||
return nil, errors.New("P256 point is the point at infinity")
|
||||
}
|
||||
|
||||
x := new(p256Element)
|
||||
p256Inverse(x, &p.z)
|
||||
p256Sqr(x, x, 1)
|
||||
p256Mul(x, &p.x, x)
|
||||
p256FromMont(x, x)
|
||||
p256LittleToBig((*[32]byte)(out[:]), x)
|
||||
|
||||
return out[:], nil
|
||||
}
|
||||
|
||||
// BytesCompressed returns the compressed or infinity encoding of p, as
|
||||
// specified in SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the
|
||||
// point at infinity is shorter than all other encodings.
|
||||
func (p *P256Point) BytesCompressed() []byte {
|
||||
// This function is outlined to make the allocations inline in the caller
|
||||
// rather than happen on the heap.
|
||||
var out [p256CompressedLength]byte
|
||||
return p.bytesCompressed(&out)
|
||||
}
|
||||
|
||||
func (p *P256Point) bytesCompressed(out *[p256CompressedLength]byte) []byte {
|
||||
if p.isInfinity() == 1 {
|
||||
return append(out[:0], 0)
|
||||
}
|
||||
|
||||
x, y := new(p256Element), new(p256Element)
|
||||
p.affineFromMont(x, y)
|
||||
|
||||
out[0] = 2 | byte(y[0]&1)
|
||||
p256LittleToBig((*[32]byte)(out[1:33]), x)
|
||||
|
||||
return out[:]
|
||||
}
|
||||
|
||||
// Select sets q to p1 if cond == 1, and to p2 if cond == 0.
|
||||
func (q *P256Point) Select(p1, p2 *P256Point, cond int) *P256Point {
|
||||
p256MovCond(q, p1, p2, cond)
|
||||
return q
|
||||
}
|
||||
|
||||
// p256Inverse sets out to in⁻¹ mod p. If in is zero, out will be zero.
|
||||
func p256Inverse(out, in *p256Element) {
|
||||
// Inversion is calculated through exponentiation by p - 2, per Fermat's
|
||||
// little theorem.
|
||||
//
|
||||
// The sequence of 12 multiplications and 255 squarings is derived from the
|
||||
// following addition chain generated with github.com/mmcloughlin/addchain
|
||||
// v0.4.0.
|
||||
//
|
||||
// _10 = 2*1
|
||||
// _11 = 1 + _10
|
||||
// _110 = 2*_11
|
||||
// _111 = 1 + _110
|
||||
// _111000 = _111 << 3
|
||||
// _111111 = _111 + _111000
|
||||
// x12 = _111111 << 6 + _111111
|
||||
// x15 = x12 << 3 + _111
|
||||
// x16 = 2*x15 + 1
|
||||
// x32 = x16 << 16 + x16
|
||||
// i53 = x32 << 15
|
||||
// x47 = x15 + i53
|
||||
// i263 = ((i53 << 17 + 1) << 143 + x47) << 47
|
||||
// return (x47 + i263) << 2 + 1
|
||||
//
|
||||
var z = new(p256Element)
|
||||
var t0 = new(p256Element)
|
||||
var t1 = new(p256Element)
|
||||
|
||||
p256Sqr(z, in, 1)
|
||||
p256Mul(z, in, z)
|
||||
p256Sqr(z, z, 1)
|
||||
p256Mul(z, in, z)
|
||||
p256Sqr(t0, z, 3)
|
||||
p256Mul(t0, z, t0)
|
||||
p256Sqr(t1, t0, 6)
|
||||
p256Mul(t0, t0, t1)
|
||||
p256Sqr(t0, t0, 3)
|
||||
p256Mul(z, z, t0)
|
||||
p256Sqr(t0, z, 1)
|
||||
p256Mul(t0, in, t0)
|
||||
p256Sqr(t1, t0, 16)
|
||||
p256Mul(t0, t0, t1)
|
||||
p256Sqr(t0, t0, 15)
|
||||
p256Mul(z, z, t0)
|
||||
p256Sqr(t0, t0, 17)
|
||||
p256Mul(t0, in, t0)
|
||||
p256Sqr(t0, t0, 143)
|
||||
p256Mul(t0, z, t0)
|
||||
p256Sqr(t0, t0, 47)
|
||||
p256Mul(z, z, t0)
|
||||
p256Sqr(z, z, 2)
|
||||
p256Mul(out, in, z)
|
||||
}
|
||||
|
||||
func boothW5(in uint) (int, int) {
|
||||
var s uint = ^((in >> 5) - 1)
|
||||
var d uint = (1 << 6) - in - 1
|
||||
d = (d & s) | (in & (^s))
|
||||
d = (d >> 1) + (d & 1)
|
||||
return int(d), int(s & 1)
|
||||
}
|
||||
|
||||
func boothW6(in uint) (int, int) {
|
||||
var s uint = ^((in >> 6) - 1)
|
||||
var d uint = (1 << 7) - in - 1
|
||||
d = (d & s) | (in & (^s))
|
||||
d = (d >> 1) + (d & 1)
|
||||
return int(d), int(s & 1)
|
||||
}
|
||||
|
||||
func (p *P256Point) p256BaseMult(scalar *p256OrdElement) {
|
||||
var t0 p256AffinePoint
|
||||
|
||||
wvalue := (scalar[0] << 1) & 0x7f
|
||||
sel, sign := boothW6(uint(wvalue))
|
||||
p256SelectAffine(&t0, &p256Precomputed[0], sel)
|
||||
p.x, p.y, p.z = t0.x, t0.y, p256One
|
||||
p256NegCond(&p.y, sign)
|
||||
|
||||
index := uint(5)
|
||||
zero := sel
|
||||
|
||||
for i := 1; i < 43; i++ {
|
||||
if index < 192 {
|
||||
wvalue = ((scalar[index/64] >> (index % 64)) + (scalar[index/64+1] << (64 - (index % 64)))) & 0x7f
|
||||
} else {
|
||||
wvalue = (scalar[index/64] >> (index % 64)) & 0x7f
|
||||
}
|
||||
index += 6
|
||||
sel, sign = boothW6(uint(wvalue))
|
||||
p256SelectAffine(&t0, &p256Precomputed[i], sel)
|
||||
p256PointAddAffineAsm(p, p, &t0, sign, sel, zero)
|
||||
zero |= sel
|
||||
}
|
||||
|
||||
// If the whole scalar was zero, set to the point at infinity.
|
||||
p256MovCond(p, p, NewP256Point(), zero)
|
||||
}
|
||||
|
||||
func (p *P256Point) p256ScalarMult(scalar *p256OrdElement) {
|
||||
// precomp is a table of precomputed points that stores powers of p
|
||||
// from p^1 to p^16.
|
||||
var precomp p256Table
|
||||
var t0, t1, t2, t3 P256Point
|
||||
|
||||
// Prepare the table
|
||||
precomp[0] = *p // 1
|
||||
|
||||
p256PointDoubleAsm(&t0, p)
|
||||
p256PointDoubleAsm(&t1, &t0)
|
||||
p256PointDoubleAsm(&t2, &t1)
|
||||
p256PointDoubleAsm(&t3, &t2)
|
||||
precomp[1] = t0 // 2
|
||||
precomp[3] = t1 // 4
|
||||
precomp[7] = t2 // 8
|
||||
precomp[15] = t3 // 16
|
||||
|
||||
p256PointAddAsm(&t0, &t0, p)
|
||||
p256PointAddAsm(&t1, &t1, p)
|
||||
p256PointAddAsm(&t2, &t2, p)
|
||||
precomp[2] = t0 // 3
|
||||
precomp[4] = t1 // 5
|
||||
precomp[8] = t2 // 9
|
||||
|
||||
p256PointDoubleAsm(&t0, &t0)
|
||||
p256PointDoubleAsm(&t1, &t1)
|
||||
precomp[5] = t0 // 6
|
||||
precomp[9] = t1 // 10
|
||||
|
||||
p256PointAddAsm(&t2, &t0, p)
|
||||
p256PointAddAsm(&t1, &t1, p)
|
||||
precomp[6] = t2 // 7
|
||||
precomp[10] = t1 // 11
|
||||
|
||||
p256PointDoubleAsm(&t0, &t0)
|
||||
p256PointDoubleAsm(&t2, &t2)
|
||||
precomp[11] = t0 // 12
|
||||
precomp[13] = t2 // 14
|
||||
|
||||
p256PointAddAsm(&t0, &t0, p)
|
||||
p256PointAddAsm(&t2, &t2, p)
|
||||
precomp[12] = t0 // 13
|
||||
precomp[14] = t2 // 15
|
||||
|
||||
// Start scanning the window from top bit
|
||||
index := uint(254)
|
||||
var sel, sign int
|
||||
|
||||
wvalue := (scalar[index/64] >> (index % 64)) & 0x3f
|
||||
sel, _ = boothW5(uint(wvalue))
|
||||
|
||||
p256Select(p, &precomp, sel)
|
||||
zero := sel
|
||||
|
||||
for index > 4 {
|
||||
index -= 5
|
||||
p256PointDoubleAsm(p, p)
|
||||
p256PointDoubleAsm(p, p)
|
||||
p256PointDoubleAsm(p, p)
|
||||
p256PointDoubleAsm(p, p)
|
||||
p256PointDoubleAsm(p, p)
|
||||
|
||||
if index < 192 {
|
||||
wvalue = ((scalar[index/64] >> (index % 64)) + (scalar[index/64+1] << (64 - (index % 64)))) & 0x3f
|
||||
} else {
|
||||
wvalue = (scalar[index/64] >> (index % 64)) & 0x3f
|
||||
}
|
||||
|
||||
sel, sign = boothW5(uint(wvalue))
|
||||
|
||||
p256Select(&t0, &precomp, sel)
|
||||
p256NegCond(&t0.y, sign)
|
||||
p256PointAddAsm(&t1, p, &t0)
|
||||
p256MovCond(&t1, &t1, p, sel)
|
||||
p256MovCond(p, &t1, &t0, zero)
|
||||
zero |= sel
|
||||
}
|
||||
|
||||
p256PointDoubleAsm(p, p)
|
||||
p256PointDoubleAsm(p, p)
|
||||
p256PointDoubleAsm(p, p)
|
||||
p256PointDoubleAsm(p, p)
|
||||
p256PointDoubleAsm(p, p)
|
||||
|
||||
wvalue = (scalar[0] << 1) & 0x3f
|
||||
sel, sign = boothW5(uint(wvalue))
|
||||
|
||||
p256Select(&t0, &precomp, sel)
|
||||
p256NegCond(&t0.y, sign)
|
||||
p256PointAddAsm(&t1, p, &t0)
|
||||
p256MovCond(&t1, &t1, p, sel)
|
||||
p256MovCond(p, &t1, &t0, zero)
|
||||
}
|
||||
2425
p256_asm_amd64.s
Normal file
2425
p256_asm_amd64.s
Normal file
File diff suppressed because it is too large
Load Diff
1506
p256_asm_arm64.s
Normal file
1506
p256_asm_arm64.s
Normal file
File diff suppressed because it is too large
Load Diff
2180
p256_asm_ppc64le.s
Normal file
2180
p256_asm_ppc64le.s
Normal file
File diff suppressed because it is too large
Load Diff
1989
p256_asm_s390x.s
Normal file
1989
p256_asm_s390x.s
Normal file
File diff suppressed because it is too large
Load Diff
53
p256_asm_test.go
Normal file
53
p256_asm_test.go
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright 2024 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build (amd64 || arm64 || ppc64le || s390x) && !purego && linux
|
||||
|
||||
package nistec
|
||||
|
||||
import (
|
||||
"syscall"
|
||||
"testing"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// Lightly adapted from the bytes test package. Allocate a pair of T one at the start of a page, another at the
|
||||
// end. Any access beyond or before the page boundary should cause a fault. This is linux specific.
|
||||
func dangerousObjs[T any](t *testing.T) (start *T, end *T) {
|
||||
pagesize := syscall.Getpagesize()
|
||||
b, err := syscall.Mmap(0, 0, 3*pagesize, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANONYMOUS|syscall.MAP_PRIVATE)
|
||||
if err != nil {
|
||||
t.Fatalf("mmap failed %s", err)
|
||||
}
|
||||
err = syscall.Mprotect(b[:pagesize], syscall.PROT_NONE)
|
||||
if err != nil {
|
||||
t.Fatalf("mprotect low failed %s\n", err)
|
||||
}
|
||||
err = syscall.Mprotect(b[2*pagesize:], syscall.PROT_NONE)
|
||||
if err != nil {
|
||||
t.Fatalf("mprotect high failed %s\n", err)
|
||||
}
|
||||
b = b[pagesize : 2*pagesize]
|
||||
end = (*T)(unsafe.Pointer(&b[len(b)-(int)(unsafe.Sizeof(*end))]))
|
||||
start = (*T)(unsafe.Pointer(&b[0]))
|
||||
return start, end
|
||||
}
|
||||
|
||||
func TestP256SelectAffinePageBoundary(t *testing.T) {
|
||||
var out p256AffinePoint
|
||||
begintp, endtp := dangerousObjs[p256AffineTable](t)
|
||||
for i := 0; i < 31; i++ {
|
||||
p256SelectAffine(&out, begintp, i)
|
||||
p256SelectAffine(&out, endtp, i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestP256SelectPageBoundary(t *testing.T) {
|
||||
var out P256Point
|
||||
begintp, endtp := dangerousObjs[p256Table](t)
|
||||
for i := 0; i < 15; i++ {
|
||||
p256Select(&out, begintp, i)
|
||||
p256Select(&out, endtp, i)
|
||||
}
|
||||
}
|
||||
102
p256_ordinv.go
Normal file
102
p256_ordinv.go
Normal file
@@ -0,0 +1,102 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build (amd64 || arm64) && !purego
|
||||
|
||||
package nistec
|
||||
|
||||
import "errors"
|
||||
|
||||
// Montgomery multiplication modulo org(G). Sets res = in1 * in2 * R⁻¹.
|
||||
//
|
||||
//go:noescape
|
||||
func p256OrdMul(res, in1, in2 *p256OrdElement)
|
||||
|
||||
// Montgomery square modulo org(G), repeated n times (n >= 1).
|
||||
//
|
||||
//go:noescape
|
||||
func p256OrdSqr(res, in *p256OrdElement, n int)
|
||||
|
||||
func p256OrdInverse(k []byte) ([]byte, error) {
|
||||
if len(k) != 32 {
|
||||
return nil, errors.New("invalid scalar length")
|
||||
}
|
||||
|
||||
x := new(p256OrdElement)
|
||||
p256OrdBigToLittle(x, (*[32]byte)(k))
|
||||
p256OrdReduce(x)
|
||||
|
||||
// Inversion is implemented as exponentiation by n - 2, per Fermat's little theorem.
|
||||
//
|
||||
// The sequence of 38 multiplications and 254 squarings is derived from
|
||||
// https://briansmith.org/ecc-inversion-addition-chains-01#p256_scalar_inversion
|
||||
_1 := new(p256OrdElement)
|
||||
_11 := new(p256OrdElement)
|
||||
_101 := new(p256OrdElement)
|
||||
_111 := new(p256OrdElement)
|
||||
_1111 := new(p256OrdElement)
|
||||
_10101 := new(p256OrdElement)
|
||||
_101111 := new(p256OrdElement)
|
||||
t := new(p256OrdElement)
|
||||
|
||||
// This code operates in the Montgomery domain where R = 2²⁵⁶ mod n and n is
|
||||
// the order of the scalar field. Elements in the Montgomery domain take the
|
||||
// form a×R and p256OrdMul calculates (a × b × R⁻¹) mod n. RR is R in the
|
||||
// domain, or R×R mod n, thus p256OrdMul(x, RR) gives x×R, i.e. converts x
|
||||
// into the Montgomery domain.
|
||||
RR := &p256OrdElement{0x83244c95be79eea2, 0x4699799c49bd6fa6,
|
||||
0x2845b2392b6bec59, 0x66e12d94f3d95620}
|
||||
|
||||
p256OrdMul(_1, x, RR) // _1
|
||||
p256OrdSqr(x, _1, 1) // _10
|
||||
p256OrdMul(_11, x, _1) // _11
|
||||
p256OrdMul(_101, x, _11) // _101
|
||||
p256OrdMul(_111, x, _101) // _111
|
||||
p256OrdSqr(x, _101, 1) // _1010
|
||||
p256OrdMul(_1111, _101, x) // _1111
|
||||
|
||||
p256OrdSqr(t, x, 1) // _10100
|
||||
p256OrdMul(_10101, t, _1) // _10101
|
||||
p256OrdSqr(x, _10101, 1) // _101010
|
||||
p256OrdMul(_101111, _101, x) // _101111
|
||||
p256OrdMul(x, _10101, x) // _111111 = x6
|
||||
p256OrdSqr(t, x, 2) // _11111100
|
||||
p256OrdMul(t, t, _11) // _11111111 = x8
|
||||
p256OrdSqr(x, t, 8) // _ff00
|
||||
p256OrdMul(x, x, t) // _ffff = x16
|
||||
p256OrdSqr(t, x, 16) // _ffff0000
|
||||
p256OrdMul(t, t, x) // _ffffffff = x32
|
||||
|
||||
p256OrdSqr(x, t, 64)
|
||||
p256OrdMul(x, x, t)
|
||||
p256OrdSqr(x, x, 32)
|
||||
p256OrdMul(x, x, t)
|
||||
|
||||
sqrs := []int{
|
||||
6, 5, 4, 5, 5,
|
||||
4, 3, 3, 5, 9,
|
||||
6, 2, 5, 6, 5,
|
||||
4, 5, 5, 3, 10,
|
||||
2, 5, 5, 3, 7, 6}
|
||||
muls := []*p256OrdElement{
|
||||
_101111, _111, _11, _1111, _10101,
|
||||
_101, _101, _101, _111, _101111,
|
||||
_1111, _1, _1, _1111, _111,
|
||||
_111, _111, _101, _11, _101111,
|
||||
_11, _11, _11, _1, _10101, _1111}
|
||||
|
||||
for i, s := range sqrs {
|
||||
p256OrdSqr(x, x, s)
|
||||
p256OrdMul(x, x, muls[i])
|
||||
}
|
||||
|
||||
// Montgomery multiplication by R⁻¹, or 1 outside the domain as R⁻¹×R = 1,
|
||||
// converts a Montgomery value out of the domain.
|
||||
one := &p256OrdElement{1}
|
||||
p256OrdMul(x, x, one)
|
||||
|
||||
var xOut [32]byte
|
||||
p256OrdLittleToBig(&xOut, x)
|
||||
return xOut[:], nil
|
||||
}
|
||||
13
p256_ordinv_export_test.go
Normal file
13
p256_ordinv_export_test.go
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package nistec
|
||||
|
||||
// This file exports the P256OrdInverse function so it's accessible during tests
|
||||
// from the unmodified p256_ordinv_test.go from the stdlib, but not as part
|
||||
// of the public API of filippo.io/nistec.
|
||||
|
||||
func P256OrdInverse(k []byte) ([]byte, error) {
|
||||
return p256OrdInverse(k)
|
||||
}
|
||||
13
p256_ordinv_noasm.go
Normal file
13
p256_ordinv_noasm.go
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build (!amd64 && !arm64) || purego
|
||||
|
||||
package nistec
|
||||
|
||||
import "errors"
|
||||
|
||||
func p256OrdInverse(k []byte) ([]byte, error) {
|
||||
return nil, errors.New("unimplemented")
|
||||
}
|
||||
95
p256_ordinv_test.go
Normal file
95
p256_ordinv_test.go
Normal file
@@ -0,0 +1,95 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build (amd64 || arm64) && !purego
|
||||
|
||||
package nistec_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/elliptic"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
"sources.truenas.cloud/code/nistec"
|
||||
)
|
||||
|
||||
func TestP256OrdInverse(t *testing.T) {
|
||||
N := elliptic.P256().Params().N
|
||||
|
||||
// inv(0) is expected to be 0.
|
||||
zero := make([]byte, 32)
|
||||
out, err := nistec.P256OrdInverse(zero)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(out, zero) {
|
||||
t.Error("unexpected output for inv(0)")
|
||||
}
|
||||
|
||||
// inv(N) is also 0 mod N.
|
||||
input := make([]byte, 32)
|
||||
N.FillBytes(input)
|
||||
out, err = nistec.P256OrdInverse(input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(out, zero) {
|
||||
t.Error("unexpected output for inv(N)")
|
||||
}
|
||||
if !bytes.Equal(input, N.Bytes()) {
|
||||
t.Error("input was modified")
|
||||
}
|
||||
|
||||
// Check inv(1) and inv(N+1) against math/big
|
||||
exp := new(big.Int).ModInverse(big.NewInt(1), N).FillBytes(make([]byte, 32))
|
||||
big.NewInt(1).FillBytes(input)
|
||||
out, err = nistec.P256OrdInverse(input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(out, exp) {
|
||||
t.Error("unexpected output for inv(1)")
|
||||
}
|
||||
new(big.Int).Add(N, big.NewInt(1)).FillBytes(input)
|
||||
out, err = nistec.P256OrdInverse(input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(out, exp) {
|
||||
t.Error("unexpected output for inv(N+1)")
|
||||
}
|
||||
|
||||
// Check inv(20) and inv(N+20) against math/big
|
||||
exp = new(big.Int).ModInverse(big.NewInt(20), N).FillBytes(make([]byte, 32))
|
||||
big.NewInt(20).FillBytes(input)
|
||||
out, err = nistec.P256OrdInverse(input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(out, exp) {
|
||||
t.Error("unexpected output for inv(20)")
|
||||
}
|
||||
new(big.Int).Add(N, big.NewInt(20)).FillBytes(input)
|
||||
out, err = nistec.P256OrdInverse(input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(out, exp) {
|
||||
t.Error("unexpected output for inv(N+20)")
|
||||
}
|
||||
|
||||
// Check inv(2^256-1) against math/big
|
||||
bigInput := new(big.Int).Lsh(big.NewInt(1), 256)
|
||||
bigInput.Sub(bigInput, big.NewInt(1))
|
||||
exp = new(big.Int).ModInverse(bigInput, N).FillBytes(make([]byte, 32))
|
||||
bigInput.FillBytes(input)
|
||||
out, err = nistec.P256OrdInverse(input)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !bytes.Equal(out, exp) {
|
||||
t.Error("unexpected output for inv(2^256-1)")
|
||||
}
|
||||
}
|
||||
10
p256_table.go
Normal file
10
p256_table.go
Normal file
File diff suppressed because one or more lines are too long
49
p256_test.go
Normal file
49
p256_test.go
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright 2021 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
//go:build (!amd64 && !arm64 && !ppc64le && !s390x) || purego
|
||||
|
||||
package nistec
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"sources.truenas.cloud/code/nistec/internal/fiat"
|
||||
)
|
||||
|
||||
func TestP256PrecomputedTable(t *testing.T) {
|
||||
base := NewP256Point().SetGenerator()
|
||||
|
||||
for i := 0; i < 43; i++ {
|
||||
t.Run(fmt.Sprintf("table[%d]", i), func(t *testing.T) {
|
||||
testP256AffineTable(t, base, &p256GeneratorTables[i])
|
||||
})
|
||||
|
||||
for k := 0; k < 6; k++ {
|
||||
base.Double(base)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testP256AffineTable(t *testing.T, base *P256Point, table *p256AffineTable) {
|
||||
p := NewP256Point()
|
||||
zInv := new(fiat.P256Element)
|
||||
|
||||
for j := 0; j < 32; j++ {
|
||||
p.Add(p, base)
|
||||
|
||||
// Convert p to affine coordinates.
|
||||
zInv.Invert(&p.z)
|
||||
p.x.Mul(&p.x, zInv)
|
||||
p.y.Mul(&p.y, zInv)
|
||||
p.z.One()
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
541
p384.go
Normal file
541
p384.go
Normal file
@@ -0,0 +1,541 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Code generated by generate.go. DO NOT EDIT.
|
||||
|
||||
package nistec
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"sources.truenas.cloud/code/nistec/internal/fiat"
|
||||
)
|
||||
|
||||
// p384ElementLength is the length of an element of the base or scalar field,
|
||||
// which have the same bytes length for all NIST P curves.
|
||||
const p384ElementLength = 48
|
||||
|
||||
// P384Point is a P384 point. The zero value is NOT valid.
|
||||
type P384Point struct {
|
||||
// The point is represented in projective coordinates (X:Y:Z),
|
||||
// where x = X/Z and y = Y/Z.
|
||||
x, y, z *fiat.P384Element
|
||||
}
|
||||
|
||||
// NewP384Point returns a new P384Point representing the point at infinity point.
|
||||
func NewP384Point() *P384Point {
|
||||
return &P384Point{
|
||||
x: new(fiat.P384Element),
|
||||
y: new(fiat.P384Element).One(),
|
||||
z: new(fiat.P384Element),
|
||||
}
|
||||
}
|
||||
|
||||
// SetGenerator sets p to the canonical generator and returns p.
|
||||
func (p *P384Point) SetGenerator() *P384Point {
|
||||
p.x.SetBytes([]byte{0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x5, 0x37, 0x8e, 0xb1, 0xc7, 0x1e, 0xf3, 0x20, 0xad, 0x74, 0x6e, 0x1d, 0x3b, 0x62, 0x8b, 0xa7, 0x9b, 0x98, 0x59, 0xf7, 0x41, 0xe0, 0x82, 0x54, 0x2a, 0x38, 0x55, 0x2, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c, 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0xa, 0xb7})
|
||||
p.y.SetBytes([]byte{0x36, 0x17, 0xde, 0x4a, 0x96, 0x26, 0x2c, 0x6f, 0x5d, 0x9e, 0x98, 0xbf, 0x92, 0x92, 0xdc, 0x29, 0xf8, 0xf4, 0x1d, 0xbd, 0x28, 0x9a, 0x14, 0x7c, 0xe9, 0xda, 0x31, 0x13, 0xb5, 0xf0, 0xb8, 0xc0, 0xa, 0x60, 0xb1, 0xce, 0x1d, 0x7e, 0x81, 0x9d, 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0xe, 0x5f})
|
||||
p.z.One()
|
||||
return p
|
||||
}
|
||||
|
||||
// Set sets p = q and returns p.
|
||||
func (p *P384Point) Set(q *P384Point) *P384Point {
|
||||
p.x.Set(q.x)
|
||||
p.y.Set(q.y)
|
||||
p.z.Set(q.z)
|
||||
return p
|
||||
}
|
||||
|
||||
// SetBytes sets p to the compressed, uncompressed, or infinity value encoded in
|
||||
// b, as specified in SEC 1, Version 2.0, Section 2.3.4. If the point is not on
|
||||
// the curve, it returns nil and an error, and the receiver is unchanged.
|
||||
// Otherwise, it returns p.
|
||||
func (p *P384Point) SetBytes(b []byte) (*P384Point, error) {
|
||||
switch {
|
||||
// Point at infinity.
|
||||
case len(b) == 1 && b[0] == 0:
|
||||
return p.Set(NewP384Point()), nil
|
||||
|
||||
// Uncompressed form.
|
||||
case len(b) == 1+2*p384ElementLength && b[0] == 4:
|
||||
x, err := new(fiat.P384Element).SetBytes(b[1 : 1+p384ElementLength])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
y, err := new(fiat.P384Element).SetBytes(b[1+p384ElementLength:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := p384CheckOnCurve(x, y); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.x.Set(x)
|
||||
p.y.Set(y)
|
||||
p.z.One()
|
||||
return p, nil
|
||||
|
||||
// Compressed form.
|
||||
case len(b) == 1+p384ElementLength && (b[0] == 2 || b[0] == 3):
|
||||
x, err := new(fiat.P384Element).SetBytes(b[1:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// y² = x³ - 3x + b
|
||||
y := p384Polynomial(new(fiat.P384Element), x)
|
||||
if !p384Sqrt(y, y) {
|
||||
return nil, errors.New("invalid P384 compressed point encoding")
|
||||
}
|
||||
|
||||
// Select the positive or negative root, as indicated by the least
|
||||
// significant bit, based on the encoding type byte.
|
||||
otherRoot := new(fiat.P384Element)
|
||||
otherRoot.Sub(otherRoot, y)
|
||||
cond := y.Bytes()[p384ElementLength-1]&1 ^ b[0]&1
|
||||
y.Select(otherRoot, y, int(cond))
|
||||
|
||||
p.x.Set(x)
|
||||
p.y.Set(y)
|
||||
p.z.One()
|
||||
return p, nil
|
||||
|
||||
default:
|
||||
return nil, errors.New("invalid P384 point encoding")
|
||||
}
|
||||
}
|
||||
|
||||
var _p384B *fiat.P384Element
|
||||
var _p384BOnce sync.Once
|
||||
|
||||
func p384B() *fiat.P384Element {
|
||||
_p384BOnce.Do(func() {
|
||||
_p384B, _ = new(fiat.P384Element).SetBytes([]byte{0xb3, 0x31, 0x2f, 0xa7, 0xe2, 0x3e, 0xe7, 0xe4, 0x98, 0x8e, 0x5, 0x6b, 0xe3, 0xf8, 0x2d, 0x19, 0x18, 0x1d, 0x9c, 0x6e, 0xfe, 0x81, 0x41, 0x12, 0x3, 0x14, 0x8, 0x8f, 0x50, 0x13, 0x87, 0x5a, 0xc6, 0x56, 0x39, 0x8d, 0x8a, 0x2e, 0xd1, 0x9d, 0x2a, 0x85, 0xc8, 0xed, 0xd3, 0xec, 0x2a, 0xef})
|
||||
})
|
||||
return _p384B
|
||||
}
|
||||
|
||||
// p384Polynomial sets y2 to x³ - 3x + b, and returns y2.
|
||||
func p384Polynomial(y2, x *fiat.P384Element) *fiat.P384Element {
|
||||
y2.Square(x)
|
||||
y2.Mul(y2, x)
|
||||
|
||||
threeX := new(fiat.P384Element).Add(x, x)
|
||||
threeX.Add(threeX, x)
|
||||
y2.Sub(y2, threeX)
|
||||
|
||||
return y2.Add(y2, p384B())
|
||||
}
|
||||
|
||||
func p384CheckOnCurve(x, y *fiat.P384Element) error {
|
||||
// y² = x³ - 3x + b
|
||||
rhs := p384Polynomial(new(fiat.P384Element), x)
|
||||
lhs := new(fiat.P384Element).Square(y)
|
||||
if rhs.Equal(lhs) != 1 {
|
||||
return errors.New("P384 point not on curve")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Bytes returns the uncompressed or infinity encoding of p, as specified in
|
||||
// SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the point at
|
||||
// infinity is shorter than all other encodings.
|
||||
func (p *P384Point) Bytes() []byte {
|
||||
// This function is outlined to make the allocations inline in the caller
|
||||
// rather than happen on the heap.
|
||||
var out [1 + 2*p384ElementLength]byte
|
||||
return p.bytes(&out)
|
||||
}
|
||||
|
||||
func (p *P384Point) bytes(out *[1 + 2*p384ElementLength]byte) []byte {
|
||||
if p.z.IsZero() == 1 {
|
||||
return append(out[:0], 0)
|
||||
}
|
||||
|
||||
zinv := new(fiat.P384Element).Invert(p.z)
|
||||
x := new(fiat.P384Element).Mul(p.x, zinv)
|
||||
y := new(fiat.P384Element).Mul(p.y, zinv)
|
||||
|
||||
buf := append(out[:0], 4)
|
||||
buf = append(buf, x.Bytes()...)
|
||||
buf = append(buf, y.Bytes()...)
|
||||
return buf
|
||||
}
|
||||
|
||||
// BytesX returns the encoding of the x-coordinate of p, as specified in SEC 1,
|
||||
// Version 2.0, Section 2.3.5, or an error if p is the point at infinity.
|
||||
func (p *P384Point) BytesX() ([]byte, error) {
|
||||
// This function is outlined to make the allocations inline in the caller
|
||||
// rather than happen on the heap.
|
||||
var out [p384ElementLength]byte
|
||||
return p.bytesX(&out)
|
||||
}
|
||||
|
||||
func (p *P384Point) bytesX(out *[p384ElementLength]byte) ([]byte, error) {
|
||||
if p.z.IsZero() == 1 {
|
||||
return nil, errors.New("P384 point is the point at infinity")
|
||||
}
|
||||
|
||||
zinv := new(fiat.P384Element).Invert(p.z)
|
||||
x := new(fiat.P384Element).Mul(p.x, zinv)
|
||||
|
||||
return append(out[:0], x.Bytes()...), nil
|
||||
}
|
||||
|
||||
// BytesCompressed returns the compressed or infinity encoding of p, as
|
||||
// specified in SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the
|
||||
// point at infinity is shorter than all other encodings.
|
||||
func (p *P384Point) BytesCompressed() []byte {
|
||||
// This function is outlined to make the allocations inline in the caller
|
||||
// rather than happen on the heap.
|
||||
var out [1 + p384ElementLength]byte
|
||||
return p.bytesCompressed(&out)
|
||||
}
|
||||
|
||||
func (p *P384Point) bytesCompressed(out *[1 + p384ElementLength]byte) []byte {
|
||||
if p.z.IsZero() == 1 {
|
||||
return append(out[:0], 0)
|
||||
}
|
||||
|
||||
zinv := new(fiat.P384Element).Invert(p.z)
|
||||
x := new(fiat.P384Element).Mul(p.x, zinv)
|
||||
y := new(fiat.P384Element).Mul(p.y, zinv)
|
||||
|
||||
// Encode the sign of the y coordinate (indicated by the least significant
|
||||
// bit) as the encoding type (2 or 3).
|
||||
buf := append(out[:0], 2)
|
||||
buf[0] |= y.Bytes()[p384ElementLength-1] & 1
|
||||
buf = append(buf, x.Bytes()...)
|
||||
return buf
|
||||
}
|
||||
|
||||
// Add sets q = p1 + p2, and returns q. The points may overlap.
|
||||
func (q *P384Point) Add(p1, p2 *P384Point) *P384Point {
|
||||
// Complete addition formula for a = -3 from "Complete addition formulas for
|
||||
// prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2.
|
||||
|
||||
t0 := new(fiat.P384Element).Mul(p1.x, p2.x) // t0 := X1 * X2
|
||||
t1 := new(fiat.P384Element).Mul(p1.y, p2.y) // t1 := Y1 * Y2
|
||||
t2 := new(fiat.P384Element).Mul(p1.z, p2.z) // t2 := Z1 * Z2
|
||||
t3 := new(fiat.P384Element).Add(p1.x, p1.y) // t3 := X1 + Y1
|
||||
t4 := new(fiat.P384Element).Add(p2.x, p2.y) // t4 := X2 + Y2
|
||||
t3.Mul(t3, t4) // t3 := t3 * t4
|
||||
t4.Add(t0, t1) // t4 := t0 + t1
|
||||
t3.Sub(t3, t4) // t3 := t3 - t4
|
||||
t4.Add(p1.y, p1.z) // t4 := Y1 + Z1
|
||||
x3 := new(fiat.P384Element).Add(p2.y, p2.z) // X3 := Y2 + Z2
|
||||
t4.Mul(t4, x3) // t4 := t4 * X3
|
||||
x3.Add(t1, t2) // X3 := t1 + t2
|
||||
t4.Sub(t4, x3) // t4 := t4 - X3
|
||||
x3.Add(p1.x, p1.z) // X3 := X1 + Z1
|
||||
y3 := new(fiat.P384Element).Add(p2.x, p2.z) // Y3 := X2 + Z2
|
||||
x3.Mul(x3, y3) // X3 := X3 * Y3
|
||||
y3.Add(t0, t2) // Y3 := t0 + t2
|
||||
y3.Sub(x3, y3) // Y3 := X3 - Y3
|
||||
z3 := new(fiat.P384Element).Mul(p384B(), t2) // Z3 := b * t2
|
||||
x3.Sub(y3, z3) // X3 := Y3 - Z3
|
||||
z3.Add(x3, x3) // Z3 := X3 + X3
|
||||
x3.Add(x3, z3) // X3 := X3 + Z3
|
||||
z3.Sub(t1, x3) // Z3 := t1 - X3
|
||||
x3.Add(t1, x3) // X3 := t1 + X3
|
||||
y3.Mul(p384B(), y3) // Y3 := b * Y3
|
||||
t1.Add(t2, t2) // t1 := t2 + t2
|
||||
t2.Add(t1, t2) // t2 := t1 + t2
|
||||
y3.Sub(y3, t2) // Y3 := Y3 - t2
|
||||
y3.Sub(y3, t0) // Y3 := Y3 - t0
|
||||
t1.Add(y3, y3) // t1 := Y3 + Y3
|
||||
y3.Add(t1, y3) // Y3 := t1 + Y3
|
||||
t1.Add(t0, t0) // t1 := t0 + t0
|
||||
t0.Add(t1, t0) // t0 := t1 + t0
|
||||
t0.Sub(t0, t2) // t0 := t0 - t2
|
||||
t1.Mul(t4, y3) // t1 := t4 * Y3
|
||||
t2.Mul(t0, y3) // t2 := t0 * Y3
|
||||
y3.Mul(x3, z3) // Y3 := X3 * Z3
|
||||
y3.Add(y3, t2) // Y3 := Y3 + t2
|
||||
x3.Mul(t3, x3) // X3 := t3 * X3
|
||||
x3.Sub(x3, t1) // X3 := X3 - t1
|
||||
z3.Mul(t4, z3) // Z3 := t4 * Z3
|
||||
t1.Mul(t3, t0) // t1 := t3 * t0
|
||||
z3.Add(z3, t1) // Z3 := Z3 + t1
|
||||
|
||||
q.x.Set(x3)
|
||||
q.y.Set(y3)
|
||||
q.z.Set(z3)
|
||||
return q
|
||||
}
|
||||
|
||||
// Double sets q = p + p, and returns q. The points may overlap.
|
||||
func (q *P384Point) Double(p *P384Point) *P384Point {
|
||||
// Complete addition formula for a = -3 from "Complete addition formulas for
|
||||
// prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2.
|
||||
|
||||
t0 := new(fiat.P384Element).Square(p.x) // t0 := X ^ 2
|
||||
t1 := new(fiat.P384Element).Square(p.y) // t1 := Y ^ 2
|
||||
t2 := new(fiat.P384Element).Square(p.z) // t2 := Z ^ 2
|
||||
t3 := new(fiat.P384Element).Mul(p.x, p.y) // t3 := X * Y
|
||||
t3.Add(t3, t3) // t3 := t3 + t3
|
||||
z3 := new(fiat.P384Element).Mul(p.x, p.z) // Z3 := X * Z
|
||||
z3.Add(z3, z3) // Z3 := Z3 + Z3
|
||||
y3 := new(fiat.P384Element).Mul(p384B(), t2) // Y3 := b * t2
|
||||
y3.Sub(y3, z3) // Y3 := Y3 - Z3
|
||||
x3 := new(fiat.P384Element).Add(y3, y3) // X3 := Y3 + Y3
|
||||
y3.Add(x3, y3) // Y3 := X3 + Y3
|
||||
x3.Sub(t1, y3) // X3 := t1 - Y3
|
||||
y3.Add(t1, y3) // Y3 := t1 + Y3
|
||||
y3.Mul(x3, y3) // Y3 := X3 * Y3
|
||||
x3.Mul(x3, t3) // X3 := X3 * t3
|
||||
t3.Add(t2, t2) // t3 := t2 + t2
|
||||
t2.Add(t2, t3) // t2 := t2 + t3
|
||||
z3.Mul(p384B(), z3) // Z3 := b * Z3
|
||||
z3.Sub(z3, t2) // Z3 := Z3 - t2
|
||||
z3.Sub(z3, t0) // Z3 := Z3 - t0
|
||||
t3.Add(z3, z3) // t3 := Z3 + Z3
|
||||
z3.Add(z3, t3) // Z3 := Z3 + t3
|
||||
t3.Add(t0, t0) // t3 := t0 + t0
|
||||
t0.Add(t3, t0) // t0 := t3 + t0
|
||||
t0.Sub(t0, t2) // t0 := t0 - t2
|
||||
t0.Mul(t0, z3) // t0 := t0 * Z3
|
||||
y3.Add(y3, t0) // Y3 := Y3 + t0
|
||||
t0.Mul(p.y, p.z) // t0 := Y * Z
|
||||
t0.Add(t0, t0) // t0 := t0 + t0
|
||||
z3.Mul(t0, z3) // Z3 := t0 * Z3
|
||||
x3.Sub(x3, z3) // X3 := X3 - Z3
|
||||
z3.Mul(t0, t1) // Z3 := t0 * t1
|
||||
z3.Add(z3, z3) // Z3 := Z3 + Z3
|
||||
z3.Add(z3, z3) // Z3 := Z3 + Z3
|
||||
|
||||
q.x.Set(x3)
|
||||
q.y.Set(y3)
|
||||
q.z.Set(z3)
|
||||
return q
|
||||
}
|
||||
|
||||
// Select sets q to p1 if cond == 1, and to p2 if cond == 0.
|
||||
func (q *P384Point) Select(p1, p2 *P384Point, cond int) *P384Point {
|
||||
q.x.Select(p1.x, p2.x, cond)
|
||||
q.y.Select(p1.y, p2.y, cond)
|
||||
q.z.Select(p1.z, p2.z, cond)
|
||||
return q
|
||||
}
|
||||
|
||||
// A p384Table holds the first 15 multiples of a point at offset -1, so [1]P
|
||||
// is at table[0], [15]P is at table[14], and [0]P is implicitly the identity
|
||||
// point.
|
||||
type p384Table [15]*P384Point
|
||||
|
||||
// Select selects the n-th multiple of the table base point into p. It works in
|
||||
// constant time by iterating over every entry of the table. n must be in [0, 15].
|
||||
func (table *p384Table) Select(p *P384Point, n uint8) {
|
||||
if n >= 16 {
|
||||
panic("nistec: internal error: p384Table called with out-of-bounds value")
|
||||
}
|
||||
p.Set(NewP384Point())
|
||||
for i := uint8(1); i < 16; i++ {
|
||||
cond := subtle.ConstantTimeByteEq(i, n)
|
||||
p.Select(table[i-1], p, cond)
|
||||
}
|
||||
}
|
||||
|
||||
// ScalarMult sets p = scalar * q, and returns p.
|
||||
func (p *P384Point) ScalarMult(q *P384Point, scalar []byte) (*P384Point, error) {
|
||||
// Compute a p384Table for the base point q. The explicit NewP384Point
|
||||
// calls get inlined, letting the allocations live on the stack.
|
||||
var table = p384Table{NewP384Point(), NewP384Point(), NewP384Point(),
|
||||
NewP384Point(), NewP384Point(), NewP384Point(), NewP384Point(),
|
||||
NewP384Point(), NewP384Point(), NewP384Point(), NewP384Point(),
|
||||
NewP384Point(), NewP384Point(), NewP384Point(), NewP384Point()}
|
||||
table[0].Set(q)
|
||||
for i := 1; i < 15; i += 2 {
|
||||
table[i].Double(table[i/2])
|
||||
table[i+1].Add(table[i], q)
|
||||
}
|
||||
|
||||
// Instead of doing the classic double-and-add chain, we do it with a
|
||||
// four-bit window: we double four times, and then add [0-15]P.
|
||||
t := NewP384Point()
|
||||
p.Set(NewP384Point())
|
||||
for i, byte := range scalar {
|
||||
// No need to double on the first iteration, as p is the identity at
|
||||
// this point, and [N]∞ = ∞.
|
||||
if i != 0 {
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
}
|
||||
|
||||
windowValue := byte >> 4
|
||||
table.Select(t, windowValue)
|
||||
p.Add(p, t)
|
||||
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
|
||||
windowValue = byte & 0b1111
|
||||
table.Select(t, windowValue)
|
||||
p.Add(p, t)
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
var p384GeneratorTable *[p384ElementLength * 2]p384Table
|
||||
var p384GeneratorTableOnce sync.Once
|
||||
|
||||
// generatorTable returns a sequence of p384Tables. The first table contains
|
||||
// multiples of G. Each successive table is the previous table doubled four
|
||||
// times.
|
||||
func (p *P384Point) generatorTable() *[p384ElementLength * 2]p384Table {
|
||||
p384GeneratorTableOnce.Do(func() {
|
||||
p384GeneratorTable = new([p384ElementLength * 2]p384Table)
|
||||
base := NewP384Point().SetGenerator()
|
||||
for i := 0; i < p384ElementLength*2; i++ {
|
||||
p384GeneratorTable[i][0] = NewP384Point().Set(base)
|
||||
for j := 1; j < 15; j++ {
|
||||
p384GeneratorTable[i][j] = NewP384Point().Add(p384GeneratorTable[i][j-1], base)
|
||||
}
|
||||
base.Double(base)
|
||||
base.Double(base)
|
||||
base.Double(base)
|
||||
base.Double(base)
|
||||
}
|
||||
})
|
||||
return p384GeneratorTable
|
||||
}
|
||||
|
||||
// ScalarBaseMult sets p = scalar * B, where B is the canonical generator, and
|
||||
// returns p.
|
||||
func (p *P384Point) ScalarBaseMult(scalar []byte) (*P384Point, error) {
|
||||
if len(scalar) != p384ElementLength {
|
||||
return nil, errors.New("invalid scalar length")
|
||||
}
|
||||
tables := p.generatorTable()
|
||||
|
||||
// This is also a scalar multiplication with a four-bit window like in
|
||||
// ScalarMult, but in this case the doublings are precomputed. The value
|
||||
// [windowValue]G added at iteration k would normally get doubled
|
||||
// (totIterations-k)×4 times, but with a larger precomputation we can
|
||||
// instead add [2^((totIterations-k)×4)][windowValue]G and avoid the
|
||||
// doublings between iterations.
|
||||
t := NewP384Point()
|
||||
p.Set(NewP384Point())
|
||||
tableIndex := len(tables) - 1
|
||||
for _, byte := range scalar {
|
||||
windowValue := byte >> 4
|
||||
tables[tableIndex].Select(t, windowValue)
|
||||
p.Add(p, t)
|
||||
tableIndex--
|
||||
|
||||
windowValue = byte & 0b1111
|
||||
tables[tableIndex].Select(t, windowValue)
|
||||
p.Add(p, t)
|
||||
tableIndex--
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// p384Sqrt sets e to a square root of x. If x is not a square, p384Sqrt returns
|
||||
// false and e is unchanged. e and x can overlap.
|
||||
func p384Sqrt(e, x *fiat.P384Element) (isSquare bool) {
|
||||
candidate := new(fiat.P384Element)
|
||||
p384SqrtCandidate(candidate, x)
|
||||
square := new(fiat.P384Element).Square(candidate)
|
||||
if square.Equal(x) != 1 {
|
||||
return false
|
||||
}
|
||||
e.Set(candidate)
|
||||
return true
|
||||
}
|
||||
|
||||
// p384SqrtCandidate sets z to a square root candidate for x. z and x must not overlap.
|
||||
func p384SqrtCandidate(z, x *fiat.P384Element) {
|
||||
// Since p = 3 mod 4, exponentiation by (p + 1) / 4 yields a square root candidate.
|
||||
//
|
||||
// The sequence of 14 multiplications and 381 squarings is derived from the
|
||||
// following addition chain generated with github.com/mmcloughlin/addchain v0.4.0.
|
||||
//
|
||||
// _10 = 2*1
|
||||
// _11 = 1 + _10
|
||||
// _110 = 2*_11
|
||||
// _111 = 1 + _110
|
||||
// _111000 = _111 << 3
|
||||
// _111111 = _111 + _111000
|
||||
// _1111110 = 2*_111111
|
||||
// _1111111 = 1 + _1111110
|
||||
// x12 = _1111110 << 5 + _111111
|
||||
// x24 = x12 << 12 + x12
|
||||
// x31 = x24 << 7 + _1111111
|
||||
// x32 = 2*x31 + 1
|
||||
// x63 = x32 << 31 + x31
|
||||
// x126 = x63 << 63 + x63
|
||||
// x252 = x126 << 126 + x126
|
||||
// x255 = x252 << 3 + _111
|
||||
// return ((x255 << 33 + x32) << 64 + 1) << 30
|
||||
//
|
||||
var t0 = new(fiat.P384Element)
|
||||
var t1 = new(fiat.P384Element)
|
||||
var t2 = new(fiat.P384Element)
|
||||
|
||||
z.Square(x)
|
||||
z.Mul(x, z)
|
||||
z.Square(z)
|
||||
t0.Mul(x, z)
|
||||
z.Square(t0)
|
||||
for s := 1; s < 3; s++ {
|
||||
z.Square(z)
|
||||
}
|
||||
t1.Mul(t0, z)
|
||||
t2.Square(t1)
|
||||
z.Mul(x, t2)
|
||||
for s := 0; s < 5; s++ {
|
||||
t2.Square(t2)
|
||||
}
|
||||
t1.Mul(t1, t2)
|
||||
t2.Square(t1)
|
||||
for s := 1; s < 12; s++ {
|
||||
t2.Square(t2)
|
||||
}
|
||||
t1.Mul(t1, t2)
|
||||
for s := 0; s < 7; s++ {
|
||||
t1.Square(t1)
|
||||
}
|
||||
t1.Mul(z, t1)
|
||||
z.Square(t1)
|
||||
z.Mul(x, z)
|
||||
t2.Square(z)
|
||||
for s := 1; s < 31; s++ {
|
||||
t2.Square(t2)
|
||||
}
|
||||
t1.Mul(t1, t2)
|
||||
t2.Square(t1)
|
||||
for s := 1; s < 63; s++ {
|
||||
t2.Square(t2)
|
||||
}
|
||||
t1.Mul(t1, t2)
|
||||
t2.Square(t1)
|
||||
for s := 1; s < 126; s++ {
|
||||
t2.Square(t2)
|
||||
}
|
||||
t1.Mul(t1, t2)
|
||||
for s := 0; s < 3; s++ {
|
||||
t1.Square(t1)
|
||||
}
|
||||
t0.Mul(t0, t1)
|
||||
for s := 0; s < 33; s++ {
|
||||
t0.Square(t0)
|
||||
}
|
||||
z.Mul(z, t0)
|
||||
for s := 0; s < 64; s++ {
|
||||
z.Square(z)
|
||||
}
|
||||
z.Mul(x, z)
|
||||
for s := 0; s < 30; s++ {
|
||||
z.Square(z)
|
||||
}
|
||||
}
|
||||
470
p521.go
Normal file
470
p521.go
Normal file
@@ -0,0 +1,470 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Code generated by generate.go. DO NOT EDIT.
|
||||
|
||||
package nistec
|
||||
|
||||
import (
|
||||
"crypto/subtle"
|
||||
"errors"
|
||||
"sync"
|
||||
|
||||
"sources.truenas.cloud/code/nistec/internal/fiat"
|
||||
)
|
||||
|
||||
// p521ElementLength is the length of an element of the base or scalar field,
|
||||
// which have the same bytes length for all NIST P curves.
|
||||
const p521ElementLength = 66
|
||||
|
||||
// P521Point is a P521 point. The zero value is NOT valid.
|
||||
type P521Point struct {
|
||||
// The point is represented in projective coordinates (X:Y:Z),
|
||||
// where x = X/Z and y = Y/Z.
|
||||
x, y, z *fiat.P521Element
|
||||
}
|
||||
|
||||
// NewP521Point returns a new P521Point representing the point at infinity point.
|
||||
func NewP521Point() *P521Point {
|
||||
return &P521Point{
|
||||
x: new(fiat.P521Element),
|
||||
y: new(fiat.P521Element).One(),
|
||||
z: new(fiat.P521Element),
|
||||
}
|
||||
}
|
||||
|
||||
// SetGenerator sets p to the canonical generator and returns p.
|
||||
func (p *P521Point) SetGenerator() *P521Point {
|
||||
p.x.SetBytes([]byte{0x0, 0xc6, 0x85, 0x8e, 0x6, 0xb7, 0x4, 0x4, 0xe9, 0xcd, 0x9e, 0x3e, 0xcb, 0x66, 0x23, 0x95, 0xb4, 0x42, 0x9c, 0x64, 0x81, 0x39, 0x5, 0x3f, 0xb5, 0x21, 0xf8, 0x28, 0xaf, 0x60, 0x6b, 0x4d, 0x3d, 0xba, 0xa1, 0x4b, 0x5e, 0x77, 0xef, 0xe7, 0x59, 0x28, 0xfe, 0x1d, 0xc1, 0x27, 0xa2, 0xff, 0xa8, 0xde, 0x33, 0x48, 0xb3, 0xc1, 0x85, 0x6a, 0x42, 0x9b, 0xf9, 0x7e, 0x7e, 0x31, 0xc2, 0xe5, 0xbd, 0x66})
|
||||
p.y.SetBytes([]byte{0x1, 0x18, 0x39, 0x29, 0x6a, 0x78, 0x9a, 0x3b, 0xc0, 0x4, 0x5c, 0x8a, 0x5f, 0xb4, 0x2c, 0x7d, 0x1b, 0xd9, 0x98, 0xf5, 0x44, 0x49, 0x57, 0x9b, 0x44, 0x68, 0x17, 0xaf, 0xbd, 0x17, 0x27, 0x3e, 0x66, 0x2c, 0x97, 0xee, 0x72, 0x99, 0x5e, 0xf4, 0x26, 0x40, 0xc5, 0x50, 0xb9, 0x1, 0x3f, 0xad, 0x7, 0x61, 0x35, 0x3c, 0x70, 0x86, 0xa2, 0x72, 0xc2, 0x40, 0x88, 0xbe, 0x94, 0x76, 0x9f, 0xd1, 0x66, 0x50})
|
||||
p.z.One()
|
||||
return p
|
||||
}
|
||||
|
||||
// Set sets p = q and returns p.
|
||||
func (p *P521Point) Set(q *P521Point) *P521Point {
|
||||
p.x.Set(q.x)
|
||||
p.y.Set(q.y)
|
||||
p.z.Set(q.z)
|
||||
return p
|
||||
}
|
||||
|
||||
// SetBytes sets p to the compressed, uncompressed, or infinity value encoded in
|
||||
// b, as specified in SEC 1, Version 2.0, Section 2.3.4. If the point is not on
|
||||
// the curve, it returns nil and an error, and the receiver is unchanged.
|
||||
// Otherwise, it returns p.
|
||||
func (p *P521Point) SetBytes(b []byte) (*P521Point, error) {
|
||||
switch {
|
||||
// Point at infinity.
|
||||
case len(b) == 1 && b[0] == 0:
|
||||
return p.Set(NewP521Point()), nil
|
||||
|
||||
// Uncompressed form.
|
||||
case len(b) == 1+2*p521ElementLength && b[0] == 4:
|
||||
x, err := new(fiat.P521Element).SetBytes(b[1 : 1+p521ElementLength])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
y, err := new(fiat.P521Element).SetBytes(b[1+p521ElementLength:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := p521CheckOnCurve(x, y); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.x.Set(x)
|
||||
p.y.Set(y)
|
||||
p.z.One()
|
||||
return p, nil
|
||||
|
||||
// Compressed form.
|
||||
case len(b) == 1+p521ElementLength && (b[0] == 2 || b[0] == 3):
|
||||
x, err := new(fiat.P521Element).SetBytes(b[1:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// y² = x³ - 3x + b
|
||||
y := p521Polynomial(new(fiat.P521Element), x)
|
||||
if !p521Sqrt(y, y) {
|
||||
return nil, errors.New("invalid P521 compressed point encoding")
|
||||
}
|
||||
|
||||
// Select the positive or negative root, as indicated by the least
|
||||
// significant bit, based on the encoding type byte.
|
||||
otherRoot := new(fiat.P521Element)
|
||||
otherRoot.Sub(otherRoot, y)
|
||||
cond := y.Bytes()[p521ElementLength-1]&1 ^ b[0]&1
|
||||
y.Select(otherRoot, y, int(cond))
|
||||
|
||||
p.x.Set(x)
|
||||
p.y.Set(y)
|
||||
p.z.One()
|
||||
return p, nil
|
||||
|
||||
default:
|
||||
return nil, errors.New("invalid P521 point encoding")
|
||||
}
|
||||
}
|
||||
|
||||
var _p521B *fiat.P521Element
|
||||
var _p521BOnce sync.Once
|
||||
|
||||
func p521B() *fiat.P521Element {
|
||||
_p521BOnce.Do(func() {
|
||||
_p521B, _ = new(fiat.P521Element).SetBytes([]byte{0x0, 0x51, 0x95, 0x3e, 0xb9, 0x61, 0x8e, 0x1c, 0x9a, 0x1f, 0x92, 0x9a, 0x21, 0xa0, 0xb6, 0x85, 0x40, 0xee, 0xa2, 0xda, 0x72, 0x5b, 0x99, 0xb3, 0x15, 0xf3, 0xb8, 0xb4, 0x89, 0x91, 0x8e, 0xf1, 0x9, 0xe1, 0x56, 0x19, 0x39, 0x51, 0xec, 0x7e, 0x93, 0x7b, 0x16, 0x52, 0xc0, 0xbd, 0x3b, 0xb1, 0xbf, 0x7, 0x35, 0x73, 0xdf, 0x88, 0x3d, 0x2c, 0x34, 0xf1, 0xef, 0x45, 0x1f, 0xd4, 0x6b, 0x50, 0x3f, 0x0})
|
||||
})
|
||||
return _p521B
|
||||
}
|
||||
|
||||
// p521Polynomial sets y2 to x³ - 3x + b, and returns y2.
|
||||
func p521Polynomial(y2, x *fiat.P521Element) *fiat.P521Element {
|
||||
y2.Square(x)
|
||||
y2.Mul(y2, x)
|
||||
|
||||
threeX := new(fiat.P521Element).Add(x, x)
|
||||
threeX.Add(threeX, x)
|
||||
y2.Sub(y2, threeX)
|
||||
|
||||
return y2.Add(y2, p521B())
|
||||
}
|
||||
|
||||
func p521CheckOnCurve(x, y *fiat.P521Element) error {
|
||||
// y² = x³ - 3x + b
|
||||
rhs := p521Polynomial(new(fiat.P521Element), x)
|
||||
lhs := new(fiat.P521Element).Square(y)
|
||||
if rhs.Equal(lhs) != 1 {
|
||||
return errors.New("P521 point not on curve")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Bytes returns the uncompressed or infinity encoding of p, as specified in
|
||||
// SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the point at
|
||||
// infinity is shorter than all other encodings.
|
||||
func (p *P521Point) Bytes() []byte {
|
||||
// This function is outlined to make the allocations inline in the caller
|
||||
// rather than happen on the heap.
|
||||
var out [1 + 2*p521ElementLength]byte
|
||||
return p.bytes(&out)
|
||||
}
|
||||
|
||||
func (p *P521Point) bytes(out *[1 + 2*p521ElementLength]byte) []byte {
|
||||
if p.z.IsZero() == 1 {
|
||||
return append(out[:0], 0)
|
||||
}
|
||||
|
||||
zinv := new(fiat.P521Element).Invert(p.z)
|
||||
x := new(fiat.P521Element).Mul(p.x, zinv)
|
||||
y := new(fiat.P521Element).Mul(p.y, zinv)
|
||||
|
||||
buf := append(out[:0], 4)
|
||||
buf = append(buf, x.Bytes()...)
|
||||
buf = append(buf, y.Bytes()...)
|
||||
return buf
|
||||
}
|
||||
|
||||
// BytesX returns the encoding of the x-coordinate of p, as specified in SEC 1,
|
||||
// Version 2.0, Section 2.3.5, or an error if p is the point at infinity.
|
||||
func (p *P521Point) BytesX() ([]byte, error) {
|
||||
// This function is outlined to make the allocations inline in the caller
|
||||
// rather than happen on the heap.
|
||||
var out [p521ElementLength]byte
|
||||
return p.bytesX(&out)
|
||||
}
|
||||
|
||||
func (p *P521Point) bytesX(out *[p521ElementLength]byte) ([]byte, error) {
|
||||
if p.z.IsZero() == 1 {
|
||||
return nil, errors.New("P521 point is the point at infinity")
|
||||
}
|
||||
|
||||
zinv := new(fiat.P521Element).Invert(p.z)
|
||||
x := new(fiat.P521Element).Mul(p.x, zinv)
|
||||
|
||||
return append(out[:0], x.Bytes()...), nil
|
||||
}
|
||||
|
||||
// BytesCompressed returns the compressed or infinity encoding of p, as
|
||||
// specified in SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the
|
||||
// point at infinity is shorter than all other encodings.
|
||||
func (p *P521Point) BytesCompressed() []byte {
|
||||
// This function is outlined to make the allocations inline in the caller
|
||||
// rather than happen on the heap.
|
||||
var out [1 + p521ElementLength]byte
|
||||
return p.bytesCompressed(&out)
|
||||
}
|
||||
|
||||
func (p *P521Point) bytesCompressed(out *[1 + p521ElementLength]byte) []byte {
|
||||
if p.z.IsZero() == 1 {
|
||||
return append(out[:0], 0)
|
||||
}
|
||||
|
||||
zinv := new(fiat.P521Element).Invert(p.z)
|
||||
x := new(fiat.P521Element).Mul(p.x, zinv)
|
||||
y := new(fiat.P521Element).Mul(p.y, zinv)
|
||||
|
||||
// Encode the sign of the y coordinate (indicated by the least significant
|
||||
// bit) as the encoding type (2 or 3).
|
||||
buf := append(out[:0], 2)
|
||||
buf[0] |= y.Bytes()[p521ElementLength-1] & 1
|
||||
buf = append(buf, x.Bytes()...)
|
||||
return buf
|
||||
}
|
||||
|
||||
// Add sets q = p1 + p2, and returns q. The points may overlap.
|
||||
func (q *P521Point) Add(p1, p2 *P521Point) *P521Point {
|
||||
// Complete addition formula for a = -3 from "Complete addition formulas for
|
||||
// prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2.
|
||||
|
||||
t0 := new(fiat.P521Element).Mul(p1.x, p2.x) // t0 := X1 * X2
|
||||
t1 := new(fiat.P521Element).Mul(p1.y, p2.y) // t1 := Y1 * Y2
|
||||
t2 := new(fiat.P521Element).Mul(p1.z, p2.z) // t2 := Z1 * Z2
|
||||
t3 := new(fiat.P521Element).Add(p1.x, p1.y) // t3 := X1 + Y1
|
||||
t4 := new(fiat.P521Element).Add(p2.x, p2.y) // t4 := X2 + Y2
|
||||
t3.Mul(t3, t4) // t3 := t3 * t4
|
||||
t4.Add(t0, t1) // t4 := t0 + t1
|
||||
t3.Sub(t3, t4) // t3 := t3 - t4
|
||||
t4.Add(p1.y, p1.z) // t4 := Y1 + Z1
|
||||
x3 := new(fiat.P521Element).Add(p2.y, p2.z) // X3 := Y2 + Z2
|
||||
t4.Mul(t4, x3) // t4 := t4 * X3
|
||||
x3.Add(t1, t2) // X3 := t1 + t2
|
||||
t4.Sub(t4, x3) // t4 := t4 - X3
|
||||
x3.Add(p1.x, p1.z) // X3 := X1 + Z1
|
||||
y3 := new(fiat.P521Element).Add(p2.x, p2.z) // Y3 := X2 + Z2
|
||||
x3.Mul(x3, y3) // X3 := X3 * Y3
|
||||
y3.Add(t0, t2) // Y3 := t0 + t2
|
||||
y3.Sub(x3, y3) // Y3 := X3 - Y3
|
||||
z3 := new(fiat.P521Element).Mul(p521B(), t2) // Z3 := b * t2
|
||||
x3.Sub(y3, z3) // X3 := Y3 - Z3
|
||||
z3.Add(x3, x3) // Z3 := X3 + X3
|
||||
x3.Add(x3, z3) // X3 := X3 + Z3
|
||||
z3.Sub(t1, x3) // Z3 := t1 - X3
|
||||
x3.Add(t1, x3) // X3 := t1 + X3
|
||||
y3.Mul(p521B(), y3) // Y3 := b * Y3
|
||||
t1.Add(t2, t2) // t1 := t2 + t2
|
||||
t2.Add(t1, t2) // t2 := t1 + t2
|
||||
y3.Sub(y3, t2) // Y3 := Y3 - t2
|
||||
y3.Sub(y3, t0) // Y3 := Y3 - t0
|
||||
t1.Add(y3, y3) // t1 := Y3 + Y3
|
||||
y3.Add(t1, y3) // Y3 := t1 + Y3
|
||||
t1.Add(t0, t0) // t1 := t0 + t0
|
||||
t0.Add(t1, t0) // t0 := t1 + t0
|
||||
t0.Sub(t0, t2) // t0 := t0 - t2
|
||||
t1.Mul(t4, y3) // t1 := t4 * Y3
|
||||
t2.Mul(t0, y3) // t2 := t0 * Y3
|
||||
y3.Mul(x3, z3) // Y3 := X3 * Z3
|
||||
y3.Add(y3, t2) // Y3 := Y3 + t2
|
||||
x3.Mul(t3, x3) // X3 := t3 * X3
|
||||
x3.Sub(x3, t1) // X3 := X3 - t1
|
||||
z3.Mul(t4, z3) // Z3 := t4 * Z3
|
||||
t1.Mul(t3, t0) // t1 := t3 * t0
|
||||
z3.Add(z3, t1) // Z3 := Z3 + t1
|
||||
|
||||
q.x.Set(x3)
|
||||
q.y.Set(y3)
|
||||
q.z.Set(z3)
|
||||
return q
|
||||
}
|
||||
|
||||
// Double sets q = p + p, and returns q. The points may overlap.
|
||||
func (q *P521Point) Double(p *P521Point) *P521Point {
|
||||
// Complete addition formula for a = -3 from "Complete addition formulas for
|
||||
// prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2.
|
||||
|
||||
t0 := new(fiat.P521Element).Square(p.x) // t0 := X ^ 2
|
||||
t1 := new(fiat.P521Element).Square(p.y) // t1 := Y ^ 2
|
||||
t2 := new(fiat.P521Element).Square(p.z) // t2 := Z ^ 2
|
||||
t3 := new(fiat.P521Element).Mul(p.x, p.y) // t3 := X * Y
|
||||
t3.Add(t3, t3) // t3 := t3 + t3
|
||||
z3 := new(fiat.P521Element).Mul(p.x, p.z) // Z3 := X * Z
|
||||
z3.Add(z3, z3) // Z3 := Z3 + Z3
|
||||
y3 := new(fiat.P521Element).Mul(p521B(), t2) // Y3 := b * t2
|
||||
y3.Sub(y3, z3) // Y3 := Y3 - Z3
|
||||
x3 := new(fiat.P521Element).Add(y3, y3) // X3 := Y3 + Y3
|
||||
y3.Add(x3, y3) // Y3 := X3 + Y3
|
||||
x3.Sub(t1, y3) // X3 := t1 - Y3
|
||||
y3.Add(t1, y3) // Y3 := t1 + Y3
|
||||
y3.Mul(x3, y3) // Y3 := X3 * Y3
|
||||
x3.Mul(x3, t3) // X3 := X3 * t3
|
||||
t3.Add(t2, t2) // t3 := t2 + t2
|
||||
t2.Add(t2, t3) // t2 := t2 + t3
|
||||
z3.Mul(p521B(), z3) // Z3 := b * Z3
|
||||
z3.Sub(z3, t2) // Z3 := Z3 - t2
|
||||
z3.Sub(z3, t0) // Z3 := Z3 - t0
|
||||
t3.Add(z3, z3) // t3 := Z3 + Z3
|
||||
z3.Add(z3, t3) // Z3 := Z3 + t3
|
||||
t3.Add(t0, t0) // t3 := t0 + t0
|
||||
t0.Add(t3, t0) // t0 := t3 + t0
|
||||
t0.Sub(t0, t2) // t0 := t0 - t2
|
||||
t0.Mul(t0, z3) // t0 := t0 * Z3
|
||||
y3.Add(y3, t0) // Y3 := Y3 + t0
|
||||
t0.Mul(p.y, p.z) // t0 := Y * Z
|
||||
t0.Add(t0, t0) // t0 := t0 + t0
|
||||
z3.Mul(t0, z3) // Z3 := t0 * Z3
|
||||
x3.Sub(x3, z3) // X3 := X3 - Z3
|
||||
z3.Mul(t0, t1) // Z3 := t0 * t1
|
||||
z3.Add(z3, z3) // Z3 := Z3 + Z3
|
||||
z3.Add(z3, z3) // Z3 := Z3 + Z3
|
||||
|
||||
q.x.Set(x3)
|
||||
q.y.Set(y3)
|
||||
q.z.Set(z3)
|
||||
return q
|
||||
}
|
||||
|
||||
// Select sets q to p1 if cond == 1, and to p2 if cond == 0.
|
||||
func (q *P521Point) Select(p1, p2 *P521Point, cond int) *P521Point {
|
||||
q.x.Select(p1.x, p2.x, cond)
|
||||
q.y.Select(p1.y, p2.y, cond)
|
||||
q.z.Select(p1.z, p2.z, cond)
|
||||
return q
|
||||
}
|
||||
|
||||
// A p521Table holds the first 15 multiples of a point at offset -1, so [1]P
|
||||
// is at table[0], [15]P is at table[14], and [0]P is implicitly the identity
|
||||
// point.
|
||||
type p521Table [15]*P521Point
|
||||
|
||||
// Select selects the n-th multiple of the table base point into p. It works in
|
||||
// constant time by iterating over every entry of the table. n must be in [0, 15].
|
||||
func (table *p521Table) Select(p *P521Point, n uint8) {
|
||||
if n >= 16 {
|
||||
panic("nistec: internal error: p521Table called with out-of-bounds value")
|
||||
}
|
||||
p.Set(NewP521Point())
|
||||
for i := uint8(1); i < 16; i++ {
|
||||
cond := subtle.ConstantTimeByteEq(i, n)
|
||||
p.Select(table[i-1], p, cond)
|
||||
}
|
||||
}
|
||||
|
||||
// ScalarMult sets p = scalar * q, and returns p.
|
||||
func (p *P521Point) ScalarMult(q *P521Point, scalar []byte) (*P521Point, error) {
|
||||
// Compute a p521Table for the base point q. The explicit NewP521Point
|
||||
// calls get inlined, letting the allocations live on the stack.
|
||||
var table = p521Table{NewP521Point(), NewP521Point(), NewP521Point(),
|
||||
NewP521Point(), NewP521Point(), NewP521Point(), NewP521Point(),
|
||||
NewP521Point(), NewP521Point(), NewP521Point(), NewP521Point(),
|
||||
NewP521Point(), NewP521Point(), NewP521Point(), NewP521Point()}
|
||||
table[0].Set(q)
|
||||
for i := 1; i < 15; i += 2 {
|
||||
table[i].Double(table[i/2])
|
||||
table[i+1].Add(table[i], q)
|
||||
}
|
||||
|
||||
// Instead of doing the classic double-and-add chain, we do it with a
|
||||
// four-bit window: we double four times, and then add [0-15]P.
|
||||
t := NewP521Point()
|
||||
p.Set(NewP521Point())
|
||||
for i, byte := range scalar {
|
||||
// No need to double on the first iteration, as p is the identity at
|
||||
// this point, and [N]∞ = ∞.
|
||||
if i != 0 {
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
}
|
||||
|
||||
windowValue := byte >> 4
|
||||
table.Select(t, windowValue)
|
||||
p.Add(p, t)
|
||||
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
p.Double(p)
|
||||
|
||||
windowValue = byte & 0b1111
|
||||
table.Select(t, windowValue)
|
||||
p.Add(p, t)
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
var p521GeneratorTable *[p521ElementLength * 2]p521Table
|
||||
var p521GeneratorTableOnce sync.Once
|
||||
|
||||
// generatorTable returns a sequence of p521Tables. The first table contains
|
||||
// multiples of G. Each successive table is the previous table doubled four
|
||||
// times.
|
||||
func (p *P521Point) generatorTable() *[p521ElementLength * 2]p521Table {
|
||||
p521GeneratorTableOnce.Do(func() {
|
||||
p521GeneratorTable = new([p521ElementLength * 2]p521Table)
|
||||
base := NewP521Point().SetGenerator()
|
||||
for i := 0; i < p521ElementLength*2; i++ {
|
||||
p521GeneratorTable[i][0] = NewP521Point().Set(base)
|
||||
for j := 1; j < 15; j++ {
|
||||
p521GeneratorTable[i][j] = NewP521Point().Add(p521GeneratorTable[i][j-1], base)
|
||||
}
|
||||
base.Double(base)
|
||||
base.Double(base)
|
||||
base.Double(base)
|
||||
base.Double(base)
|
||||
}
|
||||
})
|
||||
return p521GeneratorTable
|
||||
}
|
||||
|
||||
// ScalarBaseMult sets p = scalar * B, where B is the canonical generator, and
|
||||
// returns p.
|
||||
func (p *P521Point) ScalarBaseMult(scalar []byte) (*P521Point, error) {
|
||||
if len(scalar) != p521ElementLength {
|
||||
return nil, errors.New("invalid scalar length")
|
||||
}
|
||||
tables := p.generatorTable()
|
||||
|
||||
// This is also a scalar multiplication with a four-bit window like in
|
||||
// ScalarMult, but in this case the doublings are precomputed. The value
|
||||
// [windowValue]G added at iteration k would normally get doubled
|
||||
// (totIterations-k)×4 times, but with a larger precomputation we can
|
||||
// instead add [2^((totIterations-k)×4)][windowValue]G and avoid the
|
||||
// doublings between iterations.
|
||||
t := NewP521Point()
|
||||
p.Set(NewP521Point())
|
||||
tableIndex := len(tables) - 1
|
||||
for _, byte := range scalar {
|
||||
windowValue := byte >> 4
|
||||
tables[tableIndex].Select(t, windowValue)
|
||||
p.Add(p, t)
|
||||
tableIndex--
|
||||
|
||||
windowValue = byte & 0b1111
|
||||
tables[tableIndex].Select(t, windowValue)
|
||||
p.Add(p, t)
|
||||
tableIndex--
|
||||
}
|
||||
|
||||
return p, nil
|
||||
}
|
||||
|
||||
// p521Sqrt sets e to a square root of x. If x is not a square, p521Sqrt returns
|
||||
// false and e is unchanged. e and x can overlap.
|
||||
func p521Sqrt(e, x *fiat.P521Element) (isSquare bool) {
|
||||
candidate := new(fiat.P521Element)
|
||||
p521SqrtCandidate(candidate, x)
|
||||
square := new(fiat.P521Element).Square(candidate)
|
||||
if square.Equal(x) != 1 {
|
||||
return false
|
||||
}
|
||||
e.Set(candidate)
|
||||
return true
|
||||
}
|
||||
|
||||
// p521SqrtCandidate sets z to a square root candidate for x. z and x must not overlap.
|
||||
func p521SqrtCandidate(z, x *fiat.P521Element) {
|
||||
// Since p = 3 mod 4, exponentiation by (p + 1) / 4 yields a square root candidate.
|
||||
//
|
||||
// The sequence of 0 multiplications and 519 squarings is derived from the
|
||||
// following addition chain generated with github.com/mmcloughlin/addchain v0.4.0.
|
||||
//
|
||||
// return 1 << 519
|
||||
//
|
||||
|
||||
z.Square(x)
|
||||
for s := 1; s < 519; s++ {
|
||||
z.Square(z)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user