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) 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 Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are 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) 2017 The Go Authors. All rights reserved.
// Copyright (c) 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -7,16 +6,23 @@
// //
// -x^2 + y^2 = 1 + -(121665/121666)*x^2*y^2 // -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. // 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 package edwards25519
import "filippo.io/edwards25519/base"
// D is a constant in the curve equation. // D is a constant in the curve equation.
var D = &base.FieldElement{929955233495203, 466365720129213, var D = &FieldElement{929955233495203, 466365720129213,
1662059464998953, 2033849074728123, 1442794654840575} 1662059464998953, 2033849074728123, 1442794654840575}
var d2 = new(base.FieldElement).Add(D, D) var d2 = new(FieldElement).Add(D, D)
// Point types. // 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 // https://doc-internal.dalek.rs/curve25519_dalek/backend/serial/curve_models/index.html
type ProjP1xP1 struct { type ProjP1xP1 struct {
X, Y, Z, T base.FieldElement X, Y, Z, T FieldElement
} }
type ProjP2 struct { type ProjP2 struct {
X, Y, Z base.FieldElement X, Y, Z FieldElement
} }
type ProjP3 struct { type ProjP3 struct {
X, Y, Z, T base.FieldElement X, Y, Z, T FieldElement
} }
type ProjCached struct { type ProjCached struct {
YplusX, YminusX, Z, T2d base.FieldElement YplusX, YminusX, Z, T2d FieldElement
} }
type AffineCached struct { type AffineCached struct {
YplusX, YminusX, T2d base.FieldElement YplusX, YminusX, T2d FieldElement
} }
// B is the Ed25519 basepoint. // B is the Ed25519 basepoint.
var B = ProjP3{ var B = ProjP3{
X: base.FieldElement([5]uint64{1738742601995546, 1146398526822698, 2070867633025821, 562264141797630, 587772402128613}), X: FieldElement{1738742601995546, 1146398526822698, 2070867633025821, 562264141797630, 587772402128613},
Y: base.FieldElement([5]uint64{1801439850948184, 1351079888211148, 450359962737049, 900719925474099, 1801439850948198}), Y: FieldElement{1801439850948184, 1351079888211148, 450359962737049, 900719925474099, 1801439850948198},
Z: base.FieldElement([5]uint64{1, 0, 0, 0, 0}), Z: FieldElement{1, 0, 0, 0, 0},
T: base.FieldElement([5]uint64{1841354044333475, 16398895984059, 755974180946558, 900171276175154, 1821297809914039}), T: FieldElement{1841354044333475, 16398895984059, 755974180946558, 900171276175154, 1821297809914039},
} }
// Constructors. // Constructors.
@ -144,7 +150,7 @@ func (v *AffineCached) FromP3(p *ProjP3) *AffineCached {
v.YminusX.Sub(&p.Y, &p.X) v.YminusX.Sub(&p.Y, &p.X)
v.T2d.Mul(&p.T, d2) v.T2d.Mul(&p.T, d2)
var invZ base.FieldElement var invZ FieldElement
invZ.Invert(&p.Z) invZ.Invert(&p.Z)
v.YplusX.Mul(&v.YplusX, &invZ) v.YplusX.Mul(&v.YplusX, &invZ)
v.YminusX.Mul(&v.YminusX, &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 { 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) YplusX.Add(&p.Y, &p.X)
YminusX.Sub(&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 { 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) YplusX.Add(&p.Y, &p.X)
YminusX.Sub(&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 { 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) YplusX.Add(&p.Y, &p.X)
YminusX.Sub(&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 { 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) YplusX.Add(&p.Y, &p.X)
YminusX.Sub(&p.Y, &p.X) YminusX.Sub(&p.Y, &p.X)
@ -253,7 +259,7 @@ func (v *ProjP1xP1) SubAffine(p *ProjP3, q *AffineCached) *ProjP1xP1 {
// Doubling. // Doubling.
func (v *ProjP1xP1) Double(p *ProjP2) *ProjP1xP1 { func (v *ProjP1xP1) Double(p *ProjP2) *ProjP1xP1 {
var XX, YY, ZZ2, XplusYsq base.FieldElement var XX, YY, ZZ2, XplusYsq FieldElement
XX.Square(&p.X) XX.Square(&p.X)
YY.Square(&p.Y) YY.Square(&p.Y)
@ -283,7 +289,7 @@ func (v *ProjP3) Neg(p *ProjP3) *ProjP3 {
// by @ebfull // by @ebfull
// https://github.com/dalek-cryptography/curve25519-dalek/pull/226/files // https://github.com/dalek-cryptography/curve25519-dalek/pull/226/files
func (v *ProjP3) Equal(u *ProjP3) int { 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) t1.Mul(&v.X, &u.Z)
t2.Mul(&u.X, &v.Z) t2.Mul(&u.X, &v.Z)
t3.Mul(&v.Y, &u.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. // CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0.
func (v *ProjCached) CondNeg(cond int) *ProjCached { 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) v.T2d.CondNeg(&v.T2d, cond)
return v return v
} }
// CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0. // CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0.
func (v *AffineCached) CondNeg(cond int) *AffineCached { 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) v.T2d.CondNeg(&v.T2d, cond)
return v 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 // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // 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) 2017 The Go Authors. All rights reserved.
// Copyright (c) 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Package base implements GF(2^255-19) field arithmetic in radix 2^51 package edwards25519
// 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
import ( import (
"crypto/subtle" "crypto/subtle"
@ -18,15 +11,24 @@ import (
"math/bits" "math/bits"
) )
// FieldElement represents an element of the field GF(2^255-19). An element t // FieldElement represents an element of the field GF(2^255-19).
// represents the integer t[0] + t[1]*2^51 + t[2]*2^102 + t[3]*2^153 +
// t[4]*2^204.
// //
// Between operations, all limbs are expected to be lower than 2^51, except the // This type works similarly to math/big.Int, and all arguments and
// first one, which can be up to 2^255 + 2^13 * 19 due to carry propagation. // receivers are allowed to alias.
// //
// The zero value is a valid zero element. // 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 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 // two because of the inliner heuristics. The two functions MUST be called one
// after the other. // after the other.
func (v *FieldElement) carryPropagate1() *FieldElement { func (v *FieldElement) carryPropagate1() *FieldElement {
v[1] += v[0] >> 51 v.l1 += v.l0 >> 51
v[0] &= maskLow51Bits v.l0 &= maskLow51Bits
v[2] += v[1] >> 51 v.l2 += v.l1 >> 51
v[1] &= maskLow51Bits v.l1 &= maskLow51Bits
v[3] += v[2] >> 51 v.l3 += v.l2 >> 51
v[2] &= maskLow51Bits v.l2 &= maskLow51Bits
return v return v
} }
func (v *FieldElement) carryPropagate2() *FieldElement { func (v *FieldElement) carryPropagate2() *FieldElement {
v[4] += v[3] >> 51 v.l4 += v.l3 >> 51
v[3] &= maskLow51Bits v.l3 &= maskLow51Bits
v[0] += (v[4] >> 51) * 19 v.l0 += (v.l4 >> 51) * 19
v[4] &= maskLow51Bits v.l4 &= maskLow51Bits
return v 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, // 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. // generating a carry. That is, c will be 0 if v < 2^255 - 19, and 1 otherwise.
c := (v[0] + 19) >> 51 c := (v.l0 + 19) >> 51
c = (v[1] + c) >> 51 c = (v.l1 + c) >> 51
c = (v[2] + c) >> 51 c = (v.l2 + c) >> 51
c = (v[3] + c) >> 51 c = (v.l3 + c) >> 51
c = (v[4] + c) >> 51 c = (v.l4 + c) >> 51
// If v < 2^255 - 19 and c = 0, this will be a no-op. Otherwise, it's // 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. // effectively applying the reduction identity to the carry.
v[0] += 19 * c v.l0 += 19 * c
v[1] += v[0] >> 51 v.l1 += v.l0 >> 51
v[0] = v[0] & maskLow51Bits v.l0 = v.l0 & maskLow51Bits
v[2] += v[1] >> 51 v.l2 += v.l1 >> 51
v[1] = v[1] & maskLow51Bits v.l1 = v.l1 & maskLow51Bits
v[3] += v[2] >> 51 v.l3 += v.l2 >> 51
v[2] = v[2] & maskLow51Bits v.l2 = v.l2 & maskLow51Bits
v[4] += v[3] >> 51 v.l4 += v.l3 >> 51
v[3] = v[3] & maskLow51Bits v.l3 = v.l3 & maskLow51Bits
// no additional carry // no additional carry
v[4] = v[4] & maskLow51Bits v.l4 = v.l4 & maskLow51Bits
return v return v
} }
// Add sets v = a + b and returns v. // Add sets v = a + b and returns v.
func (v *FieldElement) Add(a, b *FieldElement) *FieldElement { func (v *FieldElement) Add(a, b *FieldElement) *FieldElement {
v[0] = a[0] + b[0] v.l0 = a.l0 + b.l0
v[1] = a[1] + b[1] v.l1 = a.l1 + b.l1
v[2] = a[2] + b[2] v.l2 = a.l2 + b.l2
v[3] = a[3] + b[3] v.l3 = a.l3 + b.l3
v[4] = a[4] + b[4] v.l4 = a.l4 + b.l4
return v.carryPropagate1().carryPropagate2() return v.carryPropagate1().carryPropagate2()
} }
@ -116,11 +118,11 @@ func (v *FieldElement) Add(a, b *FieldElement) *FieldElement {
func (v *FieldElement) Sub(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 // 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). // then subtract b (which can be up to 2^255 + 2^13 * 19).
v[0] = (a[0] + 0xFFFFFFFFFFFDA) - b[0] v.l0 = (a.l0 + 0xFFFFFFFFFFFDA) - b.l0
v[1] = (a[1] + 0xFFFFFFFFFFFFE) - b[1] v.l1 = (a.l1 + 0xFFFFFFFFFFFFE) - b.l1
v[2] = (a[2] + 0xFFFFFFFFFFFFE) - b[2] v.l2 = (a.l2 + 0xFFFFFFFFFFFFE) - b.l2
v[3] = (a[3] + 0xFFFFFFFFFFFFE) - b[3] v.l3 = (a.l3 + 0xFFFFFFFFFFFFE) - b.l3
v[4] = (a[4] + 0xFFFFFFFFFFFFE) - b[4] v.l4 = (a.l4 + 0xFFFFFFFFFFFFE) - b.l4
return v.carryPropagate1().carryPropagate2() return v.carryPropagate1().carryPropagate2()
} }
@ -210,17 +212,22 @@ func (v *FieldElement) FromBytes(x []byte) *FieldElement {
panic("ed25519: invalid field element input size") panic("ed25519: invalid field element input size")
} }
// Provide headroom for the slight binary.LittleEndian.Uint64 overread. (We // Bits 0:51 (bytes 0:8, bits 0:64, shift 0, mask 51).
// read 64 bits at an offset of 200, but then take only 4+51 into account.) v.l0 = binary.LittleEndian.Uint64(x[0:8])
var buf [33]byte v.l0 &= maskLow51Bits
copy(buf[:], x) // Bits 51:102 (bytes 6:14, bits 48:112, shift 3, mask 51).
v.l1 = binary.LittleEndian.Uint64(x[6:14]) >> 3
for i := range v { v.l1 &= maskLow51Bits
bitsOffset := i * 51 // Bits 102:153 (bytes 12:20, bits 96:160, shift 6, mask 51).
v[i] = binary.LittleEndian.Uint64(buf[bitsOffset/8:]) v.l2 = binary.LittleEndian.Uint64(x[12:20]) >> 6
v[i] >>= uint(bitsOffset % 8) v.l2 &= maskLow51Bits
v[i] &= 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 return v
} }
@ -236,9 +243,9 @@ func (v *FieldElement) Bytes(b []byte) []byte {
} }
var buf [8]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 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 { for i, b := range buf {
off := bitsOffset/8 + i off := bitsOffset/8 + i
if off >= len(out) { 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. // Select sets v to a if cond == 1, and to b if cond == 0.
func (v *FieldElement) Select(a, b *FieldElement, cond int) *FieldElement { func (v *FieldElement) Select(a, b *FieldElement, cond int) *FieldElement {
m := uint64(cond) * mask64Bits m := uint64(cond) * mask64Bits
v[0] = (m & a[0]) | (^m & b[0]) v.l0 = (m & a.l0) | (^m & b.l0)
v[1] = (m & a[1]) | (^m & b[1]) v.l1 = (m & a.l1) | (^m & b.l1)
v[2] = (m & a[2]) | (^m & b[2]) v.l2 = (m & a.l2) | (^m & b.l2)
v[3] = (m & a[3]) | (^m & b[3]) v.l3 = (m & a.l3) | (^m & b.l3)
v[4] = (m & a[4]) | (^m & b[4]) v.l4 = (m & a.l4) | (^m & b.l4)
return v return v
} }
// CondSwap swaps a and b if cond == 1 or leaves them unchanged if cond == 0. // CondSwap swaps a and b if cond == 1 or leaves them unchanged if cond == 0.
func CondSwap(a, b *FieldElement, cond int) { func CondSwap(a, b *FieldElement, cond int) {
m := uint64(cond) * mask64Bits m := uint64(cond) * mask64Bits
t := m & (a[0] ^ b[0]) t := m & (a.l0 ^ b.l0)
a[0] ^= t a.l0 ^= t
b[0] ^= t b.l0 ^= t
t = m & (a[1] ^ b[1]) t = m & (a.l1 ^ b.l1)
a[1] ^= t a.l1 ^= t
b[1] ^= t b.l1 ^= t
t = m & (a[2] ^ b[2]) t = m & (a.l2 ^ b.l2)
a[2] ^= t a.l2 ^= t
b[2] ^= t b.l2 ^= t
t = m & (a[3] ^ b[3]) t = m & (a.l3 ^ b.l3)
a[3] ^= t a.l3 ^= t
b[3] ^= t b.l3 ^= t
t = m & (a[4] ^ b[4]) t = m & (a.l4 ^ b.l4)
a[4] ^= t a.l4 ^= t
b[4] ^= t b.l4 ^= t
} }
// CondNeg sets v to -u if cond == 1, and to u if cond == 0. // 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. // Mul32 sets v = x * y and returns v.
func (v *FieldElement) Mul32(x *FieldElement, y uint32) *FieldElement { func (v *FieldElement) Mul32(x *FieldElement, y uint32) *FieldElement {
x0lo, x0hi := mul51(x[0], y) x0lo, x0hi := mul51(x.l0, y)
x1lo, x1hi := mul51(x[1], y) x1lo, x1hi := mul51(x.l1, y)
x2lo, x2hi := mul51(x[2], y) x2lo, x2hi := mul51(x.l2, y)
x3lo, x3hi := mul51(x[3], y) x3lo, x3hi := mul51(x.l3, y)
x4lo, x4hi := mul51(x[4], y) x4lo, x4hi := mul51(x.l4, y)
v[0] = x0lo + 19*x4hi // carried over per the reduction identity v.l0 = x0lo + 19*x4hi // carried over per the reduction identity
v[1] = x1lo + x0hi v.l1 = x1lo + x0hi
v[2] = x2lo + x1hi v.l2 = x2lo + x1hi
v[3] = x3lo + x2hi v.l3 = x3lo + x2hi
v[4] = x4lo + x3hi v.l4 = x4lo + x3hi
// The hi portions are going to be only 32 bits, plus any previous excess, // The hi portions are going to be only 32 bits, plus any previous excess,
// so we can skip the carry propagation. // so we can skip the carry propagation.
return v return v

View file

@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package base package edwards25519
import ( import (
"testing" "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 // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build amd64,!purego // +build amd64,!purego
package base package edwards25519
//go:noescape //go:noescape
func feMul(out, a, b *FieldElement) 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 // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // 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 // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package base_test package edwards25519_test
import ( import (
"testing" "testing"
"filippo.io/edwards25519/base" "filippo.io/edwards25519"
) )
func BenchmarkAdd(b *testing.B) { func BenchmarkAdd(b *testing.B) {
var x, y base.FieldElement var x, y edwards25519.FieldElement
x.One() x.One()
y.Add(base.One, base.One) y.Add(edwards25519.One, edwards25519.One)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
x.Add(&x, &y) x.Add(&x, &y)
@ -21,9 +21,9 @@ func BenchmarkAdd(b *testing.B) {
} }
func BenchmarkMul(b *testing.B) { func BenchmarkMul(b *testing.B) {
var x, y base.FieldElement var x, y edwards25519.FieldElement
x.One() x.One()
y.Add(base.One, base.One) y.Add(edwards25519.One, edwards25519.One)
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { for i := 0; i < b.N; i++ {
x.Mul(&x, &y) x.Mul(&x, &y)
@ -31,7 +31,7 @@ func BenchmarkMul(b *testing.B) {
} }
func BenchmarkMul32(b *testing.B) { func BenchmarkMul32(b *testing.B) {
var x base.FieldElement var x edwards25519.FieldElement
x.One() x.One()
b.ResetTimer() b.ResetTimer()
for i := 0; i < b.N; i++ { 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 // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package base package edwards25519
func feMulGeneric(v, x, y *FieldElement) { func feMulGeneric(v, x, y *FieldElement) {
x0 := x[0] x0 := x.l0
x1 := x[1] x1 := x.l1
x2 := x[2] x2 := x.l2
x3 := x[3] x3 := x.l3
x4 := x[4] x4 := x.l4
y0 := y[0] y0 := y.l0
y1 := y[1] y1 := y.l1
y2 := y[2] y2 := y.l2
y3 := y[3] y3 := y.l3
y4 := y[4] y4 := y.l4
// Reduction can be carried out simultaneously to multiplication. For // Reduction can be carried out simultaneously to multiplication. For
// example, we do not compute a coefficient r_5 . Whenever the result of a // 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 // this is combined with multiplication by 19 where possible. The coefficient
// reduction after squaring is the same as for multiplication. // reduction after squaring is the same as for multiplication.
x0 := x[0] x0 := x.l0
x1 := x[1] x1 := x.l1
x2 := x[2] x2 := x.l2
x3 := x[3] x3 := x.l3
x4 := x[4] x4 := x.l4
x0_2 := x0 << 1 x0_2 := x0 << 1
x1_2 := x1 << 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. // Copyright (c) 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build go1.13 // +build go1.13
package base package edwards25519
import "math/bits" import "math/bits"

View file

@ -1,11 +1,10 @@
// Copyright (c) 2017 George Tankersley. All rights reserved. // Copyright (c) 2017 The Go Authors. All rights reserved.
// Copyright (c) 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build !go1.13 // +build !go1.13
package base package edwards25519
import "unsafe" import "unsafe"

View file

@ -4,7 +4,7 @@
// +build !amd64 purego // +build !amd64 purego
package base package edwards25519
func feMul(v, x, y *FieldElement) { feMulGeneric(v, x, y) } 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) 2017 The Go Authors. All rights reserved.
// Copyright (c) 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package base package edwards25519
import ( import (
"bytes" "bytes"
@ -17,9 +16,9 @@ import (
"testing/quick" "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. // 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 { func generateFieldElement(rand *mathrand.Rand) FieldElement {
// Generation strategy: generate random limb values of [52, 51, 51, 51, 51] // 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 { if rand.Intn(2) == 0 {
return reflect.ValueOf(generateWeirdFieldElement(rand)) 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 // isInBounds returns whether the element is within the expected bit size bounds
// after a light reduction. // after a light reduction.
func isInBounds(x *FieldElement) bool { func isInBounds(x *FieldElement) bool {
return bits.Len64(x[0]) <= 52 && return bits.Len64(x.l0) <= 52 &&
bits.Len64(x[1]) <= 51 && bits.Len64(x.l1) <= 51 &&
bits.Len64(x[2]) <= 51 && bits.Len64(x.l2) <= 51 &&
bits.Len64(x[3]) <= 51 && bits.Len64(x.l3) <= 51 &&
bits.Len64(x[4]) <= 51 bits.Len64(x.l4) <= 51
} }
func TestMulDistributesOverAdd(t *testing.T) { func TestMulDistributesOverAdd(t *testing.T) {
@ -112,7 +111,7 @@ func TestMulDistributesOverAdd(t *testing.T) {
return t1.Equal(t2) == 1 && isInBounds(t1) && isInBounds(t2) 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) t.Error(err)
} }
} }
@ -198,11 +197,11 @@ func TestFromBytesRoundTrip(t *testing.T) {
} }
var tests = []feRTTest{ 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}, 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}, 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 x2, x2sq FieldElement
// var x2Go, x2sqGo FieldElement // var x2Go, x2sqGo FieldElement
x = [5]uint64{1, 1, 1, 1, 1} x = FieldElement{1, 1, 1, 1, 1}
x2.Mul(&x, &x) x2.Mul(&x, &x)
// FeMulGo(&x2Go, &x, &x) // FeMulGo(&x2Go, &x, &x)
x2sq.Square(&x) x2sq.Square(&x)
@ -293,8 +292,8 @@ func TestSanity(t *testing.T) {
} }
func TestEqual(t *testing.T) { func TestEqual(t *testing.T) {
var x FieldElement = [5]uint64{1, 1, 1, 1, 1} x := FieldElement{1, 1, 1, 1, 1}
var y FieldElement = [5]uint64{5, 4, 3, 2, 1} y := FieldElement{5, 4, 3, 2, 1}
eq := x.Equal(&x) eq := x.Equal(&x)
if eq != 1 { if eq != 1 {
@ -308,8 +307,8 @@ func TestEqual(t *testing.T) {
} }
func TestInvert(t *testing.T) { func TestInvert(t *testing.T) {
var x FieldElement = [5]uint64{1, 1, 1, 1, 1} x := FieldElement{1, 1, 1, 1, 1}
var one FieldElement = [5]uint64{1, 0, 0, 0, 0} one := FieldElement{1, 0, 0, 0, 0}
var xinv, r FieldElement var xinv, r FieldElement
xinv.Invert(&x) xinv.Invert(&x)
@ -338,8 +337,8 @@ func TestInvert(t *testing.T) {
} }
func TestSelectSwap(t *testing.T) { func TestSelectSwap(t *testing.T) {
a := FieldElement([5]uint64{358744748052810, 1691584618240980, 977650209285361, 1429865912637724, 560044844278676}) a := FieldElement{358744748052810, 1691584618240980, 977650209285361, 1429865912637724, 560044844278676}
b := FieldElement([5]uint64{84926274344903, 473620666599931, 365590438845504, 1028470286882429, 2146499180330972}) b := FieldElement{84926274344903, 473620666599931, 365590438845504, 1028470286882429, 2146499180330972}
var c, d FieldElement var c, d FieldElement
@ -365,11 +364,11 @@ func TestSelectSwap(t *testing.T) {
func TestMul32(t *testing.T) { func TestMul32(t *testing.T) {
isAlmostInBounds := func(x *FieldElement) bool { isAlmostInBounds := func(x *FieldElement) bool {
return bits.Len64(x[0]) <= 52 && return bits.Len64(x.l0) <= 52 &&
bits.Len64(x[1]) <= 52 && bits.Len64(x.l1) <= 52 &&
bits.Len64(x[2]) <= 52 && bits.Len64(x.l2) <= 52 &&
bits.Len64(x[3]) <= 52 && bits.Len64(x.l3) <= 52 &&
bits.Len64(x[4]) <= 52 bits.Len64(x.l4) <= 52
} }
mul32EquivalentToMul := func(x FieldElement, y uint32) bool { mul32EquivalentToMul := func(x FieldElement, y uint32) bool {
@ -379,7 +378,7 @@ func TestMul32(t *testing.T) {
} }
ty := new(FieldElement) ty := new(FieldElement)
ty[0] = uint64(y) ty.l0 = uint64(y)
t2 := new(FieldElement) t2 := new(FieldElement)
for i := 0; i < 100; i++ { for i := 0; i < 100; i++ {
@ -389,7 +388,7 @@ func TestMul32(t *testing.T) {
return t1.Equal(t2) == 1 && isAlmostInBounds(t1) && isInBounds(t2) 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) t.Error(err)
} }
} }

View file

@ -1,10 +1,8 @@
// Copyright 2016 The Go Authors. All rights reserved. // Copyright (c) 2016 The Go Authors. All rights reserved.
// Copyright 2019 Henry de Valence. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Package scalar implements the ristretto255 scalar group. package edwards25519
package scalar
import ( import (
"crypto/subtle" "crypto/subtle"
@ -13,8 +11,10 @@ import (
) )
// A Scalar is an integer modulo // 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 type Scalar [32]byte
var ( var (
@ -106,20 +106,6 @@ func (s *Scalar) Equal(t *Scalar) int {
return subtle.ConstantTimeCompare(ss[:], st[:]) 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 { func load3(in []byte) int64 {
r := int64(in[0]) r := int64(in[0])
r |= int64(in[1]) << 8 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 // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package scalar package edwards25519
import ( import (
"bytes" "bytes"
@ -11,11 +11,7 @@ import (
"testing/quick" "testing/quick"
) )
// quickCheckConfig will make each quickcheck test run (1024 * -quickchecks) func TestScalarFromBytesRoundTrip(t *testing.T) {
// times. The default value of -quickchecks is 100.
var quickCheckConfig = &quick.Config{MaxCountScale: 1 << 10}
func TestFromBytesRoundTrip(t *testing.T) {
f1 := func(in, out [32]byte, sc Scalar) bool { 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 in[len(in)-1] &= (1 << 4) - 1 // Mask out top 4 bits for 252-bit numbers
if err := sc.FromCanonicalBytes(in[:]); err != nil { 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, _ := new(big.Int).SetString("27742317777372353535851937790883648493", 10)
mod.Add(mod, new(big.Int).Lsh(big.NewInt(1), 252)) mod.Add(mod, new(big.Int).Lsh(big.NewInt(1), 252))
f := func(in [64]byte, sc Scalar) bool { 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 { mulDistributesOverAdd := func(x, y, z Scalar) bool {
// Compute t1 = (x+y)*z // Compute t1 = (x+y)*z
var t1 Scalar var t1 Scalar
@ -86,12 +82,12 @@ func TestMulDistributesOverAdd(t *testing.T) {
return t1.Equal(&t2) == 1 && scMinimal(t1[:]) && scMinimal(t2[:]) 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) t.Error(err)
} }
} }
func TestNonAdjacentForm(t *testing.T) { func TestScalarNonAdjacentForm(t *testing.T) {
s := Scalar([32]byte{ s := Scalar([32]byte{
0x1a, 0x0e, 0x97, 0x8a, 0x90, 0xf6, 0x62, 0x2d, 0x1a, 0x0e, 0x97, 0x8a, 0x90, 0xf6, 0x62, 0x2d,
0x37, 0x47, 0x02, 0x3f, 0x8a, 0xd8, 0x26, 0x4d, 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 { invertWorks := func(x Scalar) bool {
var xInv, check Scalar var xInv, check Scalar
xInv.Inv(&x) xInv.Inv(&x)
@ -127,7 +123,7 @@ func TestInvert(t *testing.T) {
return check.Equal(&scOne) == 1 return check.Equal(&scOne) == 1
} }
if err := quick.Check(invertWorks, quickCheckConfig); err != nil { if err := quick.Check(invertWorks, quickCheckConfig10); err != nil {
t.Error(err) 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 // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
package edwards25519 package edwards25519
import "filippo.io/edwards25519/scalar"
// Set v to x*B, where B is the Ed25519 basepoint, and return v. // Set v to x*B, where B is the Ed25519 basepoint, and return v.
// //
// The scalar multiplication is done in constant time. // 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 ) // Write x = sum(x_i * 16^i) so x*B = sum( B*x_i*16^i )
// as described in the Ed25519 paper // 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. // Set v to x*Q, and return v. v and q may alias.
// //
// The scalar multiplication is done in constant time. // 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 var table projLookupTable
table.FromP3(q) table.FromP3(q)
// v and q could alias, but once the table is built we can clobber v. // 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 sum(scalars[i]*points[i]).
// //
// The multiscalar multiplication is performed in constant time. // 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) { if len(scalars) != len(points) {
panic("called MultiscalarMul with different size inputs") 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. // Set v to a*A + b*B, where B is the Ed25519 basepoint, and return v.
// //
// The scalar multiplication is done in variable time. // 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 // Similarly to the single variable-base approach, we compute
// digits and use them with a lookup table. However, because // digits and use them with a lookup table. However, because
// we are allowed to do variable-time operations, we don't // 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 sum(scalars[i]*points[i]).
// //
// The multiscalar multiplication is performed in variable time. // 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) { if len(scalars) != len(points) {
panic("called MultiscalarMul with different size inputs") 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 // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
@ -7,29 +7,26 @@ package edwards25519
import ( import (
"testing" "testing"
"testing/quick" "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 ( 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. // 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. // the above, times the Ed25519 basepoint.
dalekScalarBasepoint = ProjP3{ dalekScalarBasepoint = ProjP3{
X: base.FieldElement([5]uint64{778774234987948, 1589187156384239, 1213330452914652, 186161118421127, 2186284806803213}), X: FieldElement{778774234987948, 1589187156384239, 1213330452914652, 186161118421127, 2186284806803213},
Y: base.FieldElement([5]uint64{1241255309069369, 1115278942994853, 1016511918109334, 1303231926552315, 1801448517689873}), Y: FieldElement{1241255309069369, 1115278942994853, 1016511918109334, 1303231926552315, 1801448517689873},
Z: base.FieldElement([5]uint64{353337085654440, 1327844406437681, 2207296012811921, 707394926933424, 917408459573183}), Z: FieldElement{353337085654440, 1327844406437681, 2207296012811921, 707394926933424, 917408459573183},
T: base.FieldElement([5]uint64{585487439439725, 1792815221887900, 946062846079052, 1954901232609667, 1418300670001780}), T: FieldElement{585487439439725, 1792815221887900, 946062846079052, 1954901232609667, 1418300670001780},
} }
) )
func TestScalarMulSmallScalars(t *testing.T) { func TestScalarMulSmallScalars(t *testing.T) {
var z scalar.Scalar var z Scalar
var p, check ProjP3 var p, check ProjP3
p.ScalarMul(&z, &B) p.ScalarMul(&z, &B)
check.Zero() check.Zero()
@ -37,7 +34,7 @@ func TestScalarMulSmallScalars(t *testing.T) {
t.Error("0*B != 0") 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) p.ScalarMul(&z, &B)
check.Set(&B) check.Set(&B)
if check.Equal(&p) != 1 { if check.Equal(&p) != 1 {
@ -63,7 +60,7 @@ func TestBasepointMulVsDalek(t *testing.T) {
func TestVartimeDoubleBaseMulVsDalek(t *testing.T) { func TestVartimeDoubleBaseMulVsDalek(t *testing.T) {
var p ProjP3 var p ProjP3
var z scalar.Scalar var z Scalar
p.VartimeDoubleBaseMul(&dalekScalar, &B, &z) p.VartimeDoubleBaseMul(&dalekScalar, &B, &z)
if dalekScalarBasepoint.Equal(&p) != 1 { if dalekScalarBasepoint.Equal(&p) != 1 {
t.Error("VartimeDoubleBaseMul fails with b=0") t.Error("VartimeDoubleBaseMul fails with b=0")
@ -75,14 +72,14 @@ func TestVartimeDoubleBaseMulVsDalek(t *testing.T) {
} }
func TestScalarMulDistributesOverAdd(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 // The quickcheck generation strategy chooses a random
// 32-byte array, but we require that the high bit is // 32-byte array, but we require that the high bit is
// unset. FIXME: make Scalar opaque. Until then, // unset. FIXME: make Scalar opaque. Until then,
// mask the high bits: // mask the high bits:
x[31] &= 127 x[31] &= 127
y[31] &= 127 y[31] &= 127
var z scalar.Scalar var z Scalar
z.Add(&x, &y) z.Add(&x, &y)
var p, q, r, check ProjP3 var p, q, r, check ProjP3
p.ScalarMul(&x, &B) p.ScalarMul(&x, &B)
@ -92,7 +89,7 @@ func TestScalarMulDistributesOverAdd(t *testing.T) {
return check.Equal(&r) == 1 return check.Equal(&r) == 1
} }
if err := quick.Check(scalarMulDistributesOverAdd, quickCheckConfig); err != nil { if err := quick.Check(scalarMulDistributesOverAdd, quickCheckConfig6); err != nil {
t.Error(err) t.Error(err)
} }
} }
@ -126,7 +123,7 @@ func TestBasepointTableGeneration(t *testing.T) {
} }
func TestScalarMulMatchesBasepointMul(t *testing.T) { func TestScalarMulMatchesBasepointMul(t *testing.T) {
scalarMulMatchesBasepointMul := func(x scalar.Scalar) bool { scalarMulMatchesBasepointMul := func(x Scalar) bool {
// FIXME opaque scalars // FIXME opaque scalars
x[31] &= 127 x[31] &= 127
var p, q ProjP3 var p, q ProjP3
@ -135,20 +132,20 @@ func TestScalarMulMatchesBasepointMul(t *testing.T) {
return p.Equal(&q) == 1 return p.Equal(&q) == 1
} }
if err := quick.Check(scalarMulMatchesBasepointMul, quickCheckConfig); err != nil { if err := quick.Check(scalarMulMatchesBasepointMul, quickCheckConfig6); err != nil {
t.Error(err) t.Error(err)
} }
} }
func TestMultiScalarMulMatchesBasepointMul(t *testing.T) { func TestMultiScalarMulMatchesBasepointMul(t *testing.T) {
multiScalarMulMatchesBasepointMul := func(x, y, z scalar.Scalar) bool { multiScalarMulMatchesBasepointMul := func(x, y, z Scalar) bool {
// FIXME opaque scalars // FIXME opaque scalars
x[31] &= 127 x[31] &= 127
y[31] &= 127 y[31] &= 127
z[31] &= 127 z[31] &= 127
var p, q1, q2, q3, check ProjP3 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) q1.BasepointMul(&x)
q2.BasepointMul(&y) q2.BasepointMul(&y)
@ -159,7 +156,7 @@ func TestMultiScalarMulMatchesBasepointMul(t *testing.T) {
return p.Equal(&check) == 1 return p.Equal(&check) == 1
} }
if err := quick.Check(multiScalarMulMatchesBasepointMul, quickCheckConfig); err != nil { if err := quick.Check(multiScalarMulMatchesBasepointMul, quickCheckConfig6); err != nil {
t.Error(err) t.Error(err)
} }
} }
@ -174,7 +171,7 @@ func TestBasepointNafTableGeneration(t *testing.T) {
} }
func TestVartimeDoubleBaseMulMatchesBasepointMul(t *testing.T) { func TestVartimeDoubleBaseMulMatchesBasepointMul(t *testing.T) {
vartimeDoubleBaseMulMatchesBasepointMul := func(x, y scalar.Scalar) bool { vartimeDoubleBaseMulMatchesBasepointMul := func(x, y Scalar) bool {
// FIXME opaque scalars // FIXME opaque scalars
x[31] &= 127 x[31] &= 127
y[31] &= 127 y[31] &= 127
@ -190,20 +187,20 @@ func TestVartimeDoubleBaseMulMatchesBasepointMul(t *testing.T) {
return p.Equal(&check) == 1 return p.Equal(&check) == 1
} }
if err := quick.Check(vartimeDoubleBaseMulMatchesBasepointMul, quickCheckConfig); err != nil { if err := quick.Check(vartimeDoubleBaseMulMatchesBasepointMul, quickCheckConfig6); err != nil {
t.Error(err) t.Error(err)
} }
} }
func TestVartimeMultiScalarMulMatchesBasepointMul(t *testing.T) { func TestVartimeMultiScalarMulMatchesBasepointMul(t *testing.T) {
vartimeMultiScalarMulMatchesBasepointMul := func(x, y, z scalar.Scalar) bool { vartimeMultiScalarMulMatchesBasepointMul := func(x, y, z Scalar) bool {
// FIXME opaque scalars // FIXME opaque scalars
x[31] &= 127 x[31] &= 127
y[31] &= 127 y[31] &= 127
z[31] &= 127 z[31] &= 127
var p, q1, q2, q3, check ProjP3 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) q1.BasepointMul(&x)
q2.BasepointMul(&y) q2.BasepointMul(&y)
@ -214,7 +211,7 @@ func TestVartimeMultiScalarMulMatchesBasepointMul(t *testing.T) {
return p.Equal(&check) == 1 return p.Equal(&check) == 1
} }
if err := quick.Check(vartimeMultiScalarMulMatchesBasepointMul, quickCheckConfig); err != nil { if err := quick.Check(vartimeMultiScalarMulMatchesBasepointMul, quickCheckConfig6); err != nil {
t.Error(err) t.Error(err)
} }
} }
@ -250,7 +247,7 @@ func BenchmarkMultiscalarMulSize8(t *testing.B) {
x := dalekScalar x := dalekScalar
for i := 0; i < t.N; i++ { 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 // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // 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 // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.