Skip to content

bwesterb/go-ristretto

Repository files navigation

go-ristretto

Many cryptographic schemes need a group of prime order. Popular and efficient elliptic curves like (Edwards25519 of ed25519 fame) are rarely of prime order. There is, however, a convenient method to construct a prime order group from such curves, called Ristretto proposed by Mike Hamburg.

This is a pure Go implementation of the group operations on the Ristretto prime-order group built from Edwards25519. Documentation is on godoc.

Example: El'Gamal encryption

// Generate an El'Gamal keypair
var secretKey ristretto.Scalar
var publicKey ristretto.Point

secretKey.Rand() // generate a new secret key
publicKey.ScalarMultBase(&secretKey) // compute public key

// El'Gamal encrypt a random curve point p into a ciphertext-pair (c1,c2)
var p ristretto.Point
var r ristretto.Scalar
var c1 ristretto.Point
var c2 ristretto.Point
p.Rand()
r.Rand()
c2.ScalarMultBase(&r)
c1.PublicScalarMult(&publicKey, &r)
c1.Add(&c1, &p)

// Decrypt (c1,c2) back to p
var blinding, p2 ristretto.Point
blinding.ScalarMult(&c2, &secretKey)
p2.Sub(&c1, &blinding)

fmt.Printf("%v", bytes.Equal(p.Bytes(), p2.Bytes()))
// Output:
// true

Compatibility with ristretto255 RFC draft

An RFC has been proposed to standardise Ristretto over Ed25519. This RFC is compatible with go-ristretto. There is one caveat: one should use Point.DeriveDalek instead of Point.Derive to derive a point from a string.

References

The curve and Ristretto implementation is based on the unpublished PandA library by Chuengsatiansup, Ribarski and Schwabe, see cref/cref.c. The old generic radix 25.5 field operations borrow from Adam Langley's ed25519. The amd64 optimized field arithmetic are from George Tankersley's ed25519 patch, which in turn is based on SUPERCOP's amd64-51-30k by Bernstein, Duif, Lange, Schwabe and Yang. The new generic radix 51 field operations are also based on amd64-51-30k. The variable-time scalar multiplication code is based on that of curve25519-dalek. The Lizard encoding was proposed by Bram Westerbaan. The quick RistrettoElligator inversion for it is joint work with Bram Westerbaan and Mike Hamburg.

other platforms

Changes

1.2.3 (16-03-2023)

  • Panic when reading randomness fails.

1.2.2 (29-07-2022)

  • Add Point.ConditionalSet() and Scalar.ConditionalSet().

1.2.1 (08-11-2021)

  • Add Scalar.SetUint64().

1.2.0 (17-02-2021)

  • Add Point.Double(). See issue #21.
  • To align more closely with the RFC, Point.SetBytes() and Point.UnmarshalBinary() will now reject points with non-canonical encodings. See #20.

1.1.1 (24-09-2019)

  • Only use bits.Add64 from Go 1.13 onwards to make sure we're constant-time on non-amd64 platforms. Thanks @Yawning; see issue #17.

1.1.0 (13-05-2019)

  • Add support for the Lizard 16-bytes-to-point-injection. See ristretto.Point.{SetLizard(), Lizard(),LizardInto()}.

  • Add Scalar.DeriveShort() to derive a half-length scalar. (Warning: half-length scalars are unsafe in almost every application.)

  • (internal) Add ExtendedPoint.RistrettoElligator2Inverse() to compute all preimages of a given point up-to Ristretto equivalence of CompletedPoint.SetRistrettoElligator2().