// Decode an Edwards curve point into the given x,y coordinates. // Returns an error if the input does not denote a valid curve point. // Note that this does NOT check if the point is in the prime-order subgroup: // an adversary could create an encoding denoting a point // on the twist of the curve, or in a larger subgroup. // However, the "safecurves" criteria (http://safecurves.cr.yp.to) // ensure that none of these other subgroups are small // other than the tiny ones represented by the cofactor; // hence Diffie-Hellman exchange can be done without subgroup checking // without exposing more than the least-significant bits of the scalar. func (c *curve) decodePoint(bb []byte, x, y *nist.Int) error { // Convert from little-endian //fmt.Printf("decoding:\n%s\n", hex.Dump(bb)) b := make([]byte, len(bb)) util.Reverse(b, bb) // Extract the sign of the x-coordinate xsign := uint(b[0] >> 7) b[0] &^= 0x80 // Extract the y-coordinate y.V.SetBytes(b) y.M = &c.P // Compute the corresponding x-coordinate if !c.solveForX(x, y) { return errors.New("invalid elliptic curve point") } if c.coordSign(x) != xsign { x.Neg(x) } return nil }
// Encode an Edwards curve point. // We use little-endian encoding for consistency with Ed25519. func (c *curve) encodePoint(x, y *nist.Int) []byte { // Encode the y-coordinate b, _ := y.MarshalBinary() // Encode the sign of the x-coordinate. if y.M.BitLen()&7 == 0 { // No unused bits at the top of y-coordinate encoding, // so we must prepend a whole byte. b = append(make([]byte, 1), b...) } if c.coordSign(x) != 0 { b[0] |= 0x80 } // Convert to little-endian util.Reverse(b, b) //fmt.Printf("encoding %s,%s:\n%s\n", x.String(), y.String(), // hex.Dump(b)) return b }
// Equality test for two Points on the same curve. // We can avoid inversions here because: // // (X1/Z1,Y1/Z1) == (X2/Z2,Y2/Z2) // iff // (X1*Z2,Y1*Z2) == (X2*Z1,Y2*Z1) // func (P1 *projPoint) Equal(CP2 abstract.Point) bool { P2 := CP2.(*projPoint) var t1, t2 nist.Int xeq := t1.Mul(&P1.X, &P2.Z).Equal(t2.Mul(&P2.X, &P1.Z)) yeq := t1.Mul(&P1.Y, &P2.Z).Equal(t2.Mul(&P2.Y, &P1.Z)) return xeq && yeq }
// Parameters defining Curve1174, as specified in: // Bernstein et al, "Elligator: Elliptic-curve points indistinguishable // from uniform random strings" // http://elligator.cr.yp.to/elligator-20130828.pdf // func Param1174() *Param { var p Param var mi nist.Int p.Name = "1174" p.P.SetBit(zero, 251, 1).Sub(&p.P, big.NewInt(9)) p.Q.SetString("45330879683285730139092453152713398835", 10) p.Q.Sub(&p.P, &p.Q).Div(&p.Q, big.NewInt(4)) p.R = 4 p.A.SetInt64(1) p.D.SetInt64(-1174) // Full-group generator is (4/V,3/5) mi.InitString("4", "19225777642111670230408712442205514783403012708409058383774613284963344096", 10, &p.P) p.FBX.Set(&mi.V) mi.InitString("3", "5", 10, &p.P) p.FBY.Set(&mi.V) // Elligator1 parameter s for Curve1174 (Elligator paper section 4.1) p.Elligator1s.SetString("1806494121122717992522804053500797229648438766985538871240722010849934886421", 10) 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 }
// 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 }
// Convert a point to string representation. func (c *curve) pointString(x, y *nist.Int) string { return fmt.Sprintf("(%s,%s)", x.String(), y.String()) }
// 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) }
// 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. 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) }
// 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 }
// Pick a [pseudo-]random curve point with optional embedded data, // filling in the point's x,y coordinates // and returning any remaining data not embedded. func (c *curve) pickPoint(P point, data []byte, rand cipher.Stream) []byte { // How much data to embed? dl := c.pickLen() if dl > len(data) { dl = len(data) } // Retry until we find a valid point var x, y nist.Int var Q abstract.Point for { // Get random bits the size of a compressed Point encoding, // in which the topmost bit is reserved for the x-coord sign. l := c.PointLen() b := make([]byte, l) rand.XORKeyStream(b, b) // Interpret as little-endian if data != nil { b[0] = byte(dl) // Encode length in low 8 bits copy(b[1:1+dl], data) // Copy in data to embed } util.Reverse(b, b) // Convert to big-endian form xsign := b[0] >> 7 // save x-coordinate sign bit b[0] &^= 0xff << uint(c.P.BitLen()&7) // clear high bits y.M = &c.P // set y-coordinate y.SetBytes(b) if !c.solveForX(&x, &y) { // Corresponding x-coordinate? continue // none, retry } // Pick a random sign for the x-coordinate if c.coordSign(&x) != uint(xsign) { x.Neg(&x) } // Initialize the point P.initXY(&x.V, &y.V, c.self) if c.full { // If we're using the full group, // we just need any point on the curve, so we're done. return data[dl:] } // We're using the prime-order subgroup, // so we need to make sure the point is in that subgroup. // If we're not trying to embed data, // we can convert our point into one in the subgroup // simply by multiplying it by the cofactor. if data == nil { P.Mul(P, &c.cofact) // multiply by cofactor if P.Equal(c.null) { continue // unlucky; try again } return data[dl:] } // Since we need the point's y-coordinate to make sense, // we must simply check if the point is in the subgroup // and retry point generation until it is. if Q == nil { Q = c.self.Point() } Q.Mul(P, &c.order) if Q.Equal(c.null) { return data[dl:] } // Keep trying... } }
// 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 }
// Check the validity of the T coordinate func (P *extPoint) checkT() { var t1, t2 nist.Int if !t1.Mul(&P.X, &P.Y).Equal(t2.Mul(&P.Z, &P.T)) { panic("oops") } }
// Compute the square root function, // specified in section 5.5 of the Elligator paper. func (el *el2param) sqrt(r, a *nist.Int) { var b, b2 nist.Int b.Exp(a, &el.pp3d8) // b = a^((p+3)/8); b in {a,-a} b2.Mul(&b, &b) // b^2 = a? if !b2.Equal(a) { b.Mul(&b, &el.sqrtm1) // b*sqrt(-1) } if b.V.Cmp(&el.pm1d2) > 0 { // |b| b.Neg(&b) } r.Set(&b) }
// 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) }
// Test if a supposed point is on the curve, // by checking the characteristic equation for Edwards curves: // // a*x^2 + y^2 = 1 + d*x^2*y^2 // func (c *curve) onCurve(x, y *nist.Int) bool { var xx, yy, l, r nist.Int xx.Mul(x, x) // xx = x^2 yy.Mul(y, y) // yy = y^2 l.Mul(&c.a, &xx).Add(&l, &yy) // l = a*x^2 + y^2 r.Mul(&c.d, &xx).Mul(&r, &yy).Add(&c.one, &r) // r = 1 + d*x^2*y^2 return l.Equal(&r) }
// 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) }
// 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 }
func chi(r, v *nist.Int) { r.Init64(int64(math.Jacobi(&v.V, v.M)), v.M) }
// 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 }
// 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 }
// 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 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) }