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:
parent
6f5f5828e1
commit
d3569cbbb3
2
LICENSE
2
LICENSE
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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"
|
|
@ -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)
|
|
@ -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.
|
||||
|
|
@ -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++ {
|
|
@ -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
|
|
@ -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"
|
||||
|
|
@ -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"
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
// +build !amd64 purego
|
||||
|
||||
package base
|
||||
package edwards25519
|
||||
|
||||
func feMul(v, x, y *FieldElement) { feMulGeneric(v, x, y) }
|
||||
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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
|
@ -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.
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
Loading…
Reference in a new issue