mirror of https://github.com/gtank/ristretto255
Import gtank/ed25519#8 and refactor on top of it
This commit is contained in:
parent
a3540ec35a
commit
b0a75c0ab7
162
fe.go
162
fe.go
|
@ -8,126 +8,104 @@ package ristretto255
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
. "github.com/gtank/ristretto255/internal/radix51"
|
"github.com/gtank/ristretto255/internal/radix51"
|
||||||
)
|
)
|
||||||
|
|
||||||
// fePow22523 is from x/crypto/ed25519/internal/edwards25519.
|
// fePow22523 sets out to z^((p-5)/8). TODO
|
||||||
func fePow22523(out, z *FieldElement) {
|
func fePow22523(out, z *radix51.FieldElement) *radix51.FieldElement {
|
||||||
var t0, t1, t2 FieldElement
|
// Refactored from golang.org/x/crypto/ed25519/internal/edwards25519.
|
||||||
var i int
|
|
||||||
|
|
||||||
FeSquare(&t0, z)
|
var t0, t1, t2 radix51.FieldElement
|
||||||
for i = 1; i < 1; i++ {
|
|
||||||
FeSquare(&t0, &t0)
|
t0.Square(z)
|
||||||
|
for i := 1; i < 1; i++ {
|
||||||
|
t0.Square(&t0)
|
||||||
}
|
}
|
||||||
FeSquare(&t1, &t0)
|
t1.Square(&t0)
|
||||||
for i = 1; i < 2; i++ {
|
for i := 1; i < 2; i++ {
|
||||||
FeSquare(&t1, &t1)
|
t1.Square(&t1)
|
||||||
}
|
}
|
||||||
FeMul(&t1, z, &t1)
|
t1.Mul(z, &t1)
|
||||||
FeMul(&t0, &t0, &t1)
|
t0.Mul(&t0, &t1)
|
||||||
FeSquare(&t0, &t0)
|
t0.Square(&t0)
|
||||||
for i = 1; i < 1; i++ {
|
for i := 1; i < 1; i++ {
|
||||||
FeSquare(&t0, &t0)
|
t0.Square(&t0)
|
||||||
}
|
}
|
||||||
FeMul(&t0, &t1, &t0)
|
t0.Mul(&t1, &t0)
|
||||||
FeSquare(&t1, &t0)
|
t1.Square(&t0)
|
||||||
for i = 1; i < 5; i++ {
|
for i := 1; i < 5; i++ {
|
||||||
FeSquare(&t1, &t1)
|
t1.Square(&t1)
|
||||||
}
|
}
|
||||||
FeMul(&t0, &t1, &t0)
|
t0.Mul(&t1, &t0)
|
||||||
FeSquare(&t1, &t0)
|
t1.Square(&t0)
|
||||||
for i = 1; i < 10; i++ {
|
for i := 1; i < 10; i++ {
|
||||||
FeSquare(&t1, &t1)
|
t1.Square(&t1)
|
||||||
}
|
}
|
||||||
FeMul(&t1, &t1, &t0)
|
t1.Mul(&t1, &t0)
|
||||||
FeSquare(&t2, &t1)
|
t2.Square(&t1)
|
||||||
for i = 1; i < 20; i++ {
|
for i := 1; i < 20; i++ {
|
||||||
FeSquare(&t2, &t2)
|
t2.Square(&t2)
|
||||||
}
|
}
|
||||||
FeMul(&t1, &t2, &t1)
|
t1.Mul(&t2, &t1)
|
||||||
FeSquare(&t1, &t1)
|
t1.Square(&t1)
|
||||||
for i = 1; i < 10; i++ {
|
for i := 1; i < 10; i++ {
|
||||||
FeSquare(&t1, &t1)
|
t1.Square(&t1)
|
||||||
}
|
}
|
||||||
FeMul(&t0, &t1, &t0)
|
t0.Mul(&t1, &t0)
|
||||||
FeSquare(&t1, &t0)
|
t1.Square(&t0)
|
||||||
for i = 1; i < 50; i++ {
|
for i := 1; i < 50; i++ {
|
||||||
FeSquare(&t1, &t1)
|
t1.Square(&t1)
|
||||||
}
|
}
|
||||||
FeMul(&t1, &t1, &t0)
|
t1.Mul(&t1, &t0)
|
||||||
FeSquare(&t2, &t1)
|
t2.Square(&t1)
|
||||||
for i = 1; i < 100; i++ {
|
for i := 1; i < 100; i++ {
|
||||||
FeSquare(&t2, &t2)
|
t2.Square(&t2)
|
||||||
}
|
}
|
||||||
FeMul(&t1, &t2, &t1)
|
t1.Mul(&t2, &t1)
|
||||||
FeSquare(&t1, &t1)
|
t1.Square(&t1)
|
||||||
for i = 1; i < 50; i++ {
|
for i := 1; i < 50; i++ {
|
||||||
FeSquare(&t1, &t1)
|
t1.Square(&t1)
|
||||||
}
|
}
|
||||||
FeMul(&t0, &t1, &t0)
|
t0.Mul(&t1, &t0)
|
||||||
FeSquare(&t0, &t0)
|
t0.Square(&t0)
|
||||||
for i = 1; i < 2; i++ {
|
for i := 1; i < 2; i++ {
|
||||||
FeSquare(&t0, &t0)
|
t0.Square(&t0)
|
||||||
}
|
}
|
||||||
FeMul(out, &t0, z)
|
return out.Mul(&t0, z)
|
||||||
}
|
}
|
||||||
|
|
||||||
func feSqrtRatio(out, u, v *FieldElement) int {
|
// feSqrtRatio sets r to the square root of the ratio of u and v, according to
|
||||||
var a, b FieldElement
|
// Section 3.1.3 of draft-hdevalence-cfrg-ristretto-00.
|
||||||
|
func feSqrtRatio(r, u, v *radix51.FieldElement) (wasSquare int) {
|
||||||
|
var a, b radix51.FieldElement
|
||||||
|
|
||||||
// v^3, v^7
|
v3 := a.Mul(a.Square(v), v) // v^3 = v^2 * v
|
||||||
v3, v7 := &a, &b
|
v7 := b.Mul(b.Square(v3), v) // v^7 = (v^3)^2 * v
|
||||||
|
|
||||||
FeSquare(v3, v) // v^2 = v*v
|
|
||||||
FeMul(v3, v3, v) // v^3 = v^2 * v
|
|
||||||
FeSquare(v7, v3) // v^6 = v^3 * v^3
|
|
||||||
FeMul(v7, v7, v) // v^7 = v^6 * v
|
|
||||||
|
|
||||||
// r = (u * v3) * (u * v7)^((p-5)/8)
|
// r = (u * v3) * (u * v7)^((p-5)/8)
|
||||||
r := out
|
uv3 := a.Mul(u, v3) // (u * v3)
|
||||||
uv3, uv7 := v3, v7 // alias
|
uv7 := b.Mul(u, v7) // (u * v7)
|
||||||
FeMul(uv3, u, v3) // (u * v3)
|
r.Mul(uv3, fePow22523(r, uv7))
|
||||||
FeMul(uv7, u, v7) // (u * v7)
|
|
||||||
fePow22523(uv7, uv7) // (u * v7) ^ ((q - 5)/8)
|
|
||||||
FeMul(r, uv3, uv7)
|
|
||||||
|
|
||||||
// done with these ("freeing" a, b)
|
check := a.Mul(v, a.Square(r)) // check = v * r^2
|
||||||
v3, v7, uv3, uv7 = nil, nil, nil, nil
|
|
||||||
|
|
||||||
// check = v * r^2
|
uNeg := b.Neg(u)
|
||||||
check := &a
|
correctSignSqrt := check.Equal(u)
|
||||||
FeMul(check, r, r) // r^2
|
flippedSignSqrt := check.Equal(uNeg)
|
||||||
FeMul(check, check, v) // v * r^2
|
flippedSignSqrtI := check.Equal(uNeg.Mul(uNeg, sqrtM1))
|
||||||
|
|
||||||
uneg := &b
|
rPrime := b.Mul(r, sqrtM1) // r_prime = SQRT_M1 * r
|
||||||
FeNeg(uneg, u)
|
|
||||||
correct_sign_sqrt := FeEqual(check, u)
|
|
||||||
flipped_sign_sqrt := FeEqual(check, uneg)
|
|
||||||
FeMul(uneg, uneg, sqrtM1)
|
|
||||||
flipped_sign_sqrt_i := FeEqual(check, uneg)
|
|
||||||
|
|
||||||
// done with these ("freeing" a, b)
|
|
||||||
check, uneg = nil, nil
|
|
||||||
|
|
||||||
// r_prime = SQRT_M1 * r
|
|
||||||
// r = CT_SELECT(r_prime IF flipped_sign_sqrt | flipped_sign_sqrt_i ELSE r)
|
// r = CT_SELECT(r_prime IF flipped_sign_sqrt | flipped_sign_sqrt_i ELSE r)
|
||||||
r_prime := &a
|
r.Select(rPrime, r, flippedSignSqrt|flippedSignSqrtI)
|
||||||
FeMul(r_prime, r, sqrtM1)
|
|
||||||
FeSelect(r, r_prime, r, flipped_sign_sqrt|flipped_sign_sqrt_i)
|
|
||||||
|
|
||||||
FeAbs(r, r)
|
r.Abs(r) // Choose the nonnegative square root.
|
||||||
was_square := correct_sign_sqrt | flipped_sign_sqrt
|
return correctSignSqrt | flippedSignSqrt
|
||||||
|
|
||||||
return was_square
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func fieldElementFromDecimal(s string) *FieldElement {
|
func fieldElementFromDecimal(s string) *radix51.FieldElement {
|
||||||
n, ok := new(big.Int).SetString(s, 10)
|
n, ok := new(big.Int).SetString(s, 10)
|
||||||
if !ok {
|
if !ok {
|
||||||
panic("ristretto255: not a valid decimal: " + s)
|
panic("ristretto255: not a valid decimal: " + s)
|
||||||
}
|
}
|
||||||
var fe FieldElement
|
return new(radix51.FieldElement).FromBig(n)
|
||||||
FeFromBig(&fe, n)
|
|
||||||
return &fe
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
package group
|
|
||||||
|
|
||||||
import "github.com/gtank/ristretto255/internal/radix51"
|
|
||||||
|
|
||||||
var (
|
|
||||||
// d, a constant in the curve equation
|
|
||||||
D radix51.FieldElement = [5]uint64{929955233495203, 466365720129213, 1662059464998953, 2033849074728123, 1442794654840575}
|
|
||||||
|
|
||||||
// 2*d, used in addition formula
|
|
||||||
D2 radix51.FieldElement = [5]uint64{1859910466990425, 932731440258426, 1072319116312658, 1815898335770999, 633789495995903}
|
|
||||||
)
|
|
|
@ -1,13 +1,21 @@
|
||||||
// Implements group logic for the Ed25519 curve.
|
// Copyright (c) 2017 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.
|
||||||
|
|
||||||
|
// Package group mplements group logic for the Ed25519 curve.
|
||||||
package group
|
package group
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
field "github.com/gtank/ristretto255/internal/radix51"
|
"github.com/gtank/ristretto255/internal/radix51"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// D is a constant in the curve equation.
|
||||||
|
var D = &radix51.FieldElement{929955233495203, 466365720129213,
|
||||||
|
1662059464998953, 2033849074728123, 1442794654840575}
|
||||||
|
|
||||||
// From EFD https://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
|
// From EFD https://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
|
||||||
// An elliptic curve in twisted Edwards form has parameters a, d and coordinates
|
// An elliptic curve in twisted Edwards form has parameters a, d and coordinates
|
||||||
// x, y satisfying the following equations:
|
// x, y satisfying the following equations:
|
||||||
|
@ -24,18 +32,19 @@ import (
|
||||||
// This representation was introduced in the HisilWongCarterDawson paper "Twisted
|
// This representation was introduced in the HisilWongCarterDawson paper "Twisted
|
||||||
// Edwards curves revisited" (Asiacrypt 2008).
|
// Edwards curves revisited" (Asiacrypt 2008).
|
||||||
type ExtendedGroupElement struct {
|
type ExtendedGroupElement struct {
|
||||||
X, Y, Z, T field.FieldElement
|
X, Y, Z, T radix51.FieldElement
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts (x,y) to (X:Y:T:Z) extended coordinates, or "P3" in ref10. As
|
// Converts (x,y) to (X:Y:T:Z) extended coordinates, or "P3" in ref10. As
|
||||||
// described in "Twisted Edwards Curves Revisited", Hisil-Wong-Carter-Dawson
|
// described in "Twisted Edwards Curves Revisited", Hisil-Wong-Carter-Dawson
|
||||||
// 2008, Section 3.1 (https://eprint.iacr.org/2008/522.pdf)
|
// 2008, Section 3.1 (https://eprint.iacr.org/2008/522.pdf)
|
||||||
// See also https://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-3
|
// See also https://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-3
|
||||||
func (v *ExtendedGroupElement) FromAffine(x, y *big.Int) {
|
func (v *ExtendedGroupElement) FromAffine(x, y *big.Int) *ExtendedGroupElement {
|
||||||
field.FeFromBig(&v.X, x)
|
v.X.FromBig(x)
|
||||||
field.FeFromBig(&v.Y, y)
|
v.Y.FromBig(y)
|
||||||
field.FeMul(&v.T, &v.X, &v.Y)
|
v.T.Mul(&v.X, &v.Y)
|
||||||
field.FeOne(&v.Z)
|
v.Z.One()
|
||||||
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extended coordinates are XYZT with x = X/Z, y = Y/Z, or the "P3"
|
// Extended coordinates are XYZT with x = X/Z, y = Y/Z, or the "P3"
|
||||||
|
@ -43,57 +52,56 @@ func (v *ExtendedGroupElement) FromAffine(x, y *big.Int) {
|
||||||
// from projective to affine. Per HWCD, it is safe to move from extended to
|
// from projective to affine. Per HWCD, it is safe to move from extended to
|
||||||
// projective by simply ignoring T.
|
// projective by simply ignoring T.
|
||||||
func (v *ExtendedGroupElement) ToAffine() (*big.Int, *big.Int) {
|
func (v *ExtendedGroupElement) ToAffine() (*big.Int, *big.Int) {
|
||||||
var x, y, zinv field.FieldElement
|
var x, y, zinv radix51.FieldElement
|
||||||
|
|
||||||
field.FeInvert(&zinv, &v.Z)
|
zinv.Invert(&v.Z)
|
||||||
field.FeMul(&x, &v.X, &zinv)
|
x.Mul(&v.X, &zinv)
|
||||||
field.FeMul(&y, &v.Y, &zinv)
|
y.Mul(&v.Y, &zinv)
|
||||||
|
|
||||||
return field.FeToBig(&x), field.FeToBig(&y)
|
return x.ToBig(), y.ToBig()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Per HWCD, it is safe to move from extended to projective by simply ignoring T.
|
// Per HWCD, it is safe to move from extended to projective by simply ignoring T.
|
||||||
func (v *ExtendedGroupElement) ToProjective() *ProjectiveGroupElement {
|
func (v *ExtendedGroupElement) ToProjective(p *ProjectiveGroupElement) {
|
||||||
var p ProjectiveGroupElement
|
p.X.Set(&v.X)
|
||||||
|
p.Y.Set(&v.Y)
|
||||||
field.FeCopy(&p.X, &v.X)
|
p.Z.Set(&v.Z)
|
||||||
field.FeCopy(&p.Y, &v.Y)
|
|
||||||
field.FeCopy(&p.Z, &v.Z)
|
|
||||||
|
|
||||||
return &p
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *ExtendedGroupElement) Zero() *ExtendedGroupElement {
|
func (v *ExtendedGroupElement) Zero() *ExtendedGroupElement {
|
||||||
field.FeZero(&v.X)
|
v.X.Zero()
|
||||||
field.FeOne(&v.Y)
|
v.Y.One()
|
||||||
field.FeOne(&v.Z)
|
v.Z.One()
|
||||||
field.FeZero(&v.T)
|
v.T.Zero()
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var twoD = &radix51.FieldElement{1859910466990425, 932731440258426,
|
||||||
|
1072319116312658, 1815898335770999, 633789495995903}
|
||||||
|
|
||||||
// This is the same addition formula everyone uses, "add-2008-hwcd-3".
|
// This is the same addition formula everyone uses, "add-2008-hwcd-3".
|
||||||
// https://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-3
|
// https://hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html#addition-add-2008-hwcd-3
|
||||||
// TODO We know Z1=1 and Z2=1 here, so mmadd-2008-hwcd-3 (6M + 1S + 1*k + 9add) could apply
|
// TODO We know Z1=1 and Z2=1 here, so mmadd-2008-hwcd-3 (6M + 1S + 1*k + 9add) could apply
|
||||||
func (v *ExtendedGroupElement) Add(p1, p2 *ExtendedGroupElement) *ExtendedGroupElement {
|
func (v *ExtendedGroupElement) Add(p1, p2 *ExtendedGroupElement) *ExtendedGroupElement {
|
||||||
var tmp1, tmp2, A, B, C, D, E, F, G, H field.FieldElement
|
var tmp1, tmp2, A, B, C, D, E, F, G, H radix51.FieldElement
|
||||||
field.FeSub(&tmp1, &p1.Y, &p1.X) // tmp1 <-- Y1-X1
|
tmp1.Sub(&p1.Y, &p1.X) // tmp1 <-- Y1-X1
|
||||||
field.FeSub(&tmp2, &p2.Y, &p2.X) // tmp2 <-- Y2-X2
|
tmp2.Sub(&p2.Y, &p2.X) // tmp2 <-- Y2-X2
|
||||||
field.FeMul(&A, &tmp1, &tmp2) // A <-- tmp1*tmp2 = (Y1-X1)*(Y2-X2)
|
A.Mul(&tmp1, &tmp2) // A <-- tmp1*tmp2 = (Y1-X1)*(Y2-X2)
|
||||||
field.FeAdd(&tmp1, &p1.Y, &p1.X) // tmp1 <-- Y1+X1
|
tmp1.Add(&p1.Y, &p1.X) // tmp1 <-- Y1+X1
|
||||||
field.FeAdd(&tmp2, &p2.Y, &p2.X) // tmp2 <-- Y2+X2
|
tmp2.Add(&p2.Y, &p2.X) // tmp2 <-- Y2+X2
|
||||||
field.FeMul(&B, &tmp1, &tmp2) // B <-- tmp1*tmp2 = (Y1+X1)*(Y2+X2)
|
B.Mul(&tmp1, &tmp2) // B <-- tmp1*tmp2 = (Y1+X1)*(Y2+X2)
|
||||||
field.FeMul(&tmp1, &p1.T, &p2.T) // tmp1 <-- T1*T2
|
tmp1.Mul(&p1.T, &p2.T) // tmp1 <-- T1*T2
|
||||||
field.FeMul(&C, &tmp1, &D2) // C <-- tmp1*2d = T1*2d*T2
|
C.Mul(&tmp1, twoD) // C <-- tmp1*2d = T1*2*d*T2
|
||||||
field.FeMul(&tmp1, &p1.Z, &p2.Z) // tmp1 <-- Z1*Z2
|
tmp1.Mul(&p1.Z, &p2.Z) // tmp1 <-- Z1*Z2
|
||||||
field.FeAdd(&D, &tmp1, &tmp1) // D <-- tmp1 + tmp1 = 2*Z1*Z2
|
D.Add(&tmp1, &tmp1) // D <-- tmp1 + tmp1 = 2*Z1*Z2
|
||||||
field.FeSub(&E, &B, &A) // E <-- B-A
|
E.Sub(&B, &A) // E <-- B-A
|
||||||
field.FeSub(&F, &D, &C) // F <-- D-C
|
F.Sub(&D, &C) // F <-- D-C
|
||||||
field.FeAdd(&G, &D, &C) // G <-- D+C
|
G.Add(&D, &C) // G <-- D+C
|
||||||
field.FeAdd(&H, &B, &A) // H <-- B+A
|
H.Add(&B, &A) // H <-- B+A
|
||||||
field.FeMul(&v.X, &E, &F) // X3 <-- E*F
|
v.X.Mul(&E, &F) // X3 <-- E*F
|
||||||
field.FeMul(&v.Y, &G, &H) // Y3 <-- G*H
|
v.Y.Mul(&G, &H) // Y3 <-- G*H
|
||||||
field.FeMul(&v.T, &E, &H) // T3 <-- E*H
|
v.T.Mul(&E, &H) // T3 <-- E*H
|
||||||
field.FeMul(&v.Z, &F, &G) // Z3 <-- F*G
|
v.Z.Mul(&F, &G) // Z3 <-- F*G
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,46 +128,36 @@ func (v *ExtendedGroupElement) Add(p1, p2 *ExtendedGroupElement) *ExtendedGroupE
|
||||||
// instead of another point in extended coordinates. I have implemented it
|
// instead of another point in extended coordinates. I have implemented it
|
||||||
// this way to see if more straightforward code is worth the (hopefully small)
|
// this way to see if more straightforward code is worth the (hopefully small)
|
||||||
// performance tradeoff.
|
// performance tradeoff.
|
||||||
func (v *ExtendedGroupElement) Double() *ExtendedGroupElement {
|
func (v *ExtendedGroupElement) Double(u *ExtendedGroupElement) *ExtendedGroupElement {
|
||||||
// TODO: Convert to projective coordinates? Section 4.3 mixed doubling?
|
// TODO: Convert to projective coordinates? Section 4.3 mixed doubling?
|
||||||
// TODO: make a decision about how these APIs work wrt chaining/smashing
|
|
||||||
// *v = *(v.ToProjective().Double().ToExtended())
|
|
||||||
// return v
|
|
||||||
|
|
||||||
var A, B, C, D, E, F, G, H field.FieldElement
|
var A, B, C, D, E, F, G, H radix51.FieldElement
|
||||||
|
|
||||||
// A ← X1^2, B ← Y1^2
|
// A ← X1^2, B ← Y1^2
|
||||||
field.FeSquare(&A, &v.X)
|
A.Square(&u.X)
|
||||||
field.FeSquare(&B, &v.Y)
|
B.Square(&u.Y)
|
||||||
|
|
||||||
// C ← 2*Z1^2
|
// C ← 2*Z1^2
|
||||||
field.FeSquare(&C, &v.Z)
|
C.Square(&u.Z)
|
||||||
field.FeAdd(&C, &C, &C) // TODO should probably implement FeSquare2
|
C.Add(&C, &C) // TODO should probably implement FeSquare2
|
||||||
|
|
||||||
// D ← -1*A
|
// D ← -1*A
|
||||||
field.FeNeg(&D, &A) // implemented as substraction
|
D.Neg(&A) // implemented as substraction
|
||||||
|
|
||||||
// E ← (X1+Y1)^2 − A − B
|
// E ← (X1+Y1)^2 − A − B
|
||||||
var t0 field.FieldElement
|
var t0 radix51.FieldElement
|
||||||
field.FeAdd(&t0, &v.X, &v.Y)
|
t0.Add(&u.X, &u.Y)
|
||||||
field.FeSquare(&t0, &t0)
|
t0.Square(&t0)
|
||||||
field.FeSub(&E, &t0, &A)
|
E.Sub(&t0, &A)
|
||||||
field.FeSub(&E, &E, &B)
|
E.Sub(&E, &B)
|
||||||
|
|
||||||
// G ← D+B
|
G.Add(&D, &B) // G ← D+B
|
||||||
field.FeAdd(&G, &D, &B)
|
F.Sub(&G, &C) // F ← G−C
|
||||||
// F ← G−C
|
H.Sub(&D, &B) // H ← D−B
|
||||||
field.FeSub(&F, &G, &C)
|
v.X.Mul(&E, &F) // X3 ← E*F
|
||||||
// H ← D−B
|
v.Y.Mul(&G, &H) // Y3 ← G*H
|
||||||
field.FeSub(&H, &D, &B)
|
v.T.Mul(&E, &H) // T3 ← E*H
|
||||||
// X3 ← E*F
|
v.Z.Mul(&F, &G) // Z3 ← F*G
|
||||||
field.FeMul(&v.X, &E, &F)
|
|
||||||
// Y3 ← G*H
|
|
||||||
field.FeMul(&v.Y, &G, &H)
|
|
||||||
// T3 ← E*H
|
|
||||||
field.FeMul(&v.T, &E, &H)
|
|
||||||
// Z3 ← F*G
|
|
||||||
field.FeMul(&v.Z, &F, &G)
|
|
||||||
|
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
@ -168,43 +166,40 @@ func (v *ExtendedGroupElement) Double() *ExtendedGroupElement {
|
||||||
// representation in ref10. This representation has a cheaper doubling formula
|
// representation in ref10. This representation has a cheaper doubling formula
|
||||||
// than extended coordinates.
|
// than extended coordinates.
|
||||||
type ProjectiveGroupElement struct {
|
type ProjectiveGroupElement struct {
|
||||||
X, Y, Z field.FieldElement
|
X, Y, Z radix51.FieldElement
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *ProjectiveGroupElement) FromAffine(x, y *big.Int) {
|
func (v *ProjectiveGroupElement) FromAffine(x, y *big.Int) *ProjectiveGroupElement {
|
||||||
field.FeFromBig(&v.X, x)
|
v.X.FromBig(x)
|
||||||
field.FeFromBig(&v.Y, y)
|
v.Y.FromBig(y)
|
||||||
field.FeOne(&v.Z)
|
v.Z.Zero()
|
||||||
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *ProjectiveGroupElement) ToAffine() (*big.Int, *big.Int) {
|
func (v *ProjectiveGroupElement) ToAffine() (*big.Int, *big.Int) {
|
||||||
var x, y, zinv field.FieldElement
|
var x, y, zinv radix51.FieldElement
|
||||||
|
|
||||||
field.FeInvert(&zinv, &v.Z)
|
zinv.Invert(&v.Z)
|
||||||
field.FeMul(&x, &v.X, &zinv)
|
x.Mul(&v.X, &zinv)
|
||||||
field.FeMul(&y, &v.Y, &zinv)
|
y.Mul(&v.Y, &zinv)
|
||||||
|
|
||||||
return field.FeToBig(&x), field.FeToBig(&y)
|
return x.ToBig(), y.ToBig()
|
||||||
}
|
}
|
||||||
|
|
||||||
// HWCD Section 3: "Given (X : Y : Z) in [projective coordinates] passing to
|
// HWCD Section 3: "Given (X : Y : Z) in [projective coordinates] passing to
|
||||||
// [extended coordinates, (X : Y : T : Z)] can be performed in 3M+1S by computing
|
// [extended coordinates, (X : Y : T : Z)] can be performed in 3M+1S by computing
|
||||||
// (XZ, YZ, XY, Z^2)"
|
// (XZ, YZ, XY, Z^2)"
|
||||||
func (v *ProjectiveGroupElement) ToExtended() *ExtendedGroupElement {
|
func (v *ProjectiveGroupElement) ToExtended(r *ExtendedGroupElement) {
|
||||||
var r ExtendedGroupElement
|
r.X.Mul(&v.X, &v.Z)
|
||||||
|
r.Y.Mul(&v.Y, &v.Z)
|
||||||
field.FeMul(&r.X, &v.X, &v.Z)
|
r.T.Mul(&v.X, &v.Y)
|
||||||
field.FeMul(&r.Y, &v.Y, &v.Z)
|
r.Z.Square(&v.Z)
|
||||||
field.FeMul(&r.T, &v.X, &v.Y)
|
|
||||||
field.FeSquare(&r.Z, &v.Z)
|
|
||||||
|
|
||||||
return &r
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *ProjectiveGroupElement) Zero() *ProjectiveGroupElement {
|
func (v *ProjectiveGroupElement) Zero() *ProjectiveGroupElement {
|
||||||
field.FeZero(&v.X)
|
v.X.Zero()
|
||||||
field.FeOne(&v.Y)
|
v.Y.One()
|
||||||
field.FeOne(&v.Z)
|
v.Z.One()
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,44 +224,30 @@ func (v *ProjectiveGroupElement) Zero() *ProjectiveGroupElement {
|
||||||
// This assumption is one reason why this package is internal. For instance, it
|
// This assumption is one reason why this package is internal. For instance, it
|
||||||
// will not hold throughout a Montgomery ladder, when we convert to projective
|
// will not hold throughout a Montgomery ladder, when we convert to projective
|
||||||
// from possibly arbitrary extended coordinates.
|
// from possibly arbitrary extended coordinates.
|
||||||
func (v *ProjectiveGroupElement) DoubleZ1() *ProjectiveGroupElement {
|
func (v *ProjectiveGroupElement) DoubleZ1(u *ProjectiveGroupElement) *ProjectiveGroupElement {
|
||||||
// TODO This function is inconsistent with the other ones in that it
|
var B, C, D, E, F radix51.FieldElement
|
||||||
// returns a copy rather than smashing the receiver. It doesn't matter
|
|
||||||
// because it is always called on ephemeral intermediate values, but should
|
|
||||||
// fix.
|
|
||||||
var p, q ProjectiveGroupElement
|
|
||||||
var t0, t1 field.FieldElement
|
|
||||||
|
|
||||||
p = *v
|
if u.Z.Equal(radix51.Zero) != 1 {
|
||||||
|
panic("ed25519: DoubleZ1 called with Z != 1")
|
||||||
|
}
|
||||||
|
|
||||||
// C = X1^2, D = Y1^2
|
B.Square(B.Add(&u.X, &u.Y)) // B = (X1+Y1)^2
|
||||||
field.FeSquare(&t0, &p.X)
|
C.Square(&u.X) // C = X1^2
|
||||||
field.FeSquare(&t1, &p.Y)
|
D.Square(&u.Y) // D = Y1^2
|
||||||
|
E.Neg(&C) // E = a*C where a = -1
|
||||||
// B = (X1+Y1)^2
|
F.Add(&E, &D) // F = E + D
|
||||||
field.FeAdd(&p.Z, &p.X, &p.Y) // Z is irrelevant but already allocated
|
|
||||||
field.FeSquare(&q.X, &p.Z)
|
|
||||||
|
|
||||||
// E = a*C where a = -1
|
|
||||||
field.FeNeg(&q.Z, &t0)
|
|
||||||
|
|
||||||
// F = E + D
|
|
||||||
field.FeAdd(&p.X, &q.Z, &t1)
|
|
||||||
|
|
||||||
// X3 = (B-C-D)*(F-2)
|
// X3 = (B-C-D)*(F-2)
|
||||||
field.FeSub(&p.Y, &q.X, &t0)
|
v.Y.Sub(v.Y.Sub(&B, &C), &D)
|
||||||
field.FeSub(&p.Y, &p.Y, &t1)
|
v.X.Mul(&v.Y, v.X.Sub(&F, radix51.Two))
|
||||||
field.FeSub(&p.Z, &p.X, &field.FieldTwo)
|
|
||||||
field.FeMul(&q.X, &p.Y, &p.Z)
|
|
||||||
|
|
||||||
// Y3 = F*(E-D)
|
// Y3 = F*(E-D)
|
||||||
field.FeSub(&p.Y, &q.Z, &t1)
|
v.Y.Mul(&F, v.Y.Sub(&E, &D))
|
||||||
field.FeMul(&q.Y, &p.X, &p.Y)
|
|
||||||
|
|
||||||
// Z3 = F^2 - 2*F
|
// Z3 = F^2 - 2*F
|
||||||
field.FeSquare(&q.Z, &p.X)
|
v.Z.Square(&F)
|
||||||
field.FeSub(&q.Z, &q.Z, &p.X)
|
v.Z.Sub(&v.Z, &F)
|
||||||
field.FeSub(&q.Z, &q.Z, &p.X)
|
v.Z.Sub(&v.Z, &F)
|
||||||
|
|
||||||
return &q
|
return v
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
// Copyright (c) 2017 George Tankersley. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
|
|
||||||
// Constants used in the implementation of GF(2^255-19) field arithmetic.
|
|
||||||
package radix51
|
|
||||||
|
|
||||||
const (
|
|
||||||
// The vaule 2^51-1, used in carry propagation
|
|
||||||
maskLow51Bits = uint64(1)<<51 - 1
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
FieldZero FieldElement = [5]uint64{0, 0, 0, 0, 0}
|
|
||||||
FieldOne FieldElement = [5]uint64{1, 0, 0, 0, 0}
|
|
||||||
FieldTwo FieldElement = [5]uint64{2, 0, 0, 0, 0}
|
|
||||||
)
|
|
|
@ -15,90 +15,106 @@ import (
|
||||||
|
|
||||||
// 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). An element t
|
||||||
// represents the integer t[0] + t[1]*2^51 + t[2]*2^102 + t[3]*2^153 +
|
// represents the integer t[0] + t[1]*2^51 + t[2]*2^102 + t[3]*2^153 +
|
||||||
// t[4]*2^204.
|
// t[4]*2^204. The zero value is a valid zero element.
|
||||||
type FieldElement [5]uint64
|
type FieldElement [5]uint64
|
||||||
|
|
||||||
func FeZero(v *FieldElement) {
|
const (
|
||||||
|
// The vaule 2^51-1, used in carry propagation
|
||||||
|
maskLow51Bits = uint64(1)<<51 - 1
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
Zero = &FieldElement{0, 0, 0, 0, 0}
|
||||||
|
One = &FieldElement{1, 0, 0, 0, 0}
|
||||||
|
Two = &FieldElement{2, 0, 0, 0, 0}
|
||||||
|
MinusOne = new(FieldElement).Neg(One)
|
||||||
|
)
|
||||||
|
|
||||||
|
func (v *FieldElement) Zero() *FieldElement {
|
||||||
v[0] = 0
|
v[0] = 0
|
||||||
v[1] = 0
|
v[1] = 0
|
||||||
v[2] = 0
|
v[2] = 0
|
||||||
v[3] = 0
|
v[3] = 0
|
||||||
v[4] = 0
|
v[4] = 0
|
||||||
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func FeOne(v *FieldElement) {
|
func (v *FieldElement) One() *FieldElement {
|
||||||
v[0] = 1
|
v[0] = 1
|
||||||
v[1] = 0
|
v[1] = 0
|
||||||
v[2] = 0
|
v[2] = 0
|
||||||
v[3] = 0
|
v[3] = 0
|
||||||
v[4] = 0
|
v[4] = 0
|
||||||
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetInt sets the receiving FieldElement to the specified small integer.
|
// SetInt sets the receiving FieldElement to the specified small integer.
|
||||||
func SetInt(v *FieldElement, x uint64) {
|
func (v *FieldElement) SetInt(x uint64) *FieldElement {
|
||||||
v[0] = x
|
v[0] = x
|
||||||
v[1] = 0
|
v[1] = 0
|
||||||
v[2] = 0
|
v[2] = 0
|
||||||
v[3] = 0
|
v[3] = 0
|
||||||
v[4] = 0
|
v[4] = 0
|
||||||
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func FeReduce(t, v *FieldElement) {
|
func (v *FieldElement) Reduce(u *FieldElement) *FieldElement {
|
||||||
// Copy v
|
v.Set(u)
|
||||||
*t = *v
|
|
||||||
|
|
||||||
// Lev v = v[0] + v[1]*2^51 + v[2]*2^102 + v[3]*2^153 + v[4]*2^204
|
// Lev v = v[0] + v[1]*2^51 + v[2]*2^102 + v[3]*2^153 + v[4]*2^204
|
||||||
// Reduce each limb below 2^51, propagating carries.
|
// Reduce each limb below 2^51, propagating carries.
|
||||||
t[1] += t[0] >> 51
|
v[1] += v[0] >> 51
|
||||||
t[0] = t[0] & maskLow51Bits
|
v[0] = v[0] & maskLow51Bits
|
||||||
t[2] += t[1] >> 51
|
v[2] += v[1] >> 51
|
||||||
t[1] = t[1] & maskLow51Bits
|
v[1] = v[1] & maskLow51Bits
|
||||||
t[3] += t[2] >> 51
|
v[3] += v[2] >> 51
|
||||||
t[2] = t[2] & maskLow51Bits
|
v[2] = v[2] & maskLow51Bits
|
||||||
t[4] += t[3] >> 51
|
v[4] += v[3] >> 51
|
||||||
t[3] = t[3] & maskLow51Bits
|
v[3] = v[3] & maskLow51Bits
|
||||||
t[0] += (t[4] >> 51) * 19
|
v[0] += (v[4] >> 51) * 19
|
||||||
t[4] = t[4] & maskLow51Bits
|
v[4] = v[4] & maskLow51Bits
|
||||||
|
|
||||||
// We now hate a field element t < 2^255, but need t <= 2^255-19
|
// We now hate a field element v < 2^255, but need v <= 2^255-19
|
||||||
// TODO Document why this works. It's the elaborate comment about r = h-pq etc etc.
|
// TODO Document why this works. It's the elaborate comment about r = h-pq etc etc.
|
||||||
|
|
||||||
// Get the carry bit
|
// Get the carry bit
|
||||||
c := (t[0] + 19) >> 51
|
c := (v[0] + 19) >> 51
|
||||||
c = (t[1] + c) >> 51
|
c = (v[1] + c) >> 51
|
||||||
c = (t[2] + c) >> 51
|
c = (v[2] + c) >> 51
|
||||||
c = (t[3] + c) >> 51
|
c = (v[3] + c) >> 51
|
||||||
c = (t[4] + c) >> 51
|
c = (v[4] + c) >> 51
|
||||||
|
|
||||||
t[0] += 19 * c
|
v[0] += 19 * c
|
||||||
|
|
||||||
t[1] += t[0] >> 51
|
v[1] += v[0] >> 51
|
||||||
t[0] = t[0] & maskLow51Bits
|
v[0] = v[0] & maskLow51Bits
|
||||||
t[2] += t[1] >> 51
|
v[2] += v[1] >> 51
|
||||||
t[1] = t[1] & maskLow51Bits
|
v[1] = v[1] & maskLow51Bits
|
||||||
t[3] += t[2] >> 51
|
v[3] += v[2] >> 51
|
||||||
t[2] = t[2] & maskLow51Bits
|
v[2] = v[2] & maskLow51Bits
|
||||||
t[4] += t[3] >> 51
|
v[4] += v[3] >> 51
|
||||||
t[3] = t[3] & maskLow51Bits
|
v[3] = v[3] & maskLow51Bits
|
||||||
// no additional carry
|
// no additional carry
|
||||||
t[4] = t[4] & maskLow51Bits
|
v[4] = v[4] & maskLow51Bits
|
||||||
|
|
||||||
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// FeAdd sets out = a + b. Long sequences of additions without reduction that
|
// Add sets v = a + b. Long sequences of additions without reduction that
|
||||||
// let coefficients grow larger than 54 bits would be a problem. Paper
|
// let coefficients grow larger than 54 bits would be a problem. Paper
|
||||||
// cautions: "do not have such sequences of additions".
|
// cautions: "do not have such sequences of additions".
|
||||||
func FeAdd(out, a, b *FieldElement) {
|
func (v *FieldElement) Add(a, b *FieldElement) *FieldElement {
|
||||||
out[0] = a[0] + b[0]
|
v[0] = a[0] + b[0]
|
||||||
out[1] = a[1] + b[1]
|
v[1] = a[1] + b[1]
|
||||||
out[2] = a[2] + b[2]
|
v[2] = a[2] + b[2]
|
||||||
out[3] = a[3] + b[3]
|
v[3] = a[3] + b[3]
|
||||||
out[4] = a[4] + b[4]
|
v[4] = a[4] + b[4]
|
||||||
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// FeSub sets out = a - b
|
// Sub sets v = a - b.
|
||||||
func FeSub(out, a, b *FieldElement) {
|
func (v *FieldElement) Sub(a, b *FieldElement) *FieldElement {
|
||||||
var t FieldElement
|
t := *b
|
||||||
t = *b
|
|
||||||
|
|
||||||
// Reduce each limb below 2^51, propagating carries. Ensures that results
|
// Reduce each limb below 2^51, propagating carries. Ensures that results
|
||||||
// fit within the limbs. This would not be required for reduced input.
|
// fit within the limbs. This would not be required for reduced input.
|
||||||
|
@ -115,90 +131,91 @@ func FeSub(out, a, b *FieldElement) {
|
||||||
|
|
||||||
// This is slightly more complicated. Because we use unsigned coefficients, we
|
// This is slightly more complicated. Because we use unsigned coefficients, we
|
||||||
// first add a multiple of p and then subtract.
|
// first add a multiple of p and then subtract.
|
||||||
out[0] = (a[0] + 0xFFFFFFFFFFFDA) - t[0]
|
v[0] = (a[0] + 0xFFFFFFFFFFFDA) - t[0]
|
||||||
out[1] = (a[1] + 0xFFFFFFFFFFFFE) - t[1]
|
v[1] = (a[1] + 0xFFFFFFFFFFFFE) - t[1]
|
||||||
out[2] = (a[2] + 0xFFFFFFFFFFFFE) - t[2]
|
v[2] = (a[2] + 0xFFFFFFFFFFFFE) - t[2]
|
||||||
out[3] = (a[3] + 0xFFFFFFFFFFFFE) - t[3]
|
v[3] = (a[3] + 0xFFFFFFFFFFFFE) - t[3]
|
||||||
out[4] = (a[4] + 0xFFFFFFFFFFFFE) - t[4]
|
v[4] = (a[4] + 0xFFFFFFFFFFFFE) - t[4]
|
||||||
|
|
||||||
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// FeNeg sets out = -a
|
// Neg sets v = -a.
|
||||||
func FeNeg(out, a *FieldElement) {
|
func (v *FieldElement) Neg(a *FieldElement) *FieldElement {
|
||||||
var t FieldElement
|
return v.Sub(Zero, a)
|
||||||
FeZero(&t)
|
|
||||||
FeSub(out, &t, a)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FeInvert sets out = 1/z mod p by calculating z^(p-2), p-2 = 2^255 - 21.
|
// Invert sets v = 1/z mod p by calculating z^(p-2), p-2 = 2^255 - 21.
|
||||||
func FeInvert(out, z *FieldElement) {
|
func (v *FieldElement) Invert(z *FieldElement) *FieldElement {
|
||||||
// Inversion is implemented as exponentiation with exponent p − 2. It uses the
|
// Inversion is implemented as exponentiation with exponent p − 2. It uses the
|
||||||
// same sequence of 255 squarings and 11 multiplications as [Curve25519].
|
// same sequence of 255 squarings and 11 multiplications as [Curve25519].
|
||||||
var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t FieldElement
|
var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t FieldElement
|
||||||
|
|
||||||
FeSquare(&z2, z) // 2
|
z2.Square(z) // 2
|
||||||
FeSquare(&t, &z2) // 4
|
t.Square(&z2) // 4
|
||||||
FeSquare(&t, &t) // 8
|
t.Square(&t) // 8
|
||||||
FeMul(&z9, &t, z) // 9
|
z9.Mul(&t, z) // 9
|
||||||
FeMul(&z11, &z9, &z2) // 11
|
z11.Mul(&z9, &z2) // 11
|
||||||
FeSquare(&t, &z11) // 22
|
t.Square(&z11) // 22
|
||||||
FeMul(&z2_5_0, &t, &z9) // 2^5 - 2^0 = 31
|
z2_5_0.Mul(&t, &z9) // 2^5 - 2^0 = 31
|
||||||
|
|
||||||
FeSquare(&t, &z2_5_0) // 2^6 - 2^1
|
t.Square(&z2_5_0) // 2^6 - 2^1
|
||||||
for i := 0; i < 4; i++ {
|
for i := 0; i < 4; i++ {
|
||||||
FeSquare(&t, &t) // 2^10 - 2^5
|
t.Square(&t) // 2^10 - 2^5
|
||||||
}
|
}
|
||||||
FeMul(&z2_10_0, &t, &z2_5_0) // 2^10 - 2^0
|
z2_10_0.Mul(&t, &z2_5_0) // 2^10 - 2^0
|
||||||
|
|
||||||
FeSquare(&t, &z2_10_0) // 2^11 - 2^1
|
t.Square(&z2_10_0) // 2^11 - 2^1
|
||||||
for i := 0; i < 9; i++ {
|
for i := 0; i < 9; i++ {
|
||||||
FeSquare(&t, &t) // 2^20 - 2^10
|
t.Square(&t) // 2^20 - 2^10
|
||||||
}
|
}
|
||||||
FeMul(&z2_20_0, &t, &z2_10_0) // 2^20 - 2^0
|
z2_20_0.Mul(&t, &z2_10_0) // 2^20 - 2^0
|
||||||
|
|
||||||
FeSquare(&t, &z2_20_0) // 2^21 - 2^1
|
t.Square(&z2_20_0) // 2^21 - 2^1
|
||||||
for i := 0; i < 19; i++ {
|
for i := 0; i < 19; i++ {
|
||||||
FeSquare(&t, &t) // 2^40 - 2^20
|
t.Square(&t) // 2^40 - 2^20
|
||||||
}
|
}
|
||||||
FeMul(&t, &t, &z2_20_0) // 2^40 - 2^0
|
t.Mul(&t, &z2_20_0) // 2^40 - 2^0
|
||||||
|
|
||||||
FeSquare(&t, &t) // 2^41 - 2^1
|
t.Square(&t) // 2^41 - 2^1
|
||||||
for i := 0; i < 9; i++ {
|
for i := 0; i < 9; i++ {
|
||||||
FeSquare(&t, &t) // 2^50 - 2^10
|
t.Square(&t) // 2^50 - 2^10
|
||||||
}
|
}
|
||||||
FeMul(&z2_50_0, &t, &z2_10_0) // 2^50 - 2^0
|
z2_50_0.Mul(&t, &z2_10_0) // 2^50 - 2^0
|
||||||
|
|
||||||
FeSquare(&t, &z2_50_0) // 2^51 - 2^1
|
t.Square(&z2_50_0) // 2^51 - 2^1
|
||||||
for i := 0; i < 49; i++ {
|
for i := 0; i < 49; i++ {
|
||||||
FeSquare(&t, &t) // 2^100 - 2^50
|
t.Square(&t) // 2^100 - 2^50
|
||||||
}
|
}
|
||||||
FeMul(&z2_100_0, &t, &z2_50_0) // 2^100 - 2^0
|
z2_100_0.Mul(&t, &z2_50_0) // 2^100 - 2^0
|
||||||
|
|
||||||
FeSquare(&t, &z2_100_0) // 2^101 - 2^1
|
t.Square(&z2_100_0) // 2^101 - 2^1
|
||||||
for i := 0; i < 99; i++ {
|
for i := 0; i < 99; i++ {
|
||||||
FeSquare(&t, &t) // 2^200 - 2^100
|
t.Square(&t) // 2^200 - 2^100
|
||||||
}
|
}
|
||||||
FeMul(&t, &t, &z2_100_0) // 2^200 - 2^0
|
t.Mul(&t, &z2_100_0) // 2^200 - 2^0
|
||||||
|
|
||||||
FeSquare(&t, &t) // 2^201 - 2^1
|
t.Square(&t) // 2^201 - 2^1
|
||||||
for i := 0; i < 49; i++ {
|
for i := 0; i < 49; i++ {
|
||||||
FeSquare(&t, &t) // 2^250 - 2^50
|
t.Square(&t) // 2^250 - 2^50
|
||||||
}
|
}
|
||||||
FeMul(&t, &t, &z2_50_0) // 2^250 - 2^0
|
t.Mul(&t, &z2_50_0) // 2^250 - 2^0
|
||||||
|
|
||||||
FeSquare(&t, &t) // 2^251 - 2^1
|
t.Square(&t) // 2^251 - 2^1
|
||||||
FeSquare(&t, &t) // 2^252 - 2^2
|
t.Square(&t) // 2^252 - 2^2
|
||||||
FeSquare(&t, &t) // 2^253 - 2^3
|
t.Square(&t) // 2^253 - 2^3
|
||||||
FeSquare(&t, &t) // 2^254 - 2^4
|
t.Square(&t) // 2^254 - 2^4
|
||||||
FeSquare(&t, &t) // 2^255 - 2^5
|
t.Square(&t) // 2^255 - 2^5
|
||||||
|
|
||||||
FeMul(out, &t, &z11) // 2^255 - 21
|
return v.Mul(&t, &z11) // 2^255 - 21
|
||||||
}
|
}
|
||||||
|
|
||||||
func FeCopy(out, in *FieldElement) {
|
func (v *FieldElement) Set(a *FieldElement) *FieldElement {
|
||||||
copy(out[:], in[:])
|
*v = *a
|
||||||
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func FeFromBytes(v *FieldElement, x *[32]byte) {
|
func (v *FieldElement) FromBytes(x *[32]byte) *FieldElement {
|
||||||
v[0] = uint64(x[0])
|
v[0] = uint64(x[0])
|
||||||
v[0] |= uint64(x[1]) << 8
|
v[0] |= uint64(x[1]) << 8
|
||||||
v[0] |= uint64(x[2]) << 16
|
v[0] |= uint64(x[2]) << 16
|
||||||
|
@ -239,11 +256,12 @@ func FeFromBytes(v *FieldElement, x *[32]byte) {
|
||||||
v[4] |= uint64(x[29]) << 28
|
v[4] |= uint64(x[29]) << 28
|
||||||
v[4] |= uint64(x[30]) << 36
|
v[4] |= uint64(x[30]) << 36
|
||||||
v[4] |= uint64(x[31]&127) << 44
|
v[4] |= uint64(x[31]&127) << 44
|
||||||
|
|
||||||
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func FeToBytes(r *[32]byte, v *FieldElement) {
|
func (v *FieldElement) ToBytes(r *[32]byte) {
|
||||||
var t FieldElement
|
t := new(FieldElement).Reduce(v)
|
||||||
FeReduce(&t, v)
|
|
||||||
|
|
||||||
r[0] = byte(t[0] & 0xff)
|
r[0] = byte(t[0] & 0xff)
|
||||||
r[1] = byte((t[0] >> 8) & 0xff)
|
r[1] = byte((t[0] >> 8) & 0xff)
|
||||||
|
@ -287,7 +305,7 @@ func FeToBytes(r *[32]byte, v *FieldElement) {
|
||||||
r[31] = byte((t[4] >> 44))
|
r[31] = byte((t[4] >> 44))
|
||||||
}
|
}
|
||||||
|
|
||||||
func FeFromBig(h *FieldElement, num *big.Int) {
|
func (v *FieldElement) FromBig(num *big.Int) *FieldElement {
|
||||||
var buf [32]byte
|
var buf [32]byte
|
||||||
|
|
||||||
offset := 0
|
offset := 0
|
||||||
|
@ -305,12 +323,12 @@ func FeFromBig(h *FieldElement, num *big.Int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FeFromBytes(h, &buf)
|
return v.FromBytes(&buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
func FeToBig(h *FieldElement) *big.Int {
|
func (v *FieldElement) ToBig() *big.Int {
|
||||||
var buf [32]byte
|
var buf [32]byte
|
||||||
FeToBytes(&buf, h) // does a reduction
|
v.ToBytes(&buf) // does a reduction
|
||||||
|
|
||||||
numWords := 256 / bits.UintSize
|
numWords := 256 / bits.UintSize
|
||||||
words := make([]big.Word, numWords)
|
words := make([]big.Word, numWords)
|
||||||
|
@ -333,48 +351,39 @@ func FeToBig(h *FieldElement) *big.Int {
|
||||||
return out.SetBits(words)
|
return out.SetBits(words)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FeEqual returns 1 if a and b are equal, and 0 otherwise.
|
// Equal returns 1 if v and u are equal, and 0 otherwise.
|
||||||
func FeEqual(a, b *FieldElement) int {
|
func (v *FieldElement) Equal(u *FieldElement) int {
|
||||||
var sa, sb [32]byte
|
var sa, sv [32]byte
|
||||||
FeToBytes(&sa, a)
|
u.ToBytes(&sa)
|
||||||
FeToBytes(&sb, b)
|
v.ToBytes(&sv)
|
||||||
return subtle.ConstantTimeCompare(sa[:], sb[:])
|
return subtle.ConstantTimeCompare(sa[:], sv[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
// FeSelect sets out to v if cond == 1, and to u if cond == 0.
|
// Select sets v to a if cond == 1, and to b if cond == 0.
|
||||||
// out, v and u are allowed to overlap.
|
// v, a and b are allowed to overlap.
|
||||||
func FeSelect(out, v, u *FieldElement, cond int) {
|
func (v *FieldElement) Select(a, b *FieldElement, cond int) *FieldElement {
|
||||||
b := uint64(cond) * 0xffffffffffffffff
|
m := uint64(cond) * 0xffffffffffffffff
|
||||||
out[0] = (b & v[0]) | (^b & u[0])
|
v[0] = (m & a[0]) | (^m & b[0])
|
||||||
out[1] = (b & v[1]) | (^b & u[1])
|
v[1] = (m & a[1]) | (^m & b[1])
|
||||||
out[2] = (b & v[2]) | (^b & u[2])
|
v[2] = (m & a[2]) | (^m & b[2])
|
||||||
out[3] = (b & v[3]) | (^b & u[3])
|
v[3] = (m & a[3]) | (^m & b[3])
|
||||||
out[4] = (b & v[4]) | (^b & u[4])
|
v[4] = (m & a[4]) | (^m & b[4])
|
||||||
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// FeCondNeg sets u 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.
|
||||||
func FeCondNeg(u *FieldElement, cond int) {
|
func (v *FieldElement) CondNeg(u *FieldElement, cond int) *FieldElement {
|
||||||
var neg FieldElement
|
return v.Select(v.Neg(u), u, cond)
|
||||||
FeNeg(&neg, u)
|
|
||||||
|
|
||||||
b := uint64(cond) * 0xffffffffffffffff
|
|
||||||
u[0] ^= b & (u[0] ^ neg[0])
|
|
||||||
u[1] ^= b & (u[1] ^ neg[1])
|
|
||||||
u[2] ^= b & (u[2] ^ neg[2])
|
|
||||||
u[3] ^= b & (u[3] ^ neg[3])
|
|
||||||
u[4] ^= b & (u[4] ^ neg[4])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// FeIsNegative returns 1 if u is negative, and 0 otherwise.
|
// IsNegative returns 1 if v is negative, and 0 otherwise.
|
||||||
func FeIsNegative(u *FieldElement) int {
|
func (v *FieldElement) IsNegative() int {
|
||||||
var b [32]byte
|
var b [32]byte
|
||||||
FeToBytes(&b, u)
|
v.ToBytes(&b)
|
||||||
return int(b[0] & 1)
|
return int(b[0] & 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FeAbs sets out to |u|. out and u are allowed to overlap.
|
// Abs sets v to |u|. v and u are allowed to overlap.
|
||||||
func FeAbs(out, u *FieldElement) {
|
func (v *FieldElement) Abs(u *FieldElement) *FieldElement {
|
||||||
var neg FieldElement
|
return v.CondNeg(u, u.IsNegative())
|
||||||
FeNeg(&neg, u)
|
|
||||||
FeSelect(out, &neg, u, FeIsNegative(u))
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
|
|
||||||
package radix51
|
package radix51
|
||||||
|
|
||||||
// FeMul sets out = a * b
|
// Mul sets out = x * y.
|
||||||
func FeMul(out, x, y *FieldElement) {
|
func (v *FieldElement) Mul(x, y *FieldElement) *FieldElement {
|
||||||
var x0, x1, x2, x3, x4 uint64
|
var x0, x1, x2, x3, x4 uint64
|
||||||
var y0, y1, y2, y3, y4 uint64
|
var y0, y1, y2, y3, y4 uint64
|
||||||
|
|
||||||
|
@ -118,9 +118,10 @@ func FeMul(out, x, y *FieldElement) {
|
||||||
r00 += (r40 >> 51) * 19
|
r00 += (r40 >> 51) * 19
|
||||||
r40 &= maskLow51Bits
|
r40 &= maskLow51Bits
|
||||||
|
|
||||||
out[0] = r00
|
v[0] = r00
|
||||||
out[1] = r10
|
v[1] = r10
|
||||||
out[2] = r20
|
v[2] = r20
|
||||||
out[3] = r30
|
v[3] = r30
|
||||||
out[4] = r40
|
v[4] = r40
|
||||||
|
return v
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,5 +6,11 @@
|
||||||
|
|
||||||
package radix51
|
package radix51
|
||||||
|
|
||||||
|
// Mul sets out = x * y.
|
||||||
|
func (v *FieldElement) Mul(x, y *FieldElement) *FieldElement {
|
||||||
|
feMul(v, x, y)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
// go:noescape
|
// go:noescape
|
||||||
func FeMul(out, a, b *FieldElement)
|
func feMul(out, a, b *FieldElement)
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
|
|
||||||
// +build amd64,!noasm
|
// +build amd64,!noasm
|
||||||
|
|
||||||
// func FeMul(outp *uint64, xp *uint64, yp *uint64)
|
// func feMul(outp *uint64, xp *uint64, yp *uint64)
|
||||||
TEXT ·FeMul(SB),$0-24
|
TEXT ·feMul(SB),$0-24
|
||||||
MOVQ outp+0(FP), DI
|
MOVQ outp+0(FP), DI
|
||||||
MOVQ xp+8(FP), BX
|
MOVQ xp+8(FP), BX
|
||||||
MOVQ yp+16(FP), CX
|
MOVQ yp+16(FP), CX
|
||||||
|
|
|
@ -6,8 +6,8 @@
|
||||||
|
|
||||||
package radix51
|
package radix51
|
||||||
|
|
||||||
// FeSquare sets out = x*x
|
// Square sets v = x * x.
|
||||||
func FeSquare(out, x *FieldElement) {
|
func (v *FieldElement) Square(x *FieldElement) *FieldElement {
|
||||||
// Squaring needs only 15 mul instructions. Some inputs are multiplied by 2;
|
// Squaring needs only 15 mul instructions. Some inputs are multiplied by 2;
|
||||||
// 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.
|
||||||
|
@ -90,9 +90,10 @@ func FeSquare(out, x *FieldElement) {
|
||||||
r00 += (r40 >> 51) * 19
|
r00 += (r40 >> 51) * 19
|
||||||
r40 &= maskLow51Bits
|
r40 &= maskLow51Bits
|
||||||
|
|
||||||
out[0] = r00
|
v[0] = r00
|
||||||
out[1] = r10
|
v[1] = r10
|
||||||
out[2] = r20
|
v[2] = r20
|
||||||
out[3] = r30
|
v[3] = r30
|
||||||
out[4] = r40
|
v[4] = r40
|
||||||
|
return v
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,5 +6,11 @@
|
||||||
|
|
||||||
package radix51
|
package radix51
|
||||||
|
|
||||||
|
// Square sets v = x * x.
|
||||||
|
func (v *FieldElement) Square(x *FieldElement) *FieldElement {
|
||||||
|
feSquare(v, x)
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
|
||||||
// go:noescape
|
// go:noescape
|
||||||
func FeSquare(out, x *FieldElement)
|
func feSquare(out, x *FieldElement)
|
||||||
|
|
|
@ -4,8 +4,8 @@
|
||||||
|
|
||||||
// +build amd64,!noasm
|
// +build amd64,!noasm
|
||||||
|
|
||||||
// func FeSquare(outp *uint64, xp *uint64)
|
// func feSquare(outp *uint64, xp *uint64)
|
||||||
TEXT ·FeSquare(SB),4,$0-16
|
TEXT ·feSquare(SB),4,$0-16
|
||||||
MOVQ outp+0(FP), DI
|
MOVQ outp+0(FP), DI
|
||||||
MOVQ xp+8(FP), SI
|
MOVQ xp+8(FP), SI
|
||||||
|
|
||||||
|
|
|
@ -73,8 +73,8 @@ func TestFeFromBytesRoundTrip(t *testing.T) {
|
||||||
in = [32]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
|
in = [32]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
|
||||||
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}
|
18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32}
|
||||||
|
|
||||||
FeFromBytes(&fe, &in)
|
fe.FromBytes(&in)
|
||||||
FeToBytes(&out, &fe)
|
fe.ToBytes(&out)
|
||||||
|
|
||||||
if !bytes.Equal(in[:], out[:]) {
|
if !bytes.Equal(in[:], out[:]) {
|
||||||
t.Error("Bytes<>FE doesn't roundtrip")
|
t.Error("Bytes<>FE doesn't roundtrip")
|
||||||
|
@ -87,8 +87,8 @@ func TestFeFromBytesRoundTrip(t *testing.T) {
|
||||||
fe[3] = 0x5e8fca9e0881c
|
fe[3] = 0x5e8fca9e0881c
|
||||||
fe[4] = 0x5c490f087d796
|
fe[4] = 0x5c490f087d796
|
||||||
|
|
||||||
FeToBytes(&out, &fe)
|
fe.ToBytes(&out)
|
||||||
FeFromBytes(&r, &out)
|
r.FromBytes(&out)
|
||||||
|
|
||||||
for i := 0; i < len(fe); i++ {
|
for i := 0; i < len(fe); i++ {
|
||||||
if r[i] != fe[i] {
|
if r[i] != fe[i] {
|
||||||
|
@ -104,9 +104,9 @@ func TestSanity(t *testing.T) {
|
||||||
// var x2Go, x2sqGo FieldElement
|
// var x2Go, x2sqGo FieldElement
|
||||||
|
|
||||||
x = [5]uint64{1, 1, 1, 1, 1}
|
x = [5]uint64{1, 1, 1, 1, 1}
|
||||||
FeMul(&x2, &x, &x)
|
x2.Mul(&x, &x)
|
||||||
// FeMulGo(&x2Go, &x, &x)
|
// FeMulGo(&x2Go, &x, &x)
|
||||||
FeSquare(&x2sq, &x)
|
x2sq.Square(&x)
|
||||||
// FeSquareGo(&x2sqGo, &x)
|
// FeSquareGo(&x2sqGo, &x)
|
||||||
|
|
||||||
// if !vartimeEqual(x2, x2Go) || !vartimeEqual(x2sq, x2sqGo) || !vartimeEqual(x2, x2sq) {
|
// if !vartimeEqual(x2, x2Go) || !vartimeEqual(x2sq, x2sqGo) || !vartimeEqual(x2, x2sq) {
|
||||||
|
@ -123,11 +123,11 @@ func TestSanity(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
FeFromBytes(&x, &bytes)
|
x.FromBytes(&bytes)
|
||||||
|
|
||||||
FeMul(&x2, &x, &x)
|
x2.Mul(&x, &x)
|
||||||
// FeMulGo(&x2Go, &x, &x)
|
// FeMulGo(&x2Go, &x, &x)
|
||||||
FeSquare(&x2sq, &x)
|
x2sq.Square(&x)
|
||||||
// FeSquareGo(&x2sqGo, &x)
|
// FeSquareGo(&x2sqGo, &x)
|
||||||
|
|
||||||
// if !vartimeEqual(x2, x2Go) || !vartimeEqual(x2sq, x2sqGo) || !vartimeEqual(x2, x2sq) {
|
// if !vartimeEqual(x2, x2Go) || !vartimeEqual(x2sq, x2sqGo) || !vartimeEqual(x2, x2sq) {
|
||||||
|
@ -152,13 +152,13 @@ func TestFeEqual(t *testing.T) {
|
||||||
var x FieldElement = [5]uint64{1, 1, 1, 1, 1}
|
var x FieldElement = [5]uint64{1, 1, 1, 1, 1}
|
||||||
var y FieldElement = [5]uint64{5, 4, 3, 2, 1}
|
var y FieldElement = [5]uint64{5, 4, 3, 2, 1}
|
||||||
|
|
||||||
eq := FeEqual(&x, &x)
|
eq := x.Equal(&x)
|
||||||
if !eq {
|
if eq != 1 {
|
||||||
t.Errorf("wrong about equality")
|
t.Errorf("wrong about equality")
|
||||||
}
|
}
|
||||||
|
|
||||||
eq = FeEqual(&x, &y)
|
eq = x.Equal(&y)
|
||||||
if eq {
|
if eq != 0 {
|
||||||
t.Errorf("wrong about inequality")
|
t.Errorf("wrong about inequality")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,9 +168,9 @@ func TestFeInvert(t *testing.T) {
|
||||||
var one FieldElement = [5]uint64{1, 0, 0, 0, 0}
|
var one FieldElement = [5]uint64{1, 0, 0, 0, 0}
|
||||||
var xinv, r FieldElement
|
var xinv, r FieldElement
|
||||||
|
|
||||||
FeInvert(&xinv, &x)
|
xinv.Invert(&x)
|
||||||
FeMul(&r, &x, &xinv)
|
r.Mul(&x, &xinv)
|
||||||
FeReduce(&r, &r)
|
r.Reduce(&r)
|
||||||
|
|
||||||
if !vartimeEqual(one, r) {
|
if !vartimeEqual(one, r) {
|
||||||
t.Errorf("inversion identity failed, got: %x", r)
|
t.Errorf("inversion identity failed, got: %x", r)
|
||||||
|
@ -182,11 +182,11 @@ func TestFeInvert(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
FeFromBytes(&x, &bytes)
|
x.FromBytes(&bytes)
|
||||||
|
|
||||||
FeInvert(&xinv, &x)
|
xinv.Invert(&x)
|
||||||
FeMul(&r, &x, &xinv)
|
r.Mul(&x, &xinv)
|
||||||
FeReduce(&r, &r)
|
r.Reduce(&r)
|
||||||
|
|
||||||
if !vartimeEqual(one, r) {
|
if !vartimeEqual(one, r) {
|
||||||
t.Errorf("random inversion identity failed, got: %x for field element %x", r, x)
|
t.Errorf("random inversion identity failed, got: %x for field element %x", r, x)
|
||||||
|
|
|
@ -35,13 +35,13 @@ type Element struct {
|
||||||
func (e *Element) Equal(ee *Element) int {
|
func (e *Element) Equal(ee *Element) int {
|
||||||
var f0, f1 radix51.FieldElement
|
var f0, f1 radix51.FieldElement
|
||||||
|
|
||||||
radix51.FeMul(&f0, &e.r.X, &ee.r.Y) // x1 * y2
|
f0.Mul(&e.r.X, &ee.r.Y) // x1 * y2
|
||||||
radix51.FeMul(&f1, &e.r.Y, &ee.r.X) // y1 * x2
|
f1.Mul(&e.r.Y, &ee.r.X) // y1 * x2
|
||||||
out := radix51.FeEqual(&f0, &f1)
|
out := f0.Equal(&f1)
|
||||||
|
|
||||||
radix51.FeMul(&f0, &e.r.Y, &ee.r.Y) // y1 * y2
|
f0.Mul(&e.r.Y, &ee.r.Y) // y1 * y2
|
||||||
radix51.FeMul(&f1, &e.r.X, &ee.r.X) // x1 * x2
|
f1.Mul(&e.r.X, &ee.r.X) // x1 * x2
|
||||||
out = out | radix51.FeEqual(&f0, &f1)
|
out = out | f0.Equal(&f1)
|
||||||
|
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
@ -58,71 +58,75 @@ func (e *Element) FromUniformBytes(b []byte) {
|
||||||
f := &radix51.FieldElement{}
|
f := &radix51.FieldElement{}
|
||||||
|
|
||||||
copy(buf[:], b[:32])
|
copy(buf[:], b[:32])
|
||||||
radix51.FeFromBytes(f, &buf)
|
f.FromBytes(&buf)
|
||||||
p1 := &group.ExtendedGroupElement{}
|
p1 := &group.ExtendedGroupElement{}
|
||||||
mapToPoint(p1, f)
|
mapToPoint(p1, f)
|
||||||
|
|
||||||
copy(buf[:], b[32:])
|
copy(buf[:], b[32:])
|
||||||
radix51.FeFromBytes(f, &buf)
|
f.FromBytes(&buf)
|
||||||
p2 := &group.ExtendedGroupElement{}
|
p2 := &group.ExtendedGroupElement{}
|
||||||
mapToPoint(p2, f)
|
mapToPoint(p2, f)
|
||||||
|
|
||||||
e.r.Add(p1, p2)
|
e.r.Add(p1, p2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// mapToPoint implements MAP from Section 3.2.4 of draft-hdevalence-cfrg-ristretto-00.
|
||||||
func mapToPoint(out *group.ExtendedGroupElement, t *radix51.FieldElement) {
|
func mapToPoint(out *group.ExtendedGroupElement, t *radix51.FieldElement) {
|
||||||
|
// r = SQRT_M1 * t^2
|
||||||
r := &radix51.FieldElement{}
|
r := &radix51.FieldElement{}
|
||||||
radix51.FeSquare(r, t)
|
r.Mul(sqrtM1, r.Square(t))
|
||||||
radix51.FeMul(r, r, sqrtM1)
|
|
||||||
|
|
||||||
one := &radix51.FieldElement{}
|
|
||||||
radix51.FeOne(one)
|
|
||||||
minusOne := &radix51.FieldElement{}
|
|
||||||
radix51.FeNeg(minusOne, one)
|
|
||||||
|
|
||||||
|
// u = (r + 1) * ONE_MINUS_D_SQ
|
||||||
u := &radix51.FieldElement{}
|
u := &radix51.FieldElement{}
|
||||||
radix51.FeAdd(u, r, one)
|
u.Mul(u.Add(r, radix51.One), oneMinusDSQ)
|
||||||
radix51.FeMul(u, u, oneMinusDSQ)
|
|
||||||
|
|
||||||
|
// c = -1
|
||||||
|
c := &radix51.FieldElement{}
|
||||||
|
c.Set(radix51.MinusOne)
|
||||||
|
|
||||||
|
// v = (c - r*D) * (r + D)
|
||||||
rPlusD := &radix51.FieldElement{}
|
rPlusD := &radix51.FieldElement{}
|
||||||
radix51.FeAdd(rPlusD, r, &group.D)
|
rPlusD.Add(r, group.D)
|
||||||
v := &radix51.FieldElement{}
|
v := &radix51.FieldElement{}
|
||||||
radix51.FeMul(v, r, &group.D)
|
v.Mul(v.Sub(c, v.Mul(r, group.D)), rPlusD)
|
||||||
radix51.FeSub(v, minusOne, v)
|
|
||||||
radix51.FeMul(v, v, rPlusD)
|
|
||||||
|
|
||||||
|
// (was_square, s) = SQRT_RATIO_M1(u, v)
|
||||||
s := &radix51.FieldElement{}
|
s := &radix51.FieldElement{}
|
||||||
wasSquare := feSqrtRatio(s, u, v)
|
wasSquare := feSqrtRatio(s, u, v)
|
||||||
|
|
||||||
|
// s_prime = -CT_ABS(s*t)
|
||||||
sPrime := &radix51.FieldElement{}
|
sPrime := &radix51.FieldElement{}
|
||||||
radix51.FeMul(sPrime, s, t)
|
sPrime.Neg(sPrime.Abs(sPrime.Mul(s, t)))
|
||||||
radix51.FeAbs(sPrime, sPrime)
|
|
||||||
radix51.FeNeg(sPrime, sPrime)
|
|
||||||
|
|
||||||
c := &radix51.FieldElement{}
|
// s = CT_SELECT(s IF was_square ELSE s_prime)
|
||||||
radix51.FeSelect(s, s, sPrime, wasSquare)
|
s.Select(s, sPrime, wasSquare)
|
||||||
radix51.FeSelect(c, minusOne, r, wasSquare)
|
// c = CT_SELECT(c IF was_square ELSE r)
|
||||||
|
c.Select(c, r, wasSquare)
|
||||||
|
|
||||||
|
// N = c * (r - 1) * D_MINUS_ONE_SQ - v
|
||||||
N := &radix51.FieldElement{}
|
N := &radix51.FieldElement{}
|
||||||
radix51.FeSub(N, r, one)
|
N.Mul(c, N.Sub(r, radix51.One))
|
||||||
radix51.FeMul(N, N, c)
|
N.Sub(N.Mul(N, dMinusOneSQ), v)
|
||||||
radix51.FeMul(N, N, dMinusOneSQ)
|
|
||||||
radix51.FeSub(N, N, v)
|
|
||||||
|
|
||||||
sSquare := &radix51.FieldElement{}
|
s2 := &radix51.FieldElement{}
|
||||||
radix51.FeSquare(sSquare, s)
|
s2.Square(s)
|
||||||
|
|
||||||
|
// w0 = 2 * s * v
|
||||||
w0 := &radix51.FieldElement{}
|
w0 := &radix51.FieldElement{}
|
||||||
radix51.FeMul(w0, s, v)
|
w0.Add(w0, w0.Mul(s, v))
|
||||||
radix51.FeAdd(w0, w0, w0)
|
// w1 = N * SQRT_AD_MINUS_ONE
|
||||||
w1 := &radix51.FieldElement{}
|
w1 := &radix51.FieldElement{}
|
||||||
radix51.FeMul(w1, N, sqrtADMinusOne)
|
w1.Mul(N, sqrtADMinusOne)
|
||||||
|
// w2 = 1 - s^2
|
||||||
w2 := &radix51.FieldElement{}
|
w2 := &radix51.FieldElement{}
|
||||||
radix51.FeSub(w2, one, sSquare)
|
w2.Sub(radix51.One, s2)
|
||||||
|
// w3 = 1 + s^2
|
||||||
w3 := &radix51.FieldElement{}
|
w3 := &radix51.FieldElement{}
|
||||||
radix51.FeAdd(w3, one, sSquare)
|
w3.Add(radix51.One, s2)
|
||||||
|
|
||||||
radix51.FeMul(&out.X, w0, w3)
|
// return (w0*w3, w2*w1, w1*w3, w0*w2)
|
||||||
radix51.FeMul(&out.Y, w2, w1)
|
out.X.Mul(w0, w3)
|
||||||
radix51.FeMul(&out.Z, w1, w3)
|
out.Y.Mul(w2, w1)
|
||||||
radix51.FeMul(&out.T, w0, w2)
|
out.Z.Mul(w1, w3)
|
||||||
|
out.T.Mul(w0, w2)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue