// 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 }
// Given a y-coordinate, solve for the x-coordinate on the curve, // using the characteristic equation rewritten as: // // x^2 = (1 - y^2)/(a - d*y^2) // // Returns true on success, // false if there is no x-coordinate corresponding to the chosen y-coordinate. // func (c *curve) solveForX(x, y *nist.Int) bool { var yy, t1, t2 nist.Int yy.Mul(y, y) // yy = y^2 t1.Sub(&c.one, &yy) // t1 = 1 - y^-2 t2.Mul(&c.d, &yy).Sub(&c.a, &t2) // t2 = a - d*y^2 t2.Div(&t1, &t2) // t2 = x^2 return x.Sqrt(&t2) // may fail if not a square }
// 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 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) }
// 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 }
// Initialize Elligator 1 parameters given magic point s func (el *el2param) init(ec *curve, u *big.Int) *el2param { el.ec = ec el.u.Init(u, &ec.P) // Compute the parameters for the Montgomery conversion: // A = 2(a+d)/(a-d) // B = 4/(a-d) // See Bernstein et al, "Twisted Edwards Curves", theorem 3.2 // http://eprint.iacr.org/2008/013.pdf var amd nist.Int amd.Sub(&ec.a, &ec.d) // t = a-d el.A.Add(&ec.a, &ec.d).Add(&el.A, &el.A).Div(&el.A, &amd) el.B.Init64(4, &ec.P).Div(&el.B, &amd) // Other precomputed constants el.sqrtB.Sqrt(&el.B) el.negA.Neg(&el.A) el.pp3d8.Add(&ec.P, big.NewInt(3)).Div(&el.pp3d8, big.NewInt(8)) el.pm1d2.Sub(&ec.P, big.NewInt(1)).Div(&el.pm1d2, big.NewInt(2)) el.sqrtm1.Init64(-1, &ec.P).Sqrt(&el.sqrtm1) return el }
// 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 }
// 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) }