// ScalarMult returns k*(Bx,By) where k is a number in big-endian form. This // uses the repeated doubling method, which is variable time. // TODO use a constant time method to prevent side channel attacks. func (curve *TwistedEdwardsCurve) ScalarMult(x1, y1 *big.Int, k []byte) (x, y *big.Int) { // Convert the scalar to a big int. s := new(big.Int).SetBytes(k) // Get a new group element to do cached doubling // calculations in. dEGE := new(edwards25519.ExtendedGroupElement) dEGE.Zero() // Use the doubling method for the multiplication. // p := given point // q := point(zero) // for each bit in the scalar, descending: // double(q) // if bit == 1: // add(q, p) // return q // // Note that the addition is skipped for zero bits, // making this variable time and thus vulnerable to // side channel attack vectors. for i := s.BitLen() - 1; i >= 0; i-- { dCGE := new(edwards25519.CompletedGroupElement) dEGE.Double(dCGE) dCGE.ToExtended(dEGE) if s.Bit(i) == 1 { ss := new([32]byte) dEGE.ToBytes(ss) var err error xi, yi, err := curve.EncodedBytesToBigIntPoint(ss) if err != nil { return nil, nil } xAdd, yAdd := curve.Add(xi, yi, x1, y1) dTempBytes := BigIntPointToEncodedBytes(xAdd, yAdd) dEGE.FromBytes(dTempBytes) } } finalBytes := new([32]byte) dEGE.ToBytes(finalBytes) var err error x, y, err = curve.EncodedBytesToBigIntPoint(finalBytes) if err != nil { return nil, nil } return }
// Double adds the same pair of big integer coordinates to itself on the // elliptical curve. func (curve *TwistedEdwardsCurve) Double(x1, y1 *big.Int) (x, y *big.Int) { // Convert to extended projective coordinates. a := BigIntPointToEncodedBytes(x1, y1) aEGE := new(edwards25519.ExtendedGroupElement) aEGE.FromBytes(a) r := new(edwards25519.CompletedGroupElement) aEGE.Double(r) rEGE := new(edwards25519.ExtendedGroupElement) r.ToExtended(rEGE) s := new([32]byte) rEGE.ToBytes(s) x, y, _ = curve.EncodedBytesToBigIntPoint(s) return }
// Add adds two points represented by pairs of big integers on the elliptical // curve. func (curve *TwistedEdwardsCurve) Add(x1, y1, x2, y2 *big.Int) (x, y *big.Int) { // Convert to extended from affine. a := BigIntPointToEncodedBytes(x1, y1) aEGE := new(edwards25519.ExtendedGroupElement) aEGE.FromBytes(a) b := BigIntPointToEncodedBytes(x2, y2) bEGE := new(edwards25519.ExtendedGroupElement) bEGE.FromBytes(b) // Cache b for use in group element addition. bCached := new(cachedGroupElement) toCached(bCached, bEGE) p := aEGE q := bCached // geAdd(r*CompletedGroupElement, p*ExtendedGroupElement, // q*CachedGroupElement) // r is the result. r := new(edwards25519.CompletedGroupElement) var t0 edwards25519.FieldElement edwards25519.FeAdd(&r.X, &p.Y, &p.X) edwards25519.FeSub(&r.Y, &p.Y, &p.X) edwards25519.FeMul(&r.Z, &r.X, &q.yPlusX) edwards25519.FeMul(&r.Y, &r.Y, &q.yMinusX) edwards25519.FeMul(&r.T, &q.T2d, &p.T) edwards25519.FeMul(&r.X, &p.Z, &q.Z) edwards25519.FeAdd(&t0, &r.X, &r.X) edwards25519.FeSub(&r.X, &r.Z, &r.Y) edwards25519.FeAdd(&r.Y, &r.Z, &r.Y) edwards25519.FeAdd(&r.Z, &t0, &r.T) edwards25519.FeSub(&r.T, &t0, &r.T) rEGE := new(edwards25519.ExtendedGroupElement) r.ToExtended(rEGE) s := new([32]byte) rEGE.ToBytes(s) x, y, _ = curve.EncodedBytesToBigIntPoint(s) return }