Skip to content

Commit

Permalink
Adding Fp2 arithmetic.
Browse files Browse the repository at this point in the history
  • Loading branch information
armfazh committed Jun 3, 2020
1 parent c217ebe commit 4038960
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 126 deletions.
33 changes: 20 additions & 13 deletions curve/toy/toy.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const (
W1ISO ID = "W1ISO"
W2 ID = "W2"
W3 ID = "W3"
W4 ID = "W4"
WC0 ID = "WC0"
M0 ID = "M0"
M1 ID = "M1"
Expand All @@ -27,10 +28,10 @@ const (

type params struct {
model C.Model
p int
p, m int
a, b int
h, r int
x, y int
x, y interface{}
}

// Curves is a list of toy curves.
Expand All @@ -41,24 +42,30 @@ func init() {
Curves = make([]ID, 0, 10)
toyCurves = make(map[ID]*params)

W0.register(&params{C.Weierstrass, 53, 3, 2, 51, 3, 46, 3})
W1.register(&params{C.Weierstrass, 53, 0, 1, 54, 2, 13, 5})
W1ISO.register(&params{C.Weierstrass, 53, 38, 22, 54, 2, 41, 45})
W2.register(&params{C.Weierstrass, 53, 0, 2, 51, 3, 37, 27})
W3.register(&params{C.Weierstrass, 59, 16, 0, 60, 4, 33, 11})
WC0.register(&params{C.WeierstrassC, 53, 2, 3, 66, 6, 45, 4})
M0.register(&params{C.Montgomery, 53, 4, 3, 44, 4, 16, 4})
M1.register(&params{C.Montgomery, 53, 3, 1, 48, 4, 14, 22})
E0.register(&params{C.TwistedEdwards, 53, 1, 3, 44, 4, 17, 49})
E1.register(&params{C.TwistedEdwards, 53, -1, 12, 48, 4, 3, 19})
W0.register(&params{model: C.Weierstrass, p: 53, m: 1, a: 3, b: 2, r: 51, h: 3, x: 46, y: 3})
W1.register(&params{model: C.Weierstrass, p: 53, m: 1, a: 0, b: 1, r: 54, h: 2, x: 13, y: 5})
W1ISO.register(&params{model: C.Weierstrass, p: 53, m: 1, a: 38, b: 22, r: 54, h: 2, x: 41, y: 45})
W2.register(&params{model: C.Weierstrass, p: 53, m: 1, a: 0, b: 2, r: 51, h: 3, x: 37, y: 27})
W3.register(&params{model: C.Weierstrass, p: 59, m: 1, a: 16, b: 0, r: 60, h: 4, x: 33, y: 11})
WC0.register(&params{model: C.WeierstrassC, p: 53, m: 1, a: 2, b: 3, r: 66, h: 6, x: 45, y: 4})
M0.register(&params{model: C.Montgomery, p: 53, m: 1, a: 4, b: 3, r: 44, h: 4, x: 16, y: 4})
M1.register(&params{model: C.Montgomery, p: 53, m: 1, a: 3, b: 1, r: 48, h: 4, x: 14, y: 22})
E0.register(&params{model: C.TwistedEdwards, p: 53, m: 1, a: 1, b: 3, r: 44, h: 4, x: 17, y: 49})
E1.register(&params{model: C.TwistedEdwards, p: 53, m: 1, a: -1, b: 12, r: 48, h: 4, x: 3, y: 19})
W4.register(&params{model: C.Weierstrass, p: 19, m: 2, a: 1, b: 4, r: 399, h: 3, x: []interface{}{0, 1}, y: 17})
}

func (id ID) register(p *params) { toyCurves[id] = p; Curves = append(Curves, id) }

// New returns an elliptic curve and a generator point.
func (id ID) New() (C.EllCurve, C.Point, error) {
if v, ok := toyCurves[id]; ok {
F := GF.NewFp(fmt.Sprintf("%v", v.p), v.p)
var F GF.Field
if v.m == 1 {
F = GF.NewFp(fmt.Sprintf("%v", v.p), v.p)
} else if v.m == 2 {
F = GF.NewFp2(fmt.Sprintf("%v", v.p), v.p)
}
E := v.model.New(string(id), F,
F.Elt(v.a), F.Elt(v.b),
big.NewInt(int64(v.r)), big.NewInt(int64(v.h)))
Expand Down
14 changes: 2 additions & 12 deletions field/ff.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,8 @@ type Field interface {
Exp(x Elt, n *big.Int) Elt // Returns x^n.
Inv0(Elt) Elt // Returns 1/x, and 0 if x=0.
CMov(x, y Elt, b bool) Elt // Returns x if b=false, otherwise, returns y.
GetSgn0(Sgn0ID) func(Elt) int
hasSqrt
Sgn0(x Elt) int // Returns the sign of x.
hasSqrt // Returns a square-root of x.
}

type hasSqrt interface{ Sqrt(Elt) Elt }

// Sgn0ID is an identifier of a sign function.
type Sgn0ID int

const (
// SignLE denotes little-endian sign function.
SignLE Sgn0ID = iota
// SignBE denotes big-endian sign function.
SignBE
)
12 changes: 1 addition & 11 deletions field/fp.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,17 +101,7 @@ func (f fp) Exp(x Elt, y *big.Int) Elt {
// Implementing extended operations
func (f fp) Generator() Elt { return f.One() }
func (f fp) Inv0(x Elt) Elt { return f.Inv(x) }
func (f fp) GetSgn0(id Sgn0ID) func(Elt) int {
if id == SignBE {
return f.Sgn0BE
}
if id == SignLE {
return f.Sgn0LE
}
panic("Wrong signID")
}
func (f fp) Sgn0BE(x Elt) int { return 1 - 2*((f.cte.pMinus1div2.Cmp(x.(*fpElt).n)>>1)&1) }
func (f fp) Sgn0LE(x Elt) int { return 1 - 2*int(x.(*fpElt).n.Bit(0)) }
func (f fp) Sgn0(x Elt) int { return int(x.(*fpElt).n.Bit(0)) }
func (f fp) CMov(x, y Elt, b bool) Elt {
var z big.Int
if b {
Expand Down
232 changes: 142 additions & 90 deletions field/fp2.go
Original file line number Diff line number Diff line change
@@ -1,138 +1,190 @@
package field

import (
"crypto/rand"
"fmt"
"io"
"math/big"
)

type fp2Elt struct {
a, b *big.Int
}
type fp2Elt [2]fpElt

func (e fp2Elt) String() string {
return "\na: 0x" + e.a.Text(16) +
"\nb: 0x" + e.b.Text(16) + " * i"
}

func (e fp2Elt) Copy() Elt { r := &fp2Elt{}; r.a.Set(e.a); r.b.Set(e.b); return r }
func (e fp2Elt) Polynomial() []*big.Int {
return []*big.Int{
new(big.Int).Set(e.a),
new(big.Int).Set(e.b),
}
}
func (e fp2Elt) String() string { return fmt.Sprintf("\na: %v\nb: %v", e[0], e[1]) }
func (e fp2Elt) Copy() Elt { return &fp2Elt{*(e[0].Copy().(*fpElt)), *(e[1].Copy().(*fpElt))} }
func (e fp2Elt) Polynomial() []*big.Int { return append(e[0].Polynomial(), e[1].Polynomial()...) }

type fp2 struct {
p *big.Int
hasSqrt
base fp
name string
cte struct {
pMinus1div2 *big.Int
}
}

// NewFp2 creates a quadratic extension field Z/pZ[x] with irreducible polynomial x^2=-1 and given p as an int, uint, *big.Int or string.
func NewFp2(name string, p interface{}) Field {
prime := FromType(p)
if !prime.ProbablyPrime(4) {
panic("p is not prime")
base := NewFp(name, p).(fp)
f := fp2{base: base, name: name}
f.precmp()
return f
}

func (f *fp2) precmp() {
t := big.NewInt(16)
pMod16 := t.Mod(f.base.p, t).Uint64()
switch {
case pMod16%4 == uint64(3):
f.hasSqrt = generateSqrtP3mod4(f)
default:
panic("not implemented yet")
}
return fp2{p: prime, name: name}
}

func (f fp2) Elt(in interface{}) Elt {
var a, b *big.Int
if v, ok := in.([]interface{}); ok && len(v) == 2 {
a = FromType(v[0])
b = FromType(v[1])
} else {
a = FromType(in)
b = big.NewInt(0)
return &fp2Elt{
*(f.base.Elt(v[0]).(*fpElt)),
*(f.base.Elt(v[1]).(*fpElt)),
}
}
return &fp2Elt{
*(f.base.Elt(in).(*fpElt)),
*(f.base.Zero().(*fpElt)),
}
return f.mod(a, b)
}
func (f fp2) P() *big.Int { return new(big.Int).Set(f.p) }
func (f fp2) Order() *big.Int { return new(big.Int).Mul(f.p, f.p) }
func (f fp2) P() *big.Int { return f.base.P() }
func (f fp2) Order() *big.Int { return new(big.Int).Mul(f.base.p, f.base.p) }
func (f fp2) String() string { return "GF(" + f.name + ") Irred: i^2+1" }
func (f fp2) Ext() uint { return uint(2) }
func (f fp2) Zero() Elt { return f.Elt(0) }
func (f fp2) One() Elt { return f.Elt(1) }
func (f fp2) BitLen() int { return f.p.BitLen() }
func (f fp2) BitLen() int { return f.base.p.BitLen() }

func (f fp2) AreEqual(x, y Elt) bool { return f.IsZero(f.Sub(x, y)) }
func (f fp2) IsEqual(ff Field) bool { return f.p.Cmp(ff.(fp2).p) == 0 }
func (f fp2) IsEqual(ff Field) bool { return f.base.p.Cmp(ff.(fp2).base.p) == 0 }
func (f fp2) IsZero(x Elt) bool {
e := x.(*fp2Elt)
return e.a.Mod(e.a, f.p).Sign() == 0 &&
e.b.Mod(e.b, f.p).Sign() == 0
return f.base.IsZero(&e[0]) && f.base.IsZero(&e[1])
}

func (f fp2) Rand(r io.Reader) Elt {
a, _ := rand.Int(r, f.p)
b, _ := rand.Int(r, f.p)
return &fp2Elt{a, b}
return &fp2Elt{*f.base.Rand(r).(*fpElt), *f.base.Rand(r).(*fpElt)}
}

func (f fp2) mod(a, b *big.Int) Elt { return &fp2Elt{a: a.Mod(a, f.p), b: b.Mod(b, f.p)} }
func (f fp2) Add(x, y Elt) Elt {
a := new(big.Int).Add(x.(fp2Elt).a, y.(fp2Elt).a)
b := new(big.Int).Add(x.(fp2Elt).b, y.(fp2Elt).b)
a.Mod(a, f.p)
b.Mod(b, f.p)
return fp2Elt{a, b}
xx := x.(*fp2Elt)
yy := y.(*fp2Elt)
z0 := f.base.Add(&xx[0], &yy[0])
z1 := f.base.Add(&xx[1], &yy[1])
return &fp2Elt{*(z0.(*fpElt)), *(z1.(*fpElt))}
}
func (f fp2) Sub(x, y Elt) Elt {
a := new(big.Int).Sub(x.(fp2Elt).a, y.(fp2Elt).a)
b := new(big.Int).Sub(x.(fp2Elt).b, y.(fp2Elt).b)
a.Mod(a, f.p)
b.Mod(b, f.p)
return fp2Elt{a, b}
xx := x.(*fp2Elt)
yy := y.(*fp2Elt)
z0 := f.base.Sub(&xx[0], &yy[0])
z1 := f.base.Sub(&xx[1], &yy[1])
return &fp2Elt{*(z0.(*fpElt)), *(z1.(*fpElt))}
}

func (f fp2) Mul(x, y Elt) Elt { return nil }
func (f fp2) Sqr(x Elt) Elt { return nil }
func (f fp2) Inv(x Elt) Elt { return nil }
func (f fp2) Neg(x Elt) Elt { return nil }
func (f fp2) Sqrt(x Elt) Elt { return nil }
func (f fp2) Exp(x Elt, e *big.Int) Elt { return nil }
func (f fp2) IsSquare(x Elt) bool { return false }
func (f fp2) Mul(x, y Elt) Elt {
xx := x.(*fp2Elt)
yy := y.(*fp2Elt)
x0y0 := f.base.Mul(&xx[0], &yy[0])
x0y1 := f.base.Mul(&xx[0], &yy[1])
x1y0 := f.base.Mul(&xx[1], &yy[0])
x1y1 := f.base.Mul(&xx[1], &yy[1])

z0 := f.base.Sub(x0y0, x1y1)
z1 := f.base.Add(x0y1, x1y0)
return &fp2Elt{*(z0.(*fpElt)), *(z1.(*fpElt))}
}
func (f fp2) Sqr(x Elt) Elt { return f.Mul(x, x) }
func (f fp2) Inv(x Elt) Elt {
xx := x.(*fp2Elt)
tv1 := f.base.Sqr(&xx[0])
tv2 := f.base.Sqr(&xx[1])
tv3 := f.base.Add(tv1, tv2)
tv4 := f.base.Inv(tv3)
z0 := f.base.Mul(&xx[0], tv4)
z1 := f.base.Mul(&xx[1], tv4)
z1 = f.base.Neg(z1)
return &fp2Elt{*(z0.(*fpElt)), *(z1.(*fpElt))}
}
func (f fp2) Neg(x Elt) Elt {
xx := x.(*fp2Elt)
z0 := f.base.Neg(&xx[0])
z1 := f.base.Neg(&xx[1])
return &fp2Elt{*(z0.(*fpElt)), *(z1.(*fpElt))}
}
func (f fp2) Exp(x Elt, e *big.Int) Elt {
n := e.BitLen()
z := f.One()
for i := n - 1; i >= 0; i-- {
z = f.Sqr(z)
if e.Bit(i) == 1 {
z = f.Mul(z, x)
}
}
return z
}
func (f fp2) IsSquare(x Elt) bool {
xx := x.(*fp2Elt)
tv1 := f.base.Sqr(&xx[0])
tv2 := f.base.Sqr(&xx[1])
tv3 := f.base.Add(tv1, tv2)
tv4 := f.base.Exp(tv3, f.base.cte.pMinus1div2)
return f.base.AreEqual(tv4, f.base.One())
}

func (f fp2) Generator() Elt { return f.Elt([]string{"0", "1"}) }
func (f fp2) Inv0(x Elt) Elt { return f.Inv(x) }
func (f fp2) CMov(x, y Elt, b bool) Elt {
var za, zb big.Int
if b {
za.Set(y.(*fp2Elt).a)
zb.Set(y.(*fp2Elt).b)
} else {
za.Set(x.(*fp2Elt).a)
zb.Set(x.(*fp2Elt).b)
}
return &fp2Elt{&za, &zb}
xx := x.(*fp2Elt)
yy := y.(*fp2Elt)
z0 := f.base.CMov(&xx[0], &yy[0], b)
z1 := f.base.CMov(&xx[1], &yy[1], b)
return &fp2Elt{*(z0.(*fpElt)), *(z1.(*fpElt))}
}
func (f fp2) GetSgn0(id Sgn0ID) func(Elt) int {
if id == SignBE {
return f.Sgn0BE
func (f fp2) Sgn0(x Elt) int {
xx := x.(*fp2Elt)
s0 := f.base.Sgn0(&xx[0])
z0 := 0
if f.base.IsZero(&xx[0]) {
z0 = 1
}
if id == SignLE {
return f.Sgn0LE
}
panic("Wrong signID")
s1 := f.base.Sgn0(&xx[1])
return s0 | (z0 & s1)
}

type f2sqrtp3mod4 struct {
// This Alg 9. from Adj-Rodriguez
*fp2
c1 *big.Int // c1 = (p-3)/4
c2 *big.Int // c2 = (p-1)/2
}
func (f fp2) Sgn0BE(x Elt) int {
/* [TODO] */
sb := x.(*fp2Elt).b.Sign()
cb := 2*(f.cte.pMinus1div2.Cmp(x.(*fp2Elt).b)&^1) - 1
sa := x.(*fp2Elt).a.Sign()
ca := 2*(f.cte.pMinus1div2.Cmp(x.(*fp2Elt).a)&^1) - 1
return sb*cb + (1-sb)*(sa*ca+(1-sa)*1)

func generateSqrtP3mod4(f *fp2) hasSqrt {
c1 := big.NewInt(3)
c1.Sub(f.base.p, c1)
c1.Rsh(c1, 2)
c2 := big.NewInt(1)
c2.Sub(f.base.p, c2)
c2.Rsh(c2, 1)
return f2sqrtp3mod4{c1: c1, c2: c2, fp2: f}
}

func (f fp2) Sgn0LE(x Elt) int {
/* [TODO] */
sa := x.(*fp2Elt).a.Sign()
ca := 1 - 2*int(x.(*fp2Elt).a.Bit(0))
sb := x.(*fp2Elt).b.Sign()
cb := 1 - 2*int(x.(*fp2Elt).b.Bit(0))
return sa*ca + (1-sa)*(sb*cb+(1-sb)*1)
func (s f2sqrtp3mod4) Sqrt(a Elt) Elt {
a1 := s.Exp(a, s.c1)
a1a := s.Mul(a1, a)
alpha := s.Mul(a1, a1a)
x0 := a1a

var zz Elt
if t := s.Add(alpha, s.One()); s.IsZero(t) {
i := &fp2Elt{
*(s.base.Zero().(*fpElt)),
*(s.base.One().(*fpElt)),
}
zz = s.Mul(x0, i)
} else {
par := s.Add(s.One(), alpha)
b := s.Exp(par, s.c2)
zz = s.Mul(b, x0)
}
return zz
}
Loading

0 comments on commit 4038960

Please sign in to comment.