// Initialize Elligator 1 parameters given magic point s func (el *el1param) init(ec *curve, s *big.Int) *el1param { var two, invc, cm1, d nist.Int el.ec = ec el.s.Init(s, &ec.P) // c = 2/s^2 two.Init64(2, &ec.P) el.c.Mul(&el.s, &el.s).Div(&two, &el.c) // r = c+1/c invc.Inv(&el.c) el.r.Add(&el.c, &invc) // Precomputed values el.r2m2.Mul(&el.r, &el.r).Sub(&el.r2m2, &two) // r^2-2 el.invc2.Mul(&invc, &invc) // 1/c^2 el.pp1d4.Add(&ec.P, one).Div(&el.pp1d4, big.NewInt(4)) // (p+1)/4 cm1.Sub(&el.c, &ec.one) el.cm1s.Mul(&cm1, &el.s) // (c-1)s el.m2.Init64(-2, &ec.P) // -2 // 2s(c-1)Chi(c)/r chi(&el.c3x, &el.c) el.c3x.Mul(&el.c3x, &two).Mul(&el.c3x, &el.s).Mul(&el.c3x, &cm1) el.c3x.Div(&el.c3x, &el.r) // Sanity check: d = -(c+1)^2/(c-1)^2 d.Add(&el.c, &ec.one).Div(&d, &cm1).Mul(&d, &d).Neg(&d) if d.Cmp(&ec.d) != 0 { panic("el1 init: d came out wrong") } return el }
// Elligator 1 reverse-map from point to uniform representative. // Returns nil if point has no uniform representative. // See section 3.3 of the Elligator paper. func (el *el1param) HideEncode(P point, rand cipher.Stream) []byte { ec := el.ec x, y := P.getXY() var a, b, etar, etarp1, X, z, u, t, t1 nist.Int // condition 1: a = y+1 is nonzero a.Add(y, &ec.one) if a.V.Sign() == 0 { return nil // y+1 = 0, no representative } // etar = r(y-1)/2(y+1) t1.Add(y, &ec.one).Add(&t1, &t1) // 2(y+1) etar.Sub(y, &ec.one).Mul(&etar, &el.r).Div(&etar, &t1) // condition 2: b = (1 + eta r)^2 - 1 is a square etarp1.Add(&ec.one, &etar) // etarp1 = (1 + eta r) b.Mul(&etarp1, &etarp1).Sub(&b, &ec.one) if math.Jacobi(&b.V, b.M) < 0 { return nil // b not a square, no representative } // condition 3: if etar = -2 then x=2s(c-1)Chi(c)/r if etar.Equal(&el.m2) && !x.Equal(&el.c3x) { return nil } // X = -(1+eta r)+((1+eta r)^2-1)^((q+1)/4) X.Exp(&b, &el.pp1d4).Sub(&X, &etarp1) // z = Chi((c-1)sX(1+X)x(X^2+1/c^2)) z.Mul(&el.cm1s, &X).Mul(&z, t.Add(&ec.one, &X)).Mul(&z, x) z.Mul(&z, t.Mul(&X, &X).Add(&t, &el.invc2)) chi(&z, &z) // u = zX u.Mul(&z, &X) // t = (1-u)/(1+u) t.Div(a.Sub(&ec.one, &u), b.Add(&ec.one, &u)) // Map representative to a byte-string by padding the upper byte. // This assumes that the prime c.P is close enough to a power of 2 // that the adversary will never notice the "missing" values; // this is true for the class of curves Elligator1 was designed for. rep, _ := t.MarshalBinary() padmask := el.padmask() if padmask != 0 { var pad [1]byte rand.XORKeyStream(pad[:], pad[:]) rep[0] |= pad[0] & padmask } return rep }
// Elligator 2 reverse-map from point to uniform representative. // Returns nil if point has no uniform representative. // See section 5.3 of the Elligator paper. func (el *el2param) HideEncode(P point, rand cipher.Stream) []byte { edx, edy := P.getXY() var x, y, r, xpA, t1 nist.Int // convert Edwards to Montgomery coordinates el.ed2mont(&x, &y, edx, edy) // condition 1: x != -A if x.Equal(&el.negA) { return nil // x = -A, no representative } // condition 2: if y=0, then x=0 if y.V.Sign() == 0 && x.V.Sign() != 0 { return nil // y=0 but x!=0, no representative } // condition 3: -ux(x+A) is a square xpA.Add(&x, &el.A) t1.Mul(&el.u, &x).Mul(&t1, &xpA).Neg(&t1) if math.Jacobi(&t1.V, t1.M) < 0 { return nil // not a square, no representative } if y.V.Cmp(&el.pm1d2) <= 0 { // y in image of sqrt function r.Mul(&xpA, &el.u).Div(&x, &r) } else { // y not in image of sqrt function r.Mul(&el.u, &x).Div(&xpA, &r) } r.Neg(&r) el.sqrt(&r, &r) // Sanity check on result if r.V.Cmp(&el.pm1d2) > 0 { panic("el2: r too big") } // Map representative to a byte-string by padding the upper byte. // This assumes that the prime c.P is close enough to a power of 2 // that the adversary will never notice the "missing" values; // this is true for the class of curves Elligator1 was designed for. rep, _ := r.MarshalBinary() padmask := el.padmask() if padmask != 0 { var pad [1]byte rand.XORKeyStream(pad[:], pad[:]) rep[0] |= pad[0] & padmask } return rep }
// Optimized point doubling for use in scalar multiplication. // Uses the formulae in section 3.3 of: // https://www.iacr.org/archive/asiacrypt2008/53500329/53500329.pdf func (P *extPoint) double() { X1, Y1, Z1, T1 := &P.X, &P.Y, &P.Z, &P.T var A, B, C, D, E, F, G, H nist.Int A.Mul(X1, X1) B.Mul(Y1, Y1) C.Mul(Z1, Z1).Add(&C, &C) D.Mul(&P.c.a, &A) E.Add(X1, Y1).Mul(&E, &E).Sub(&E, &A).Sub(&E, &B) G.Add(&D, &B) F.Sub(&G, &C) H.Sub(&D, &B) X1.Mul(&E, &F) Y1.Mul(&G, &H) T1.Mul(&E, &H) Z1.Mul(&F, &G) }
// Subtract points so that their scalars subtract homomorphically func (P *projPoint) Sub(CP1, CP2 abstract.Point) abstract.Point { P1 := CP1.(*projPoint) P2 := CP2.(*projPoint) X1, Y1, Z1 := &P1.X, &P1.Y, &P1.Z X2, Y2, Z2 := &P2.X, &P2.Y, &P2.Z X3, Y3, Z3 := &P.X, &P.Y, &P.Z var A, B, C, D, E, F, G nist.Int A.Mul(Z1, Z2) B.Mul(&A, &A) C.Mul(X1, X2) D.Mul(Y1, Y2) E.Mul(&C, &D).Mul(&P.c.d, &E) F.Add(&B, &E) G.Sub(&B, &E) X3.Add(X1, Y1).Mul(X3, Z3.Sub(Y2, X2)).Add(X3, &C).Sub(X3, &D). Mul(&F, X3).Mul(&A, X3) Y3.Mul(&P.c.a, &C).Add(&D, Y3).Mul(&G, Y3).Mul(&A, Y3) Z3.Mul(&F, &G) return P }
// Subtract points. func (P *extPoint) Sub(CP1, CP2 abstract.Point) abstract.Point { P1 := CP1.(*extPoint) P2 := CP2.(*extPoint) X1, Y1, Z1, T1 := &P1.X, &P1.Y, &P1.Z, &P1.T X2, Y2, Z2, T2 := &P2.X, &P2.Y, &P2.Z, &P2.T X3, Y3, Z3, T3 := &P.X, &P.Y, &P.Z, &P.T var A, B, C, D, E, F, G, H nist.Int A.Mul(X1, X2) B.Mul(Y1, Y2) C.Mul(T1, T2).Mul(&C, &P.c.d) D.Mul(Z1, Z2) E.Add(X1, Y1).Mul(&E, F.Sub(Y2, X2)).Add(&E, &A).Sub(&E, &B) F.Add(&D, &C) G.Sub(&D, &C) H.Mul(&P.c.a, &A).Add(&B, &H) X3.Mul(&E, &F) Y3.Mul(&G, &H) T3.Mul(&E, &H) Z3.Mul(&F, &G) return P }
// Add two points using the basic unified addition laws for Edwards curves: // // x' = ((x1*y2 + x2*y1) / (1 + d*x1*x2*y1*y2)) // y' = ((y1*y2 - a*x1*x2) / (1 - d*x1*x2*y1*y2)) // func (P *basicPoint) Add(P1, P2 abstract.Point) abstract.Point { E1 := P1.(*basicPoint) E2 := P2.(*basicPoint) x1, y1 := E1.x, E1.y x2, y2 := E2.x, E2.y var t1, t2, dm, nx, dx, ny, dy nist.Int // Reused part of denominator: dm = d*x1*x2*y1*y2 dm.Mul(&P.c.d, &x1).Mul(&dm, &x2).Mul(&dm, &y1).Mul(&dm, &y2) // x' numerator/denominator nx.Add(t1.Mul(&x1, &y2), t2.Mul(&x2, &y1)) dx.Add(&P.c.one, &dm) // y' numerator/denominator ny.Sub(t1.Mul(&y1, &y2), t2.Mul(&x1, &x2).Mul(&P.c.a, &t2)) dy.Sub(&P.c.one, &dm) // result point P.x.Div(&nx, &dx) P.y.Div(&ny, &dy) return P }
// Optimized point doubling for use in scalar multiplication. func (P *projPoint) double() { var B, C, D, E, F, H, J nist.Int B.Add(&P.X, &P.Y).Mul(&B, &B) C.Mul(&P.X, &P.X) D.Mul(&P.Y, &P.Y) E.Mul(&P.c.a, &C) F.Add(&E, &D) H.Mul(&P.Z, &P.Z) J.Add(&H, &H).Sub(&F, &J) P.X.Sub(&B, &C).Sub(&P.X, &D).Mul(&P.X, &J) P.Y.Sub(&E, &D).Mul(&F, &P.Y) P.Z.Mul(&F, &J) }
// Elligator 2 forward-map from representative to Edwards curve point. // Currently a straightforward, unoptimized implementation. // See section 5.2 of the Elligator paper. func (el *el2param) HideDecode(P point, rep []byte) { ec := el.ec var r, v, x, y, t1, edx, edy nist.Int l := ec.PointLen() if len(rep) != l { panic("el2Map: wrong representative length") } // Take the appropriate number of bits from the representative. buf := make([]byte, l) copy(buf, rep) buf[0] &^= el.padmask() // mask off the padding bits r.InitBytes(buf, &ec.P) // v = -A/(1+ur^2) v.Mul(&r, &r).Mul(&el.u, &v).Add(&ec.one, &v).Div(&el.negA, &v) // e = Chi(v^3+Av^2+Bv), where B=1 because of ed2mont equivalence t1.Add(&v, &el.A).Mul(&t1, &v).Add(&t1, &ec.one).Mul(&t1, &v) e := math.Jacobi(&t1.V, t1.M) // x = ev-(1-e)A/2 if e == 1 { x.Set(&v) } else { x.Add(&v, &el.A).Neg(&x) } // y = -e sqrt(x^3+Ax^2+Bx), where B=1 y.Add(&x, &el.A).Mul(&y, &x).Add(&y, &ec.one).Mul(&y, &x) el.sqrt(&y, &y) if e == 1 { y.Neg(&y) // -e factor } // Convert Montgomery to Edwards coordinates el.mont2ed(&edx, &edy, &x, &y) // Sanity-check if !ec.onCurve(&edx, &edy) { panic("elligator2 produced invalid point") } P.initXY(&edx.V, &edy.V, ec.self) }
// Initialize a twisted Edwards curve with given parameters. // Caller passes pointers to null and base point prototypes to be initialized. func (c *curve) init(self abstract.Group, p *Param, fullGroup bool, null, base point) *curve { c.self = self c.Param = *p c.full = fullGroup c.null = null // Edwards curve parameters as ModInts for convenience c.a.Init(&p.A, &p.P) c.d.Init(&p.D, &p.P) // Cofactor c.cofact.Init64(int64(p.R), &c.P) // Determine the modulus for scalars on this curve. // Note that we do NOT initialize c.order with Init(), // as that would normalize to the modulus, resulting in zero. // Just to be sure it's never used, we leave c.order.M set to nil. // We want it to be in a ModInt so we can pass it to P.Mul(), // but the scalar's modulus isn't needed for point multiplication. if fullGroup { // Scalar modulus is prime-order times the ccofactor c.order.V.SetInt64(int64(p.R)).Mul(&c.order.V, &p.Q) } else { c.order.V.Set(&p.Q) // Prime-order subgroup } // Useful ModInt constants for this curve c.zero.Init64(0, &c.P) c.one.Init64(1, &c.P) // Identity element is (0,1) null.initXY(zero, one, self) // Base point B var bx, by *big.Int if !fullGroup { bx, by = &p.PBX, &p.PBY } else { bx, by = &p.FBX, &p.FBY base.initXY(&p.FBX, &p.FBY, self) } if by.Sign() == 0 { // No standard base point was defined, so pick one. // Find the lowest-numbered y-coordinate that works. //println("Picking base point:") var x, y nist.Int for y.Init64(2, &c.P); ; y.Add(&y, &c.one) { if !c.solveForX(&x, &y) { continue // try another y } if c.coordSign(&x) != 0 { x.Neg(&x) // try positive x first } base.initXY(&x.V, &y.V, self) if c.validPoint(base) { break // got one } x.Neg(&x) // try -bx if c.validPoint(base) { break // got one } } //println("BX: "+x.V.String()) //println("BY: "+y.V.String()) bx, by = &x.V, &y.V } base.initXY(bx, by, self) // Uniform representation encoding methods, // only useful when using the full group. // (Points taken from the subgroup would be trivially recognizable.) if fullGroup { if p.Elligator1s.Sign() != 0 { c.hide = new(el1param).init(c, &p.Elligator1s) } else if p.Elligator2u.Sign() != 0 { c.hide = new(el2param).init(c, &p.Elligator2u) } // XXX Elligator Squared } // Sanity checks if !c.validPoint(null) { panic("invalid identity point " + null.String()) } if !c.validPoint(base) { panic("invalid base point " + base.String()) } return c }
// Elligator 1 forward-map from representative to Edwards curve point. // Currently a straightforward, unoptimized implementation. // See section 3.2 of the Elligator paper. func (el *el1param) HideDecode(P point, rep []byte) { ec := el.ec var t, u, u2, v, Chiv, X, Y, x, y, t1, t2 nist.Int l := ec.PointLen() if len(rep) != l { panic("el1Map: wrong representative length") } // Take the appropriate number of bits from the representative. b := make([]byte, l) copy(b, rep) b[0] &^= el.padmask() // mask off the padding bits t.InitBytes(b, &ec.P) // u = (1-t)/(1+t) u.Div(t1.Sub(&ec.one, &t), t2.Add(&ec.one, &t)) // v = u^5 + (r^2-2)u^3 + u u2.Mul(&u, &u) // u2 = u^2 v.Mul(&u2, &u2) // v = u^4 v.Add(&v, t1.Mul(&el.r2m2, &u2)) // v = u^4 + (r^2-2)u^2 v.Add(&v, &ec.one).Mul(&v, &u) // v = u^5 + (r^2-2)u^3 + u // X = Chi(v)u chi(&Chiv, &v) X.Mul(&Chiv, &u) // Y = (Chi(v)v)^((q+1)/4) Chi(v) Chi(u^2+1/c^2) t1.Add(&u2, &el.invc2) chi(&t1, &t1) // t1 = Chi(u^2+1/c^2) Y.Mul(&Chiv, &v) Y.Exp(&Y, &el.pp1d4).Mul(&Y, &Chiv).Mul(&Y, &t1) // x = (c-1)sX(1+X)/Y x.Add(&ec.one, &X).Mul(&X, &x).Mul(&el.cm1s, &x).Div(&x, &Y) // y = (rX-(1+X)^2)/(rX+(1+X)^2) t1.Mul(&el.r, &X) // t1 = rX t2.Add(&ec.one, &X).Mul(&t2, &t2) // t2 = (1+X)^2 y.Div(u.Sub(&t1, &t2), v.Add(&t1, &t2)) // Sanity-check if !ec.onCurve(&x, &y) { panic("elligator1 produced invalid point") } P.initXY(&x.V, &y.V, ec.self) }
// Convert from Montgomery form (u,v) to Edwards (x,y) via: // // x = sqrt(B)u/v // y = (u-1)/(u+1) // func (el *el2param) mont2ed(x, y, u, v *nist.Int) { ec := el.ec var t1, t2 nist.Int x.Mul(u, &el.sqrtB).Div(x, v) y.Div(t1.Sub(u, &ec.one), t2.Add(u, &ec.one)) }
// Convert point from Twisted Edwards form: ax^2+y^2 = 1+dx^2y^2 // to Montgomery form: v^2 = u^3+Au^2+u // via the equivalence: // // u = (1+y)/(1-y) // v = sqrt(B)u/x // // where A=2(a+d)/(a-d) and B=4(a-d) // // Beware: the Twisted Edwards Curves paper uses B as a factor for v^2, // whereas the Elligator 2 paper uses B as a factor for the last u term. // func (el *el2param) ed2mont(u, v, x, y *nist.Int) { ec := el.ec var t1, t2 nist.Int u.Div(t1.Add(&ec.one, y), t2.Sub(&ec.one, y)) v.Mul(u, &el.sqrtB).Div(v, x) }