implement binary EEA inversion
This commit is contained in:
parent
f86324edb7
commit
618dae47a5
|
@ -92,6 +92,64 @@ func TestTripartiteDiffieHellman(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestBinaryEAA(t *testing.T) {
|
||||
for i := 0; i < 10000; i++ {
|
||||
_, Ga, err := RandomG1(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
tmpLittleFermat := &gfP{}
|
||||
tmpLittleFermat.Invert(&Ga.p.x)
|
||||
|
||||
tmpBinaryEAA := &gfP{}
|
||||
tmpBinaryEAA.EaaInvert(&Ga.p.x)
|
||||
|
||||
eq := equals(tmpLittleFermat, tmpBinaryEAA)
|
||||
if eq == false {
|
||||
t.Fatalf("results of different inversion do not agree")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLittleFermatInversion(b *testing.B) {
|
||||
el := gfP{0x0, 0x97816a916871ca8d, 0xb85045b68181585d, 0x30644e72e131a029}
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
tmp := &gfP{}
|
||||
for i := 0; i < b.N; i++ {
|
||||
tmp.Invert(&el)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkBinaryEEAInversion(b *testing.B) {
|
||||
el := gfP{0x0, 0x97816a916871ca8d, 0xb85045b68181585d, 0x30644e72e131a029}
|
||||
|
||||
b.ResetTimer()
|
||||
|
||||
tmp := &gfP{}
|
||||
for i := 0; i < b.N; i++ {
|
||||
tmp.EaaInvert(&el)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkG1AddAndMakeAffine(b *testing.B) {
|
||||
_, Ga, err := RandomG1(rand.Reader)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
_, Gb, err := RandomG1(rand.Reader)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
b.ResetTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
e := new(G1).Add(Ga, Gb)
|
||||
e.p.MakeAffine()
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkG1(b *testing.B) {
|
||||
x, _ := rand.Int(rand.Reader, Order)
|
||||
b.ResetTimer()
|
||||
|
|
|
@ -217,7 +217,8 @@ func (c *curvePoint) MakeAffine() {
|
|||
}
|
||||
|
||||
zInv := &gfP{}
|
||||
zInv.Invert(&c.z)
|
||||
zInv.EaaInvert(&c.z)
|
||||
// zInv.Invert(&c.z)
|
||||
|
||||
t, zInv2 := &gfP{}, &gfP{}
|
||||
gfpMul(t, &c.y, zInv)
|
||||
|
|
|
@ -3,6 +3,7 @@ package bn256
|
|||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/bits"
|
||||
)
|
||||
|
||||
type gfP [4]uint64
|
||||
|
@ -79,3 +80,130 @@ func (e *gfP) Unmarshal(in []byte) error {
|
|||
|
||||
func montEncode(c, a *gfP) { gfpMul(c, a, r2) }
|
||||
func montDecode(c, a *gfP) { gfpMul(c, a, &gfP{1}) }
|
||||
|
||||
func isZero(a *gfP) bool {
|
||||
return a[0] == 0 && a[1] == 0 && a[2] == 0 && a[3] == 0
|
||||
}
|
||||
|
||||
func isEven(a *gfP) bool {
|
||||
return bits.TrailingZeros64((a[0])) > 0
|
||||
}
|
||||
|
||||
func div2(a *gfP) {
|
||||
a[0] = a[0]>>1 | a[1]<<63
|
||||
a[1] = a[1]>>1 | a[2]<<63
|
||||
a[2] = a[2]>>1 | a[3]<<63
|
||||
a[3] = a[3] >> 1
|
||||
}
|
||||
|
||||
func (e *gfP) addNocarry(f *gfP) {
|
||||
carry := uint64(0)
|
||||
e[0], carry = bits.Add64(e[0], f[0], carry)
|
||||
e[1], carry = bits.Add64(e[1], f[1], carry)
|
||||
e[2], carry = bits.Add64(e[2], f[2], carry)
|
||||
e[3], _ = bits.Add64(e[3], f[3], carry)
|
||||
}
|
||||
|
||||
func (e *gfP) subNoborrow(f *gfP) {
|
||||
borrow := uint64(0)
|
||||
e[0], borrow = bits.Sub64(e[0], f[0], borrow)
|
||||
e[1], borrow = bits.Sub64(e[1], f[1], borrow)
|
||||
e[2], borrow = bits.Sub64(e[2], f[2], borrow)
|
||||
e[3], _ = bits.Sub64(e[3], f[3], borrow)
|
||||
}
|
||||
|
||||
func gte(a, b *gfP) bool {
|
||||
// subtract b from a. If no borrow occures then a >= b
|
||||
borrow := uint64(0)
|
||||
_, borrow = bits.Sub64(a[0], b[0], borrow)
|
||||
_, borrow = bits.Sub64(a[1], b[1], borrow)
|
||||
_, borrow = bits.Sub64(a[2], b[2], borrow)
|
||||
_, borrow = bits.Sub64(a[3], b[3], borrow)
|
||||
|
||||
return borrow == 0
|
||||
}
|
||||
|
||||
func equals(a, b *gfP) bool {
|
||||
return a[0] == b[0] && a[1] == b[1] && a[2] == b[2] && a[3] == b[3]
|
||||
}
|
||||
|
||||
// Performs inversion of the field element using binary EEA.
|
||||
// If element is zero (no inverse exists) then set `e` to zero
|
||||
func (e *gfP) EaaInvert(f *gfP) {
|
||||
if isZero(f) {
|
||||
e.Set(&gfP{0, 0, 0, 0})
|
||||
return
|
||||
}
|
||||
|
||||
// Guajardo Kumar Paar Pelzl
|
||||
// Efficient Software-Implementation of Finite Fields with Applications to Cryptography
|
||||
// Algorithm 16 (BEA for Inversion in Fp)
|
||||
|
||||
one := gfP{1, 0, 0, 0}
|
||||
|
||||
u, b := gfP{}, gfP{}
|
||||
u.Set(f)
|
||||
b.Set(r2)
|
||||
|
||||
v := gfP{p2[0], p2[1], p2[2], p2[3]}
|
||||
c := gfP{0, 0, 0, 0}
|
||||
modulus := gfP{p2[0], p2[1], p2[2], p2[3]}
|
||||
|
||||
for {
|
||||
if equals(&u, &one) || equals(&v, &one) {
|
||||
break
|
||||
}
|
||||
|
||||
// while u is even
|
||||
for {
|
||||
if !isEven(&u) {
|
||||
break
|
||||
}
|
||||
|
||||
div2(&u)
|
||||
if isEven(&b) {
|
||||
div2(&b)
|
||||
} else {
|
||||
// we will not overflow a modulus here,
|
||||
// so we can use specialized function
|
||||
// do perform addition without reduction
|
||||
b.addNocarry(&modulus)
|
||||
div2(&b)
|
||||
}
|
||||
}
|
||||
|
||||
// while v is even
|
||||
for {
|
||||
if !isEven(&v) {
|
||||
break
|
||||
}
|
||||
|
||||
div2(&v)
|
||||
if isEven(&c) {
|
||||
div2(&c)
|
||||
} else {
|
||||
// we will not overflow a modulus here,
|
||||
// so we can use specialized function
|
||||
// do perform addition without reduction
|
||||
c.addNocarry(&modulus)
|
||||
div2(&c)
|
||||
}
|
||||
}
|
||||
|
||||
if gte(&v, &u) {
|
||||
// v >= u
|
||||
v.subNoborrow(&u)
|
||||
gfpSub(&c, &c, &b)
|
||||
} else {
|
||||
// if v < u
|
||||
u.subNoborrow(&v)
|
||||
gfpSub(&b, &b, &c)
|
||||
}
|
||||
}
|
||||
|
||||
if equals(&u, &one) {
|
||||
e.Set(&b)
|
||||
} else {
|
||||
e.Set(&c)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue