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.
// 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
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.
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.
- Panic when reading randomness fails.
- Add Point.ConditionalSet() and Scalar.ConditionalSet().
- Add Scalar.SetUint64().
- 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.
- 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.
-
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 ofCompletedPoint.SetRistrettoElligator2()
.