// 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 }
// 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... } }