예제 #1
0
파일: curve.go 프로젝트: LegoShrimp/crypto
// 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...
	}
}