// 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 }
// 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) }
func chi(r, v *nist.Int) { r.Init64(int64(math.Jacobi(&v.V, v.M)), v.M) }
// Set to the Jacobi symbol of (a/M), which indicates whether a is // zero (0), a positive square in M (1), or a non-square in M (-1). func (i *Int) Jacobi(as abstract.Secret) abstract.Secret { ai := as.(*Int) i.M = ai.M i.V.SetInt64(int64(math.Jacobi(&ai.V, i.M))) return i }