all: flatten the package and make FieldElement opaque

For the license changes, see gtank/ristretto255-private#28 and
gtank/ristretto255#32, that contribute all code in those repositories to
the Go project under the Google CLA.
This commit is contained in:
Filippo Valsorda 2020-08-30 23:20:54 -04:00
parent 6f5f5828e1
commit d3569cbbb3
20 changed files with 274 additions and 291 deletions

View file

@ -1,6 +1,4 @@
Copyright (c) 2009 The Go Authors. All rights reserved.
Copyright (c) 2017 George Tankersley. All rights reserved.
Copyright (c) 2019 Henry de Valence. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are

View file

@ -1,5 +1,4 @@
// Copyright (c) 2017 George Tankersley. All rights reserved.
// Copyright (c) 2019 The Go Authors. All rights reserved.
// Copyright (c) 2017 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.
@ -7,16 +6,23 @@
//
// -x^2 + y^2 = 1 + -(121665/121666)*x^2*y^2
//
// This is better known as the Edwards curve equivalent to curve25519, and is
// as well as GF(2^255-19) field arithmetic.
//
// This is better known as the Edwards curve equivalent to Curve25519, and is
// the curve used by the Ed25519 signature scheme.
//
// Most users don't need this package, and should instead use crypto/ed25519 for
// signatures, golang.org/x/crypto/curve25519 for Diffie-Hellman, or
// github.com/gtank/ristretto255 for prime order group logic. However, for
// anyone currently using a fork of crypto/ed25519/internal/edwards25519 or
// github.com/agl/edwards25519, this package should be a safer, faster, and more
// powerful alternative.
package edwards25519
import "filippo.io/edwards25519/base"
// D is a constant in the curve equation.
var D = &base.FieldElement{929955233495203, 466365720129213,
var D = &FieldElement{929955233495203, 466365720129213,
1662059464998953, 2033849074728123, 1442794654840575}
var d2 = new(base.FieldElement).Add(D, D)
var d2 = new(FieldElement).Add(D, D)
// Point types.
@ -25,31 +31,31 @@ var d2 = new(base.FieldElement).Add(D, D)
// https://doc-internal.dalek.rs/curve25519_dalek/backend/serial/curve_models/index.html
type ProjP1xP1 struct {
X, Y, Z, T base.FieldElement
X, Y, Z, T FieldElement
}
type ProjP2 struct {
X, Y, Z base.FieldElement
X, Y, Z FieldElement
}
type ProjP3 struct {
X, Y, Z, T base.FieldElement
X, Y, Z, T FieldElement
}
type ProjCached struct {
YplusX, YminusX, Z, T2d base.FieldElement
YplusX, YminusX, Z, T2d FieldElement
}
type AffineCached struct {
YplusX, YminusX, T2d base.FieldElement
YplusX, YminusX, T2d FieldElement
}
// B is the Ed25519 basepoint.
var B = ProjP3{
X: base.FieldElement([5]uint64{1738742601995546, 1146398526822698, 2070867633025821, 562264141797630, 587772402128613}),
Y: base.FieldElement([5]uint64{1801439850948184, 1351079888211148, 450359962737049, 900719925474099, 1801439850948198}),
Z: base.FieldElement([5]uint64{1, 0, 0, 0, 0}),
T: base.FieldElement([5]uint64{1841354044333475, 16398895984059, 755974180946558, 900171276175154, 1821297809914039}),
X: FieldElement{1738742601995546, 1146398526822698, 2070867633025821, 562264141797630, 587772402128613},
Y: FieldElement{1801439850948184, 1351079888211148, 450359962737049, 900719925474099, 1801439850948198},
Z: FieldElement{1, 0, 0, 0, 0},
T: FieldElement{1841354044333475, 16398895984059, 755974180946558, 900171276175154, 1821297809914039},
}
// Constructors.
@ -144,7 +150,7 @@ func (v *AffineCached) FromP3(p *ProjP3) *AffineCached {
v.YminusX.Sub(&p.Y, &p.X)
v.T2d.Mul(&p.T, d2)
var invZ base.FieldElement
var invZ FieldElement
invZ.Invert(&p.Z)
v.YplusX.Mul(&v.YplusX, &invZ)
v.YminusX.Mul(&v.YminusX, &invZ)
@ -173,7 +179,7 @@ func (v *ProjP3) Sub(p, q *ProjP3) *ProjP3 {
}
func (v *ProjP1xP1) Add(p *ProjP3, q *ProjCached) *ProjP1xP1 {
var YplusX, YminusX, PP, MM, TT2d, ZZ2 base.FieldElement
var YplusX, YminusX, PP, MM, TT2d, ZZ2 FieldElement
YplusX.Add(&p.Y, &p.X)
YminusX.Sub(&p.Y, &p.X)
@ -193,7 +199,7 @@ func (v *ProjP1xP1) Add(p *ProjP3, q *ProjCached) *ProjP1xP1 {
}
func (v *ProjP1xP1) Sub(p *ProjP3, q *ProjCached) *ProjP1xP1 {
var YplusX, YminusX, PP, MM, TT2d, ZZ2 base.FieldElement
var YplusX, YminusX, PP, MM, TT2d, ZZ2 FieldElement
YplusX.Add(&p.Y, &p.X)
YminusX.Sub(&p.Y, &p.X)
@ -213,7 +219,7 @@ func (v *ProjP1xP1) Sub(p *ProjP3, q *ProjCached) *ProjP1xP1 {
}
func (v *ProjP1xP1) AddAffine(p *ProjP3, q *AffineCached) *ProjP1xP1 {
var YplusX, YminusX, PP, MM, TT2d, Z2 base.FieldElement
var YplusX, YminusX, PP, MM, TT2d, Z2 FieldElement
YplusX.Add(&p.Y, &p.X)
YminusX.Sub(&p.Y, &p.X)
@ -232,7 +238,7 @@ func (v *ProjP1xP1) AddAffine(p *ProjP3, q *AffineCached) *ProjP1xP1 {
}
func (v *ProjP1xP1) SubAffine(p *ProjP3, q *AffineCached) *ProjP1xP1 {
var YplusX, YminusX, PP, MM, TT2d, Z2 base.FieldElement
var YplusX, YminusX, PP, MM, TT2d, Z2 FieldElement
YplusX.Add(&p.Y, &p.X)
YminusX.Sub(&p.Y, &p.X)
@ -253,7 +259,7 @@ func (v *ProjP1xP1) SubAffine(p *ProjP3, q *AffineCached) *ProjP1xP1 {
// Doubling.
func (v *ProjP1xP1) Double(p *ProjP2) *ProjP1xP1 {
var XX, YY, ZZ2, XplusYsq base.FieldElement
var XX, YY, ZZ2, XplusYsq FieldElement
XX.Square(&p.X)
YY.Square(&p.Y)
@ -283,7 +289,7 @@ func (v *ProjP3) Neg(p *ProjP3) *ProjP3 {
// by @ebfull
// https://github.com/dalek-cryptography/curve25519-dalek/pull/226/files
func (v *ProjP3) Equal(u *ProjP3) int {
var t1, t2, t3, t4 base.FieldElement
var t1, t2, t3, t4 FieldElement
t1.Mul(&v.X, &u.Z)
t2.Mul(&u.X, &v.Z)
t3.Mul(&v.Y, &u.Z)
@ -313,14 +319,14 @@ func (v *AffineCached) Select(a, b *AffineCached, cond int) *AffineCached {
// CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0.
func (v *ProjCached) CondNeg(cond int) *ProjCached {
base.CondSwap(&v.YplusX, &v.YminusX, cond)
CondSwap(&v.YplusX, &v.YminusX, cond)
v.T2d.CondNeg(&v.T2d, cond)
return v
}
// CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0.
func (v *AffineCached) CondNeg(cond int) *AffineCached {
base.CondSwap(&v.YplusX, &v.YminusX, cond)
CondSwap(&v.YplusX, &v.YminusX, cond)
v.T2d.CondNeg(&v.T2d, cond)
return v
}

View file

@ -1,4 +1,4 @@
// Copyright 2019 Henry de Valence. All rights reserved.
// Copyright (c) 2019 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.

View file

@ -1,15 +1,8 @@
// Copyright (c) 2017 George Tankersley. All rights reserved.
// Copyright (c) 2019 The Go Authors. All rights reserved.
// Copyright (c) 2017 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 base implements GF(2^255-19) field arithmetic in radix 2^51
// representation. This code is a port of the public domain amd64-51-30k version
// of ed25519 from SUPERCOP.
//
// The interface works similarly to math/big.Int, and all arguments and
// receivers are allowed to alias.
package base
package edwards25519
import (
"crypto/subtle"
@ -18,15 +11,24 @@ import (
"math/bits"
)
// FieldElement represents an element of the field GF(2^255-19). An element t
// represents the integer t[0] + t[1]*2^51 + t[2]*2^102 + t[3]*2^153 +
// t[4]*2^204.
// FieldElement represents an element of the field GF(2^255-19).
//
// Between operations, all limbs are expected to be lower than 2^51, except the
// first one, which can be up to 2^255 + 2^13 * 19 due to carry propagation.
// This type works similarly to math/big.Int, and all arguments and
// receivers are allowed to alias.
//
// The zero value is a valid zero element.
type FieldElement [5]uint64
type FieldElement struct {
// An element t represents the integer
// t.l0 + t.l1*2^51 + t.l2*2^102 + t.l3*2^153 + t.l4*2^204
//
// Between operations, all limbs are expected to be lower than 2^51, except
// l0, which can be up to 2^255 + 2^13 * 19 due to carry propagation.
l0 uint64
l1 uint64
l2 uint64
l3 uint64
l4 uint64
}
const maskLow51Bits uint64 = (1 << 51) - 1
@ -53,19 +55,19 @@ func (v *FieldElement) One() *FieldElement {
// two because of the inliner heuristics. The two functions MUST be called one
// after the other.
func (v *FieldElement) carryPropagate1() *FieldElement {
v[1] += v[0] >> 51
v[0] &= maskLow51Bits
v[2] += v[1] >> 51
v[1] &= maskLow51Bits
v[3] += v[2] >> 51
v[2] &= maskLow51Bits
v.l1 += v.l0 >> 51
v.l0 &= maskLow51Bits
v.l2 += v.l1 >> 51
v.l1 &= maskLow51Bits
v.l3 += v.l2 >> 51
v.l2 &= maskLow51Bits
return v
}
func (v *FieldElement) carryPropagate2() *FieldElement {
v[4] += v[3] >> 51
v[3] &= maskLow51Bits
v[0] += (v[4] >> 51) * 19
v[4] &= maskLow51Bits
v.l4 += v.l3 >> 51
v.l3 &= maskLow51Bits
v.l0 += (v.l4 >> 51) * 19
v.l4 &= maskLow51Bits
return v
}
@ -78,37 +80,37 @@ func (v *FieldElement) reduce() *FieldElement {
// If v >= 2^255 - 19, then v + 19 >= 2^255, which would overflow 2^255 - 1,
// generating a carry. That is, c will be 0 if v < 2^255 - 19, and 1 otherwise.
c := (v[0] + 19) >> 51
c = (v[1] + c) >> 51
c = (v[2] + c) >> 51
c = (v[3] + c) >> 51
c = (v[4] + c) >> 51
c := (v.l0 + 19) >> 51
c = (v.l1 + c) >> 51
c = (v.l2 + c) >> 51
c = (v.l3 + c) >> 51
c = (v.l4 + c) >> 51
// If v < 2^255 - 19 and c = 0, this will be a no-op. Otherwise, it's
// effectively applying the reduction identity to the carry.
v[0] += 19 * c
v.l0 += 19 * c
v[1] += v[0] >> 51
v[0] = v[0] & maskLow51Bits
v[2] += v[1] >> 51
v[1] = v[1] & maskLow51Bits
v[3] += v[2] >> 51
v[2] = v[2] & maskLow51Bits
v[4] += v[3] >> 51
v[3] = v[3] & maskLow51Bits
v.l1 += v.l0 >> 51
v.l0 = v.l0 & maskLow51Bits
v.l2 += v.l1 >> 51
v.l1 = v.l1 & maskLow51Bits
v.l3 += v.l2 >> 51
v.l2 = v.l2 & maskLow51Bits
v.l4 += v.l3 >> 51
v.l3 = v.l3 & maskLow51Bits
// no additional carry
v[4] = v[4] & maskLow51Bits
v.l4 = v.l4 & maskLow51Bits
return v
}
// Add sets v = a + b and returns v.
func (v *FieldElement) Add(a, b *FieldElement) *FieldElement {
v[0] = a[0] + b[0]
v[1] = a[1] + b[1]
v[2] = a[2] + b[2]
v[3] = a[3] + b[3]
v[4] = a[4] + b[4]
v.l0 = a.l0 + b.l0
v.l1 = a.l1 + b.l1
v.l2 = a.l2 + b.l2
v.l3 = a.l3 + b.l3
v.l4 = a.l4 + b.l4
return v.carryPropagate1().carryPropagate2()
}
@ -116,11 +118,11 @@ func (v *FieldElement) Add(a, b *FieldElement) *FieldElement {
func (v *FieldElement) Sub(a, b *FieldElement) *FieldElement {
// We first add 2 * p, to guarantee the subtraction won't underflow, and
// then subtract b (which can be up to 2^255 + 2^13 * 19).
v[0] = (a[0] + 0xFFFFFFFFFFFDA) - b[0]
v[1] = (a[1] + 0xFFFFFFFFFFFFE) - b[1]
v[2] = (a[2] + 0xFFFFFFFFFFFFE) - b[2]
v[3] = (a[3] + 0xFFFFFFFFFFFFE) - b[3]
v[4] = (a[4] + 0xFFFFFFFFFFFFE) - b[4]
v.l0 = (a.l0 + 0xFFFFFFFFFFFDA) - b.l0
v.l1 = (a.l1 + 0xFFFFFFFFFFFFE) - b.l1
v.l2 = (a.l2 + 0xFFFFFFFFFFFFE) - b.l2
v.l3 = (a.l3 + 0xFFFFFFFFFFFFE) - b.l3
v.l4 = (a.l4 + 0xFFFFFFFFFFFFE) - b.l4
return v.carryPropagate1().carryPropagate2()
}
@ -210,17 +212,22 @@ func (v *FieldElement) FromBytes(x []byte) *FieldElement {
panic("ed25519: invalid field element input size")
}
// Provide headroom for the slight binary.LittleEndian.Uint64 overread. (We
// read 64 bits at an offset of 200, but then take only 4+51 into account.)
var buf [33]byte
copy(buf[:], x)
for i := range v {
bitsOffset := i * 51
v[i] = binary.LittleEndian.Uint64(buf[bitsOffset/8:])
v[i] >>= uint(bitsOffset % 8)
v[i] &= maskLow51Bits
}
// Bits 0:51 (bytes 0:8, bits 0:64, shift 0, mask 51).
v.l0 = binary.LittleEndian.Uint64(x[0:8])
v.l0 &= maskLow51Bits
// Bits 51:102 (bytes 6:14, bits 48:112, shift 3, mask 51).
v.l1 = binary.LittleEndian.Uint64(x[6:14]) >> 3
v.l1 &= maskLow51Bits
// Bits 102:153 (bytes 12:20, bits 96:160, shift 6, mask 51).
v.l2 = binary.LittleEndian.Uint64(x[12:20]) >> 6
v.l2 &= maskLow51Bits
// Bits 153:204 (bytes 19:27, bits 152:216, shift 1, mask 51).
v.l3 = binary.LittleEndian.Uint64(x[19:27]) >> 1
v.l3 &= maskLow51Bits
// Bits 204:251 (bytes 24:32, bits 192:256, shift 12, mask 51).
// Note: not bytes 25:33, shift 4, to avoid overread.
v.l4 = binary.LittleEndian.Uint64(x[24:32]) >> 12
v.l4 &= maskLow51Bits
return v
}
@ -236,9 +243,9 @@ func (v *FieldElement) Bytes(b []byte) []byte {
}
var buf [8]byte
for i := range t {
for i, l := range [5]uint64{t.l0, t.l1, t.l2, t.l3, t.l4} {
bitsOffset := i * 51
binary.LittleEndian.PutUint64(buf[:], t[i]<<uint(bitsOffset%8))
binary.LittleEndian.PutUint64(buf[:], l<<uint(bitsOffset%8))
for i, b := range buf {
off := bitsOffset/8 + i
if off >= len(out) {
@ -316,32 +323,32 @@ const mask64Bits uint64 = (1 << 64) - 1
// Select sets v to a if cond == 1, and to b if cond == 0.
func (v *FieldElement) Select(a, b *FieldElement, cond int) *FieldElement {
m := uint64(cond) * mask64Bits
v[0] = (m & a[0]) | (^m & b[0])
v[1] = (m & a[1]) | (^m & b[1])
v[2] = (m & a[2]) | (^m & b[2])
v[3] = (m & a[3]) | (^m & b[3])
v[4] = (m & a[4]) | (^m & b[4])
v.l0 = (m & a.l0) | (^m & b.l0)
v.l1 = (m & a.l1) | (^m & b.l1)
v.l2 = (m & a.l2) | (^m & b.l2)
v.l3 = (m & a.l3) | (^m & b.l3)
v.l4 = (m & a.l4) | (^m & b.l4)
return v
}
// CondSwap swaps a and b if cond == 1 or leaves them unchanged if cond == 0.
func CondSwap(a, b *FieldElement, cond int) {
m := uint64(cond) * mask64Bits
t := m & (a[0] ^ b[0])
a[0] ^= t
b[0] ^= t
t = m & (a[1] ^ b[1])
a[1] ^= t
b[1] ^= t
t = m & (a[2] ^ b[2])
a[2] ^= t
b[2] ^= t
t = m & (a[3] ^ b[3])
a[3] ^= t
b[3] ^= t
t = m & (a[4] ^ b[4])
a[4] ^= t
b[4] ^= t
t := m & (a.l0 ^ b.l0)
a.l0 ^= t
b.l0 ^= t
t = m & (a.l1 ^ b.l1)
a.l1 ^= t
b.l1 ^= t
t = m & (a.l2 ^ b.l2)
a.l2 ^= t
b.l2 ^= t
t = m & (a.l3 ^ b.l3)
a.l3 ^= t
b.l3 ^= t
t = m & (a.l4 ^ b.l4)
a.l4 ^= t
b.l4 ^= t
}
// CondNeg sets v to -u if cond == 1, and to u if cond == 0.
@ -376,16 +383,16 @@ func (v *FieldElement) Square(x *FieldElement) *FieldElement {
// Mul32 sets v = x * y and returns v.
func (v *FieldElement) Mul32(x *FieldElement, y uint32) *FieldElement {
x0lo, x0hi := mul51(x[0], y)
x1lo, x1hi := mul51(x[1], y)
x2lo, x2hi := mul51(x[2], y)
x3lo, x3hi := mul51(x[3], y)
x4lo, x4hi := mul51(x[4], y)
v[0] = x0lo + 19*x4hi // carried over per the reduction identity
v[1] = x1lo + x0hi
v[2] = x2lo + x1hi
v[3] = x3lo + x2hi
v[4] = x4lo + x3hi
x0lo, x0hi := mul51(x.l0, y)
x1lo, x1hi := mul51(x.l1, y)
x2lo, x2hi := mul51(x.l2, y)
x3lo, x3hi := mul51(x.l3, y)
x4lo, x4hi := mul51(x.l4, y)
v.l0 = x0lo + 19*x4hi // carried over per the reduction identity
v.l1 = x1lo + x0hi
v.l2 = x2lo + x1hi
v.l3 = x3lo + x2hi
v.l4 = x4lo + x3hi
// The hi portions are going to be only 32 bits, plus any previous excess,
// so we can skip the carry propagation.
return v

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package base
package edwards25519
import (
"testing"

View file

@ -1,10 +1,10 @@
// Copyright (c) 2017 George Tankersley. All rights reserved.
// Copyright (c) 2017 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.
// +build amd64,!purego
package base
package edwards25519
//go:noescape
func feMul(out, a, b *FieldElement)

View file

@ -1,4 +1,4 @@
// Copyright (c) 2017 George Tankersley. All rights reserved.
// Copyright (c) 2017 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.

View file

@ -2,18 +2,18 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package base_test
package edwards25519_test
import (
"testing"
"filippo.io/edwards25519/base"
"filippo.io/edwards25519"
)
func BenchmarkAdd(b *testing.B) {
var x, y base.FieldElement
var x, y edwards25519.FieldElement
x.One()
y.Add(base.One, base.One)
y.Add(edwards25519.One, edwards25519.One)
b.ResetTimer()
for i := 0; i < b.N; i++ {
x.Add(&x, &y)
@ -21,9 +21,9 @@ func BenchmarkAdd(b *testing.B) {
}
func BenchmarkMul(b *testing.B) {
var x, y base.FieldElement
var x, y edwards25519.FieldElement
x.One()
y.Add(base.One, base.One)
y.Add(edwards25519.One, edwards25519.One)
b.ResetTimer()
for i := 0; i < b.N; i++ {
x.Mul(&x, &y)
@ -31,7 +31,7 @@ func BenchmarkMul(b *testing.B) {
}
func BenchmarkMul32(b *testing.B) {
var x base.FieldElement
var x edwards25519.FieldElement
x.One()
b.ResetTimer()
for i := 0; i < b.N; i++ {

View file

@ -1,21 +1,21 @@
// Copyright (c) 2017 George Tankersley. All rights reserved.
// Copyright (c) 2017 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 base
package edwards25519
func feMulGeneric(v, x, y *FieldElement) {
x0 := x[0]
x1 := x[1]
x2 := x[2]
x3 := x[3]
x4 := x[4]
x0 := x.l0
x1 := x.l1
x2 := x.l2
x3 := x.l3
x4 := x.l4
y0 := y[0]
y1 := y[1]
y2 := y[2]
y3 := y[3]
y4 := y[4]
y0 := y.l0
y1 := y.l1
y2 := y.l2
y3 := y.l3
y4 := y.l4
// Reduction can be carried out simultaneously to multiplication. For
// example, we do not compute a coefficient r_5 . Whenever the result of a
@ -109,11 +109,11 @@ func feSquareGeneric(v, x *FieldElement) {
// this is combined with multiplication by 19 where possible. The coefficient
// reduction after squaring is the same as for multiplication.
x0 := x[0]
x1 := x[1]
x2 := x[2]
x3 := x[3]
x4 := x[4]
x0 := x.l0
x1 := x.l1
x2 := x.l2
x3 := x.l3
x4 := x.l4
x0_2 := x0 << 1
x1_2 := x1 << 1

View file

@ -1,11 +1,10 @@
// Copyright (c) 2019 George Tankersley. All rights reserved.
// Copyright (c) 2019 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.
// +build go1.13
package base
package edwards25519
import "math/bits"

View file

@ -1,11 +1,10 @@
// Copyright (c) 2017 George Tankersley. All rights reserved.
// Copyright (c) 2019 The Go Authors. All rights reserved.
// Copyright (c) 2017 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.
// +build !go1.13
package base
package edwards25519
import "unsafe"

View file

@ -4,7 +4,7 @@
// +build !amd64 purego
package base
package edwards25519
func feMul(v, x, y *FieldElement) { feMulGeneric(v, x, y) }

View file

@ -1,9 +1,8 @@
// Copyright (c) 2017 George Tankersley. All rights reserved.
// Copyright (c) 2019 The Go Authors. All rights reserved.
// Copyright (c) 2017 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 base
package edwards25519
import (
"bytes"
@ -17,9 +16,9 @@ import (
"testing/quick"
)
// quickCheckConfig will make each quickcheck test run (1024 * -quickchecks)
// quickCheckConfig10 will make each quickcheck test run (1024 * -quickchecks)
// times. The default value of -quickchecks is 100.
var quickCheckConfig = &quick.Config{MaxCountScale: 1 << 10}
var quickCheckConfig10 = &quick.Config{MaxCountScale: 1 << 10}
func generateFieldElement(rand *mathrand.Rand) FieldElement {
// Generation strategy: generate random limb values of [52, 51, 51, 51, 51]
@ -78,7 +77,7 @@ func generateWeirdFieldElement(rand *mathrand.Rand) FieldElement {
}
}
func (x FieldElement) Generate(rand *mathrand.Rand, size int) reflect.Value {
func (v FieldElement) Generate(rand *mathrand.Rand, size int) reflect.Value {
if rand.Intn(2) == 0 {
return reflect.ValueOf(generateWeirdFieldElement(rand))
}
@ -88,11 +87,11 @@ func (x FieldElement) Generate(rand *mathrand.Rand, size int) reflect.Value {
// isInBounds returns whether the element is within the expected bit size bounds
// after a light reduction.
func isInBounds(x *FieldElement) bool {
return bits.Len64(x[0]) <= 52 &&
bits.Len64(x[1]) <= 51 &&
bits.Len64(x[2]) <= 51 &&
bits.Len64(x[3]) <= 51 &&
bits.Len64(x[4]) <= 51
return bits.Len64(x.l0) <= 52 &&
bits.Len64(x.l1) <= 51 &&
bits.Len64(x.l2) <= 51 &&
bits.Len64(x.l3) <= 51 &&
bits.Len64(x.l4) <= 51
}
func TestMulDistributesOverAdd(t *testing.T) {
@ -112,7 +111,7 @@ func TestMulDistributesOverAdd(t *testing.T) {
return t1.Equal(t2) == 1 && isInBounds(t1) && isInBounds(t2)
}
if err := quick.Check(mulDistributesOverAdd, quickCheckConfig); err != nil {
if err := quick.Check(mulDistributesOverAdd, quickCheckConfig10); err != nil {
t.Error(err)
}
}
@ -198,11 +197,11 @@ func TestFromBytesRoundTrip(t *testing.T) {
}
var tests = []feRTTest{
{
fe: FieldElement([5]uint64{358744748052810, 1691584618240980, 977650209285361, 1429865912637724, 560044844278676}),
fe: FieldElement{358744748052810, 1691584618240980, 977650209285361, 1429865912637724, 560044844278676},
b: []byte{74, 209, 69, 197, 70, 70, 161, 222, 56, 226, 229, 19, 112, 60, 25, 92, 187, 74, 222, 56, 50, 153, 51, 233, 40, 74, 57, 6, 160, 185, 213, 31},
},
{
fe: FieldElement([5]uint64{84926274344903, 473620666599931, 365590438845504, 1028470286882429, 2146499180330972}),
fe: FieldElement{84926274344903, 473620666599931, 365590438845504, 1028470286882429, 2146499180330972},
b: []byte{199, 23, 106, 112, 61, 77, 216, 79, 186, 60, 11, 118, 13, 16, 103, 15, 42, 32, 83, 250, 44, 57, 204, 198, 78, 199, 253, 119, 146, 172, 3, 122},
},
}
@ -256,7 +255,7 @@ func TestSanity(t *testing.T) {
var x2, x2sq FieldElement
// var x2Go, x2sqGo FieldElement
x = [5]uint64{1, 1, 1, 1, 1}
x = FieldElement{1, 1, 1, 1, 1}
x2.Mul(&x, &x)
// FeMulGo(&x2Go, &x, &x)
x2sq.Square(&x)
@ -293,8 +292,8 @@ func TestSanity(t *testing.T) {
}
func TestEqual(t *testing.T) {
var x FieldElement = [5]uint64{1, 1, 1, 1, 1}
var y FieldElement = [5]uint64{5, 4, 3, 2, 1}
x := FieldElement{1, 1, 1, 1, 1}
y := FieldElement{5, 4, 3, 2, 1}
eq := x.Equal(&x)
if eq != 1 {
@ -308,8 +307,8 @@ func TestEqual(t *testing.T) {
}
func TestInvert(t *testing.T) {
var x FieldElement = [5]uint64{1, 1, 1, 1, 1}
var one FieldElement = [5]uint64{1, 0, 0, 0, 0}
x := FieldElement{1, 1, 1, 1, 1}
one := FieldElement{1, 0, 0, 0, 0}
var xinv, r FieldElement
xinv.Invert(&x)
@ -338,8 +337,8 @@ func TestInvert(t *testing.T) {
}
func TestSelectSwap(t *testing.T) {
a := FieldElement([5]uint64{358744748052810, 1691584618240980, 977650209285361, 1429865912637724, 560044844278676})
b := FieldElement([5]uint64{84926274344903, 473620666599931, 365590438845504, 1028470286882429, 2146499180330972})
a := FieldElement{358744748052810, 1691584618240980, 977650209285361, 1429865912637724, 560044844278676}
b := FieldElement{84926274344903, 473620666599931, 365590438845504, 1028470286882429, 2146499180330972}
var c, d FieldElement
@ -365,11 +364,11 @@ func TestSelectSwap(t *testing.T) {
func TestMul32(t *testing.T) {
isAlmostInBounds := func(x *FieldElement) bool {
return bits.Len64(x[0]) <= 52 &&
bits.Len64(x[1]) <= 52 &&
bits.Len64(x[2]) <= 52 &&
bits.Len64(x[3]) <= 52 &&
bits.Len64(x[4]) <= 52
return bits.Len64(x.l0) <= 52 &&
bits.Len64(x.l1) <= 52 &&
bits.Len64(x.l2) <= 52 &&
bits.Len64(x.l3) <= 52 &&
bits.Len64(x.l4) <= 52
}
mul32EquivalentToMul := func(x FieldElement, y uint32) bool {
@ -379,7 +378,7 @@ func TestMul32(t *testing.T) {
}
ty := new(FieldElement)
ty[0] = uint64(y)
ty.l0 = uint64(y)
t2 := new(FieldElement)
for i := 0; i < 100; i++ {
@ -389,7 +388,7 @@ func TestMul32(t *testing.T) {
return t1.Equal(t2) == 1 && isAlmostInBounds(t1) && isInBounds(t2)
}
if err := quick.Check(mul32EquivalentToMul, quickCheckConfig); err != nil {
if err := quick.Check(mul32EquivalentToMul, quickCheckConfig10); err != nil {
t.Error(err)
}
}

View file

@ -1,10 +1,8 @@
// Copyright 2016 The Go Authors. All rights reserved.
// Copyright 2019 Henry de Valence. All rights reserved.
// Copyright (c) 2016 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 scalar implements the ristretto255 scalar group.
package scalar
package edwards25519
import (
"crypto/subtle"
@ -13,8 +11,10 @@ import (
)
// A Scalar is an integer modulo
// l = 2^252 + 27742317777372353535851937790883648493,
// here represented as an opaque little-endian byte string.
//
// l = 2^252 + 27742317777372353535851937790883648493
//
// represented as a little-endian byte string.
type Scalar [32]byte
var (
@ -106,20 +106,6 @@ func (s *Scalar) Equal(t *Scalar) int {
return subtle.ConstantTimeCompare(ss[:], st[:])
}
// sliceForAppend extends the input slice by n bytes. head is the full extended
// slice, while tail is the appended part. If the original slice has sufficient
// capacity no allocation is performed.
func sliceForAppend(in []byte, n int) (head, tail []byte) {
if total := len(in) + n; cap(in) >= total {
head = in[:total]
} else {
head = make([]byte, total)
copy(head, in)
}
tail = head[len(in):]
return
}
func load3(in []byte) int64 {
r := int64(in[0])
r |= int64(in[1]) << 8

View file

@ -1,8 +1,8 @@
// Copyright 2019 Henry de Valence. All rights reserved.
// Copyright (c) 2019 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 scalar
package edwards25519
import (
"bytes"
@ -11,11 +11,7 @@ import (
"testing/quick"
)
// quickCheckConfig will make each quickcheck test run (1024 * -quickchecks)
// times. The default value of -quickchecks is 100.
var quickCheckConfig = &quick.Config{MaxCountScale: 1 << 10}
func TestFromBytesRoundTrip(t *testing.T) {
func TestScalarFromBytesRoundTrip(t *testing.T) {
f1 := func(in, out [32]byte, sc Scalar) bool {
in[len(in)-1] &= (1 << 4) - 1 // Mask out top 4 bits for 252-bit numbers
if err := sc.FromCanonicalBytes(in[:]); err != nil {
@ -43,7 +39,7 @@ func TestFromBytesRoundTrip(t *testing.T) {
}
}
func TestFromUniformBytes(t *testing.T) {
func TestScalarFromUniformBytes(t *testing.T) {
mod, _ := new(big.Int).SetString("27742317777372353535851937790883648493", 10)
mod.Add(mod, new(big.Int).Lsh(big.NewInt(1), 252))
f := func(in [64]byte, sc Scalar) bool {
@ -69,7 +65,7 @@ func byteSwap(b []byte) {
}
}
func TestMulDistributesOverAdd(t *testing.T) {
func TestScalarMulDistributesOverScalarAdd(t *testing.T) {
mulDistributesOverAdd := func(x, y, z Scalar) bool {
// Compute t1 = (x+y)*z
var t1 Scalar
@ -86,12 +82,12 @@ func TestMulDistributesOverAdd(t *testing.T) {
return t1.Equal(&t2) == 1 && scMinimal(t1[:]) && scMinimal(t2[:])
}
if err := quick.Check(mulDistributesOverAdd, quickCheckConfig); err != nil {
if err := quick.Check(mulDistributesOverAdd, quickCheckConfig10); err != nil {
t.Error(err)
}
}
func TestNonAdjacentForm(t *testing.T) {
func TestScalarNonAdjacentForm(t *testing.T) {
s := Scalar([32]byte{
0x1a, 0x0e, 0x97, 0x8a, 0x90, 0xf6, 0x62, 0x2d,
0x37, 0x47, 0x02, 0x3f, 0x8a, 0xd8, 0x26, 0x4d,
@ -118,7 +114,7 @@ func TestNonAdjacentForm(t *testing.T) {
}
}
func TestInvert(t *testing.T) {
func TestScalarInvert(t *testing.T) {
invertWorks := func(x Scalar) bool {
var xInv, check Scalar
xInv.Inv(&x)
@ -127,7 +123,7 @@ func TestInvert(t *testing.T) {
return check.Equal(&scOne) == 1
}
if err := quick.Check(invertWorks, quickCheckConfig); err != nil {
if err := quick.Check(invertWorks, quickCheckConfig10); err != nil {
t.Error(err)
}
}

View file

@ -1,15 +1,13 @@
// Copyright (c) 2019 Henry de Valence.
// Copyright (c) 2019 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 edwards25519
import "filippo.io/edwards25519/scalar"
// Set v to x*B, where B is the Ed25519 basepoint, and return v.
//
// The scalar multiplication is done in constant time.
func (v *ProjP3) BasepointMul(x *scalar.Scalar) *ProjP3 {
func (v *ProjP3) BasepointMul(x *Scalar) *ProjP3 {
// Write x = sum(x_i * 16^i) so x*B = sum( B*x_i*16^i )
// as described in the Ed25519 paper
//
@ -59,7 +57,7 @@ func (v *ProjP3) BasepointMul(x *scalar.Scalar) *ProjP3 {
// Set v to x*Q, and return v. v and q may alias.
//
// The scalar multiplication is done in constant time.
func (v *ProjP3) ScalarMul(x *scalar.Scalar, q *ProjP3) *ProjP3 {
func (v *ProjP3) ScalarMul(x *Scalar, q *ProjP3) *ProjP3 {
var table projLookupTable
table.FromP3(q)
// v and q could alias, but once the table is built we can clobber v.
@ -102,7 +100,7 @@ func (v *ProjP3) ScalarMul(x *scalar.Scalar, q *ProjP3) *ProjP3 {
// The multiscalar multiplication is sum(scalars[i]*points[i]).
//
// The multiscalar multiplication is performed in constant time.
func (v *ProjP3) MultiscalarMul(scalars []scalar.Scalar, points []*ProjP3) *ProjP3 {
func (v *ProjP3) MultiscalarMul(scalars []Scalar, points []*ProjP3) *ProjP3 {
if len(scalars) != len(points) {
panic("called MultiscalarMul with different size inputs")
}
@ -155,7 +153,7 @@ func (v *ProjP3) MultiscalarMul(scalars []scalar.Scalar, points []*ProjP3) *Proj
// Set v to a*A + b*B, where B is the Ed25519 basepoint, and return v.
//
// The scalar multiplication is done in variable time.
func (v *ProjP3) VartimeDoubleBaseMul(a *scalar.Scalar, A *ProjP3, b *scalar.Scalar) *ProjP3 {
func (v *ProjP3) VartimeDoubleBaseMul(a *Scalar, A *ProjP3, b *Scalar) *ProjP3 {
// Similarly to the single variable-base approach, we compute
// digits and use them with a lookup table. However, because
// we are allowed to do variable-time operations, we don't
@ -231,7 +229,7 @@ func (v *ProjP3) VartimeDoubleBaseMul(a *scalar.Scalar, A *ProjP3, b *scalar.Sca
// The multiscalar multiplication is sum(scalars[i]*points[i]).
//
// The multiscalar multiplication is performed in variable time.
func (v *ProjP3) VartimeMultiscalarMul(scalars []scalar.Scalar, points []*ProjP3) *ProjP3 {
func (v *ProjP3) VartimeMultiscalarMul(scalars []Scalar, points []*ProjP3) *ProjP3 {
if len(scalars) != len(points) {
panic("called MultiscalarMul with different size inputs")
}

View file

@ -1,4 +1,4 @@
// Copyright 2019 Henry de Valence. All rights reserved.
// Copyright (c) 2019 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.
@ -7,29 +7,26 @@ package edwards25519
import (
"testing"
"testing/quick"
"filippo.io/edwards25519/base"
"filippo.io/edwards25519/scalar"
)
// quickCheckConfig will make each quickcheck test run (2^6 * -quickchecks)
// times. The default value of -quickchecks is 100.
var (
quickCheckConfig = &quick.Config{MaxCountScale: 1 << 6}
// quickCheckConfig6 will make each quickcheck test run (2^6 * -quickchecks)
// times. The default value of -quickchecks is 100.
quickCheckConfig6 = &quick.Config{MaxCountScale: 1 << 6}
// a random scalar generated using dalek.
dalekScalar = scalar.Scalar([32]byte{219, 106, 114, 9, 174, 249, 155, 89, 69, 203, 201, 93, 92, 116, 234, 187, 78, 115, 103, 172, 182, 98, 62, 103, 187, 136, 13, 100, 248, 110, 12, 4})
dalekScalar = Scalar([32]byte{219, 106, 114, 9, 174, 249, 155, 89, 69, 203, 201, 93, 92, 116, 234, 187, 78, 115, 103, 172, 182, 98, 62, 103, 187, 136, 13, 100, 248, 110, 12, 4})
// the above, times the Ed25519 basepoint.
dalekScalarBasepoint = ProjP3{
X: base.FieldElement([5]uint64{778774234987948, 1589187156384239, 1213330452914652, 186161118421127, 2186284806803213}),
Y: base.FieldElement([5]uint64{1241255309069369, 1115278942994853, 1016511918109334, 1303231926552315, 1801448517689873}),
Z: base.FieldElement([5]uint64{353337085654440, 1327844406437681, 2207296012811921, 707394926933424, 917408459573183}),
T: base.FieldElement([5]uint64{585487439439725, 1792815221887900, 946062846079052, 1954901232609667, 1418300670001780}),
X: FieldElement{778774234987948, 1589187156384239, 1213330452914652, 186161118421127, 2186284806803213},
Y: FieldElement{1241255309069369, 1115278942994853, 1016511918109334, 1303231926552315, 1801448517689873},
Z: FieldElement{353337085654440, 1327844406437681, 2207296012811921, 707394926933424, 917408459573183},
T: FieldElement{585487439439725, 1792815221887900, 946062846079052, 1954901232609667, 1418300670001780},
}
)
func TestScalarMulSmallScalars(t *testing.T) {
var z scalar.Scalar
var z Scalar
var p, check ProjP3
p.ScalarMul(&z, &B)
check.Zero()
@ -37,7 +34,7 @@ func TestScalarMulSmallScalars(t *testing.T) {
t.Error("0*B != 0")
}
z = scalar.Scalar([32]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
z = Scalar([32]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
p.ScalarMul(&z, &B)
check.Set(&B)
if check.Equal(&p) != 1 {
@ -63,7 +60,7 @@ func TestBasepointMulVsDalek(t *testing.T) {
func TestVartimeDoubleBaseMulVsDalek(t *testing.T) {
var p ProjP3
var z scalar.Scalar
var z Scalar
p.VartimeDoubleBaseMul(&dalekScalar, &B, &z)
if dalekScalarBasepoint.Equal(&p) != 1 {
t.Error("VartimeDoubleBaseMul fails with b=0")
@ -75,14 +72,14 @@ func TestVartimeDoubleBaseMulVsDalek(t *testing.T) {
}
func TestScalarMulDistributesOverAdd(t *testing.T) {
scalarMulDistributesOverAdd := func(x, y scalar.Scalar) bool {
scalarMulDistributesOverAdd := func(x, y Scalar) bool {
// The quickcheck generation strategy chooses a random
// 32-byte array, but we require that the high bit is
// unset. FIXME: make Scalar opaque. Until then,
// mask the high bits:
x[31] &= 127
y[31] &= 127
var z scalar.Scalar
var z Scalar
z.Add(&x, &y)
var p, q, r, check ProjP3
p.ScalarMul(&x, &B)
@ -92,7 +89,7 @@ func TestScalarMulDistributesOverAdd(t *testing.T) {
return check.Equal(&r) == 1
}
if err := quick.Check(scalarMulDistributesOverAdd, quickCheckConfig); err != nil {
if err := quick.Check(scalarMulDistributesOverAdd, quickCheckConfig6); err != nil {
t.Error(err)
}
}
@ -126,7 +123,7 @@ func TestBasepointTableGeneration(t *testing.T) {
}
func TestScalarMulMatchesBasepointMul(t *testing.T) {
scalarMulMatchesBasepointMul := func(x scalar.Scalar) bool {
scalarMulMatchesBasepointMul := func(x Scalar) bool {
// FIXME opaque scalars
x[31] &= 127
var p, q ProjP3
@ -135,20 +132,20 @@ func TestScalarMulMatchesBasepointMul(t *testing.T) {
return p.Equal(&q) == 1
}
if err := quick.Check(scalarMulMatchesBasepointMul, quickCheckConfig); err != nil {
if err := quick.Check(scalarMulMatchesBasepointMul, quickCheckConfig6); err != nil {
t.Error(err)
}
}
func TestMultiScalarMulMatchesBasepointMul(t *testing.T) {
multiScalarMulMatchesBasepointMul := func(x, y, z scalar.Scalar) bool {
multiScalarMulMatchesBasepointMul := func(x, y, z Scalar) bool {
// FIXME opaque scalars
x[31] &= 127
y[31] &= 127
z[31] &= 127
var p, q1, q2, q3, check ProjP3
p.MultiscalarMul([]scalar.Scalar{x, y, z}, []*ProjP3{&B, &B, &B})
p.MultiscalarMul([]Scalar{x, y, z}, []*ProjP3{&B, &B, &B})
q1.BasepointMul(&x)
q2.BasepointMul(&y)
@ -159,7 +156,7 @@ func TestMultiScalarMulMatchesBasepointMul(t *testing.T) {
return p.Equal(&check) == 1
}
if err := quick.Check(multiScalarMulMatchesBasepointMul, quickCheckConfig); err != nil {
if err := quick.Check(multiScalarMulMatchesBasepointMul, quickCheckConfig6); err != nil {
t.Error(err)
}
}
@ -174,7 +171,7 @@ func TestBasepointNafTableGeneration(t *testing.T) {
}
func TestVartimeDoubleBaseMulMatchesBasepointMul(t *testing.T) {
vartimeDoubleBaseMulMatchesBasepointMul := func(x, y scalar.Scalar) bool {
vartimeDoubleBaseMulMatchesBasepointMul := func(x, y Scalar) bool {
// FIXME opaque scalars
x[31] &= 127
y[31] &= 127
@ -190,20 +187,20 @@ func TestVartimeDoubleBaseMulMatchesBasepointMul(t *testing.T) {
return p.Equal(&check) == 1
}
if err := quick.Check(vartimeDoubleBaseMulMatchesBasepointMul, quickCheckConfig); err != nil {
if err := quick.Check(vartimeDoubleBaseMulMatchesBasepointMul, quickCheckConfig6); err != nil {
t.Error(err)
}
}
func TestVartimeMultiScalarMulMatchesBasepointMul(t *testing.T) {
vartimeMultiScalarMulMatchesBasepointMul := func(x, y, z scalar.Scalar) bool {
vartimeMultiScalarMulMatchesBasepointMul := func(x, y, z Scalar) bool {
// FIXME opaque scalars
x[31] &= 127
y[31] &= 127
z[31] &= 127
var p, q1, q2, q3, check ProjP3
p.VartimeMultiscalarMul([]scalar.Scalar{x, y, z}, []*ProjP3{&B, &B, &B})
p.VartimeMultiscalarMul([]Scalar{x, y, z}, []*ProjP3{&B, &B, &B})
q1.BasepointMul(&x)
q2.BasepointMul(&y)
@ -214,7 +211,7 @@ func TestVartimeMultiScalarMulMatchesBasepointMul(t *testing.T) {
return p.Equal(&check) == 1
}
if err := quick.Check(vartimeMultiScalarMulMatchesBasepointMul, quickCheckConfig); err != nil {
if err := quick.Check(vartimeMultiScalarMulMatchesBasepointMul, quickCheckConfig6); err != nil {
t.Error(err)
}
}
@ -250,7 +247,7 @@ func BenchmarkMultiscalarMulSize8(t *testing.B) {
x := dalekScalar
for i := 0; i < t.N; i++ {
p.MultiscalarMul([]scalar.Scalar{x, x, x, x, x, x, x, x}, []*ProjP3{&B, &B, &B, &B, &B, &B, &B, &B})
p.MultiscalarMul([]Scalar{x, x, x, x, x, x, x, x}, []*ProjP3{&B, &B, &B, &B, &B, &B, &B, &B})
}
}

File diff suppressed because one or more lines are too long

View file

@ -1,4 +1,4 @@
// Copyright (c) 2019 Henry de Valence.
// Copyright (c) 2019 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.

View file

@ -1,4 +1,4 @@
// Copyright 2019 Henry de Valence. All rights reserved.
// Copyright (c) 2019 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.