206 lines
4.4 KiB
Go
206 lines
4.4 KiB
Go
|
// Package fp25519 provides prime field arithmetic over GF(2^255-19).
|
||
|
package fp25519
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
|
||
|
"github.com/cloudflare/circl/internal/conv"
|
||
|
)
|
||
|
|
||
|
// Size in bytes of an element.
|
||
|
const Size = 32
|
||
|
|
||
|
// Elt is a prime field element.
|
||
|
type Elt [Size]byte
|
||
|
|
||
|
func (e Elt) String() string { return conv.BytesLe2Hex(e[:]) }
|
||
|
|
||
|
// p is the prime modulus 2^255-19.
|
||
|
var p = Elt{
|
||
|
0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||
|
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f,
|
||
|
}
|
||
|
|
||
|
// P returns the prime modulus 2^255-19.
|
||
|
func P() Elt { return p }
|
||
|
|
||
|
// ToBytes stores in b the little-endian byte representation of x.
|
||
|
func ToBytes(b []byte, x *Elt) error {
|
||
|
if len(b) != Size {
|
||
|
return errors.New("wrong size")
|
||
|
}
|
||
|
Modp(x)
|
||
|
copy(b, x[:])
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// IsZero returns true if x is equal to 0.
|
||
|
func IsZero(x *Elt) bool { Modp(x); return *x == Elt{} }
|
||
|
|
||
|
// SetOne assigns x=1.
|
||
|
func SetOne(x *Elt) { *x = Elt{}; x[0] = 1 }
|
||
|
|
||
|
// Neg calculates z = -x.
|
||
|
func Neg(z, x *Elt) { Sub(z, &p, x) }
|
||
|
|
||
|
// InvSqrt calculates z = sqrt(x/y) iff x/y is a quadratic-residue, which is
|
||
|
// indicated by returning isQR = true. Otherwise, when x/y is a quadratic
|
||
|
// non-residue, z will have an undetermined value and isQR = false.
|
||
|
func InvSqrt(z, x, y *Elt) (isQR bool) {
|
||
|
sqrtMinusOne := &Elt{
|
||
|
0xb0, 0xa0, 0x0e, 0x4a, 0x27, 0x1b, 0xee, 0xc4,
|
||
|
0x78, 0xe4, 0x2f, 0xad, 0x06, 0x18, 0x43, 0x2f,
|
||
|
0xa7, 0xd7, 0xfb, 0x3d, 0x99, 0x00, 0x4d, 0x2b,
|
||
|
0x0b, 0xdf, 0xc1, 0x4f, 0x80, 0x24, 0x83, 0x2b,
|
||
|
}
|
||
|
t0, t1, t2, t3 := &Elt{}, &Elt{}, &Elt{}, &Elt{}
|
||
|
|
||
|
Mul(t0, x, y) // t0 = u*v
|
||
|
Sqr(t1, y) // t1 = v^2
|
||
|
Mul(t2, t0, t1) // t2 = u*v^3
|
||
|
Sqr(t0, t1) // t0 = v^4
|
||
|
Mul(t1, t0, t2) // t1 = u*v^7
|
||
|
|
||
|
var Tab [4]*Elt
|
||
|
Tab[0] = &Elt{}
|
||
|
Tab[1] = &Elt{}
|
||
|
Tab[2] = t3
|
||
|
Tab[3] = t1
|
||
|
|
||
|
*Tab[0] = *t1
|
||
|
Sqr(Tab[0], Tab[0])
|
||
|
Sqr(Tab[1], Tab[0])
|
||
|
Sqr(Tab[1], Tab[1])
|
||
|
Mul(Tab[1], Tab[1], Tab[3])
|
||
|
Mul(Tab[0], Tab[0], Tab[1])
|
||
|
Sqr(Tab[0], Tab[0])
|
||
|
Mul(Tab[0], Tab[0], Tab[1])
|
||
|
Sqr(Tab[1], Tab[0])
|
||
|
for i := 0; i < 4; i++ {
|
||
|
Sqr(Tab[1], Tab[1])
|
||
|
}
|
||
|
Mul(Tab[1], Tab[1], Tab[0])
|
||
|
Sqr(Tab[2], Tab[1])
|
||
|
for i := 0; i < 4; i++ {
|
||
|
Sqr(Tab[2], Tab[2])
|
||
|
}
|
||
|
Mul(Tab[2], Tab[2], Tab[0])
|
||
|
Sqr(Tab[1], Tab[2])
|
||
|
for i := 0; i < 14; i++ {
|
||
|
Sqr(Tab[1], Tab[1])
|
||
|
}
|
||
|
Mul(Tab[1], Tab[1], Tab[2])
|
||
|
Sqr(Tab[2], Tab[1])
|
||
|
for i := 0; i < 29; i++ {
|
||
|
Sqr(Tab[2], Tab[2])
|
||
|
}
|
||
|
Mul(Tab[2], Tab[2], Tab[1])
|
||
|
Sqr(Tab[1], Tab[2])
|
||
|
for i := 0; i < 59; i++ {
|
||
|
Sqr(Tab[1], Tab[1])
|
||
|
}
|
||
|
Mul(Tab[1], Tab[1], Tab[2])
|
||
|
for i := 0; i < 5; i++ {
|
||
|
Sqr(Tab[1], Tab[1])
|
||
|
}
|
||
|
Mul(Tab[1], Tab[1], Tab[0])
|
||
|
Sqr(Tab[2], Tab[1])
|
||
|
for i := 0; i < 124; i++ {
|
||
|
Sqr(Tab[2], Tab[2])
|
||
|
}
|
||
|
Mul(Tab[2], Tab[2], Tab[1])
|
||
|
Sqr(Tab[2], Tab[2])
|
||
|
Sqr(Tab[2], Tab[2])
|
||
|
Mul(Tab[2], Tab[2], Tab[3])
|
||
|
|
||
|
Mul(z, t3, t2) // z = xy^(p+3)/8 = xy^3*(xy^7)^(p-5)/8
|
||
|
// Checking whether y z^2 == x
|
||
|
Sqr(t0, z) // t0 = z^2
|
||
|
Mul(t0, t0, y) // t0 = yz^2
|
||
|
Sub(t1, t0, x) // t1 = t0-u
|
||
|
Add(t2, t0, x) // t2 = t0+u
|
||
|
if IsZero(t1) {
|
||
|
return true
|
||
|
} else if IsZero(t2) {
|
||
|
Mul(z, z, sqrtMinusOne) // z = z*sqrt(-1)
|
||
|
return true
|
||
|
} else {
|
||
|
return false
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Inv calculates z = 1/x mod p.
|
||
|
func Inv(z, x *Elt) {
|
||
|
x0, x1, x2 := &Elt{}, &Elt{}, &Elt{}
|
||
|
Sqr(x1, x)
|
||
|
Sqr(x0, x1)
|
||
|
Sqr(x0, x0)
|
||
|
Mul(x0, x0, x)
|
||
|
Mul(z, x0, x1)
|
||
|
Sqr(x1, z)
|
||
|
Mul(x0, x0, x1)
|
||
|
Sqr(x1, x0)
|
||
|
for i := 0; i < 4; i++ {
|
||
|
Sqr(x1, x1)
|
||
|
}
|
||
|
Mul(x0, x0, x1)
|
||
|
Sqr(x1, x0)
|
||
|
for i := 0; i < 9; i++ {
|
||
|
Sqr(x1, x1)
|
||
|
}
|
||
|
Mul(x1, x1, x0)
|
||
|
Sqr(x2, x1)
|
||
|
for i := 0; i < 19; i++ {
|
||
|
Sqr(x2, x2)
|
||
|
}
|
||
|
Mul(x2, x2, x1)
|
||
|
for i := 0; i < 10; i++ {
|
||
|
Sqr(x2, x2)
|
||
|
}
|
||
|
Mul(x2, x2, x0)
|
||
|
Sqr(x0, x2)
|
||
|
for i := 0; i < 49; i++ {
|
||
|
Sqr(x0, x0)
|
||
|
}
|
||
|
Mul(x0, x0, x2)
|
||
|
Sqr(x1, x0)
|
||
|
for i := 0; i < 99; i++ {
|
||
|
Sqr(x1, x1)
|
||
|
}
|
||
|
Mul(x1, x1, x0)
|
||
|
for i := 0; i < 50; i++ {
|
||
|
Sqr(x1, x1)
|
||
|
}
|
||
|
Mul(x1, x1, x2)
|
||
|
for i := 0; i < 5; i++ {
|
||
|
Sqr(x1, x1)
|
||
|
}
|
||
|
Mul(z, z, x1)
|
||
|
}
|
||
|
|
||
|
// Cmov assigns y to x if n is 1.
|
||
|
func Cmov(x, y *Elt, n uint) { cmov(x, y, n) }
|
||
|
|
||
|
// Cswap interchanges x and y if n is 1.
|
||
|
func Cswap(x, y *Elt, n uint) { cswap(x, y, n) }
|
||
|
|
||
|
// Add calculates z = x+y mod p.
|
||
|
func Add(z, x, y *Elt) { add(z, x, y) }
|
||
|
|
||
|
// Sub calculates z = x-y mod p.
|
||
|
func Sub(z, x, y *Elt) { sub(z, x, y) }
|
||
|
|
||
|
// AddSub calculates (x,y) = (x+y mod p, x-y mod p).
|
||
|
func AddSub(x, y *Elt) { addsub(x, y) }
|
||
|
|
||
|
// Mul calculates z = x*y mod p.
|
||
|
func Mul(z, x, y *Elt) { mul(z, x, y) }
|
||
|
|
||
|
// Sqr calculates z = x^2 mod p.
|
||
|
func Sqr(z, x *Elt) { sqr(z, x) }
|
||
|
|
||
|
// Modp ensures that z is between [0,p-1].
|
||
|
func Modp(z *Elt) { modp(z) }
|