diff --git a/README.md b/README.md
index 402924a..09077d3 100644
--- a/README.md
+++ b/README.md
@@ -2,13 +2,91 @@
# curve25519-dalek [](https://crates.io/crates/curve25519-dalek) [](https://docs.rs/curve25519-dalek) [](https://travis-ci.org/dalek-cryptography/curve25519-dalek)
-**A low-level cryptographic library for point, group, field, and scalar
-operations on a curve isomorphic to the twisted Edwards curve defined by -x²+y²
-= 1 - 121665/121666 x²y² over GF(2²⁵⁵ - 19).**
+**A pure-Rust implementation of group operations on Ristretto and Curve25519.**
+
+`curve25519-dalek` is a library providing group operations on the Edwards and
+Montgomery forms of Curve25519, and on the prime-order Ristretto group.
+
+`curve25519-dalek` is not intended to provide implementations of any particular
+crypto protocol. Rather, implementations of those protocols (such as
+[`x25519-dalek`][x25519-dalek] and [`ed25519-dalek`][ed25519-dalek]) should use
+`curve25519-dalek` as a library.
+
+`curve25519-dalek` is intended to provide a clean and safe _mid-level_ API for use
+implementing a wide range of ECC-based crypto protocols, such as key agreement,
+signatures, anonymous credentials, rangeproofs, and zero-knowledge proof
+systems.
+
+In particular, `curve25519-dalek` implements Ristretto, which constructs a
+prime-order group from a non-prime-order Edwards curve. This provides the
+speed and safety benefits of Edwards curve arithmetic, without the pitfalls of
+cofactor-related abstraction mismatches.
+
+## WARNING
+
+We do not yet consider this code to be production-ready. We intend to
+stabilize a production-ready version `1.0` soon.
+
+# Documentation
+
+The semver-stable, public-facing `curve25519-dalek` API is documented
+[here][docs-external]. In addition, the unstable internal implementation
+details are documented [here][docs-internal].
+
+The `curve25519-dalek` documentation requires a custom HTML header to include
+KaTeX for math support. Unfortunately `cargo doc` does not currently support
+this, but docs can be built using
+```sh
+make doc
+make doc-internal
+```
+
+# Use
+
+To import `curve25519-dalek`, add the following to the dependencies section of
+your project's `Cargo.toml`:
+```toml
+curve25519-dalek = "^0.14"
+```
+Then import the crate as:
+```rust,no_run
+extern crate curve25519_dalek;
+```
+
+# Backends and Features
+
+Curve arithmetic is implemented using one of the following backends:
+
+* a `u32` backend using `u64` products;
+* a `u64` backend using `u128` products, available using the `nightly` feature;
+* an experimental AVX2 backend, available using the `yolocrypto` feature when
+ compiling for a target with `target_feature=+avx2`.
+
+By default, the benchmarks are not compiled without the `bench`
+feature. Benchmarks can be run via:
+
+```sh
+cargo bench --features="bench" # u32 backend
+cargo bench --features="bench nightly" # u64 backend
+cargo bench --features="bench nightly yolocrypto" # u64 or avx2 if available
+```
+
+The `yolocrypto` feature enables experimental features. The name `yolocrypto`
+is meant to indicate that it is not considered production-ready, and we do not
+consider `yolocrypto` features to be covered by semver guarantees.
+
+# Contributing
+
+Please see [CONTRIBUTING.md][contributing].
+
+Patches and pull requests should be make against the `develop`
+branch, **not** `master`.
+
+# About
**SPOILER ALERT:** *The Twelfth Doctor's first encounter with the Daleks is in
his second full episode, "Into the Dalek". A beleaguered ship of the "Combined
@@ -23,65 +101,20 @@ universe's beauty, but also his deep hatred of the Daleks. Rusty destroys the
other Daleks and departs the ship, determined to track down and bring an end
to the Dalek race.*
-Significant portions of this code are ported from [Adam Langley's
-Golang ed25519 library](https://github.com/agl/ed25519), which is in
+`curve25519-dalek` is authored by Isis Agora Lovecruft and Henry de Valence.
+
+Portions of this library were originally a port of [Adam Langley's
+Golang ed25519 library](https://github.com/agl/ed25519), which was in
turn a port of the reference `ref10` implementation.
-## Warning
+The fast `u32` and `u64` scalar arithmetic was implemented by Andrew Moon, and
+the addition chain for scalar inversion was provided by Brian Smith.
-This code has **not** yet received sufficient peer review by other qualified
-cryptographers to be considered in any way, shape, or form, safe. Further,
-this library does **not** provide high-level routines such as encryption and
-decryption or signing and verification. Instead, it is a low-level library,
-intended for other cryptographers who would like to implement their own
-primitives using this curve. (For an example of how one would implement a
-signature scheme using this library, see
-[ed25519-dalek](https://github.com/dalek-cryptography/ed25519-dalek).)
+The `no_std` support was contributed by Tony Arcieri.
-**USE AT YOUR OWN RISK**
+Thanks also to Ashley Hauck, Lucas Salibian, and Manish Goregaokar for their
+contributions.
-## Documentation
-
-Extensive documentation is available [here](https://docs.rs/curve25519-dalek).
-
-# Installation
-
-To install, add the following to the dependencies section of your project's
-`Cargo.toml`:
-
-```toml
-curve25519-dalek = "^0.14"
-```
-
-Then, in your library or executable source, add:
-
- extern crate curve25519_dalek;
-
-## Features
-
-On nightly Rust, using the `nightly` feature enables a radix-51 field
-arithmetic implementation using `u128`s, which is approximately twice as
-fast. It will also enable additional developer documentation when
-compiling via `make doc-internal`.
-
-By default, the benchmarks are not compiled without the `bench`
-feature. To run the benchmarks, do:
-
-```sh
-cargo bench --features="bench"
-```
-
-## TODO
-
-We intend to stabilise the following before curve25519-dalek-1.0.0:
-
-* Implement hashing to a point on the curve (Elligator).
-* Finish Ristretto documentation.
-
-## Contributing
-
-Please see
-[CONTRIBUTING.md](https://github.com/dalek-cryptography/curve25519-dalek/blob/master/CONTRIBUTING.md).
-
-Patches and pull requests should be make against the `develop`
-branch, **not** `master`.
+[ed25519-dalek]: https://github.com/dalek-cryptography/ed25519-dalek
+[x25519-dalek]: https://github.com/dalek-cryptography/x25519-dalek
+[contributing]: https://github.com/dalek-cryptography/curve25519-dalek/blob/master/CONTRIBUTING.md
diff --git a/build.rs b/build.rs
index 6b6e652..1c8be62 100644
--- a/build.rs
+++ b/build.rs
@@ -80,11 +80,13 @@ use edwards::EdwardsBasepointTable;
use curve_models::window::LookupTable;
use curve_models::AffineNielsPoint;
-/// Table containing precomputed multiples of the basepoint `B = (x,4/5)`.
-///
-/// The table is defined so `constants::base[i][j-1] = j*(16^2i)*B`,
-/// for `0 ≤ i < 32`, `1 ≤ j < 9`.
-pub const ED25519_BASEPOINT_TABLE: EdwardsBasepointTable = {:?};
+
+/// Table containing precomputed multiples of the Ed25519 basepoint \\\\(B = (x, 4/5)\\\\).
+pub const ED25519_BASEPOINT_TABLE: EdwardsBasepointTable = ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN;
+
+/// Inner constant, used to avoid filling the docs with precomputed points.
+#[doc(hidden)]
+pub const ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = {:?};
\n\n", &table).as_bytes()).unwrap();
// Now generate AFFINE_ODD_MULTIPLES_OF_BASEPOINT
diff --git a/rustdoc-include-katex-header.html b/rustdoc-include-katex-header.html
index 695c735..455a58e 100644
--- a/rustdoc-include-katex-header.html
+++ b/rustdoc-include-katex-header.html
@@ -6,5 +6,5 @@ document.addEventListener("DOMContentLoaded", function() { renderMathInElement(d
diff --git a/src/backend/mod.rs b/src/backend/mod.rs
index 0e2ce3e..847b1fe 100644
--- a/src/backend/mod.rs
+++ b/src/backend/mod.rs
@@ -8,8 +8,7 @@
// - Isis Agora Lovecruft
// - Henry de Valence
-//! This module contains "backends" that contain different
-//! implementations of common code for different architectures.
+//! Pluggable implementations for different architectures.
//!
//! The naming of the `u32` and `u64` modules is somewhat unfortunate,
//! since these are also the names of primitive types. Since types have
diff --git a/src/backend/u32/constants.rs b/src/backend/u32/constants.rs
index 6c8fb8b..94702d7 100644
--- a/src/backend/u32/constants.rs
+++ b/src/backend/u32/constants.rs
@@ -81,24 +81,34 @@ pub(crate) const RR: Scalar32 = Scalar32([ 0x0b5f9d12, 0x1e141b17, 0x158d7f3d, 0
0x1972d781, 0x042feb7c, 0x1ceec73d, 0x1e184d1e,
0x0005046d ]);
+/// The Ed25519 basepoint, as an `EdwardsPoint`.
+///
+/// This is called `_POINT` to distinguish it from
+/// `ED25519_BASEPOINT_TABLE`, which should be used for scalar
+/// multiplication (it's much faster).
+pub const ED25519_BASEPOINT_POINT: EdwardsPoint = EdwardsPoint{
+ X: FieldElement32([52811034, 25909283, 16144682, 17082669, 27570973, 30858332, 40966398, 8378388, 20764389, 8758491]),
+ Y: FieldElement32([40265304, 26843545, 13421772, 20132659, 26843545, 6710886, 53687091, 13421772, 40265318, 26843545]),
+ Z: FieldElement32([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
+ T: FieldElement32([28827043, 27438313, 39759291, 244362, 8635006, 11264893, 19351346, 13413597, 16611511, 27139452]),
+};
+
+/// The 8-torsion subgroup \\(\mathcal E [8]\\).
+///
+/// In the case of Curve25519, it is cyclic; the \\(i\\)-th element of
+/// the array is \\([i]P\\), where \\(P\\) is a point of order \\(8\\)
+/// generating \\(\mathcal E[8]\\).
+///
+/// Thus \\(\mathcal E[8]\\) is the points indexed by `0,2,4,6`, and
+/// \\(\mathcal E[2]\\) is the points indexed by `0,4`.
/// The Ed25519 basepoint has y = 4/5. This is called `_POINT` to
/// distinguish it from `_TABLE`, which should be used for scalar
/// multiplication (it's much faster).
-pub const ED25519_BASEPOINT_POINT: EdwardsPoint = EdwardsPoint{
- X: FieldElement32([52811034, 25909283, 16144682, 17082669, 27570973, 30858332, 40966398, 8378388, 20764389, 8758491]),
- Y: FieldElement32([40265304, 26843545, 13421772, 20132659, 26843545, 6710886, 53687091, 13421772, 40265318, 26843545]),
- Z: FieldElement32([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
- T: FieldElement32([28827043, 27438313, 39759291, 244362, 8635006, 11264893, 19351346, 13413597, 16611511, 27139452]),
-};
+pub const EIGHT_TORSION: [EdwardsPoint; 8] = EIGHT_TORSION_INNER_DOC_HIDDEN;
-/// The 8-torsion subgroup Ɛ[8].
-///
-/// In the case of Curve25519, it is cyclic; the `i`th element of the
-/// array is `i*P`, where `P` is a point of order 8 generating Ɛ[8].
-///
-/// Thus Ɛ[4] is the points indexed by 0,2,4,6 and Ɛ[2] is the points
-/// indexed by 0,4.
-pub const EIGHT_TORSION: [EdwardsPoint; 8] = [
+/// Inner item used to hide limb constants from cargo doc output.
+#[doc(hidden)]
+pub const EIGHT_TORSION_INNER_DOC_HIDDEN: [EdwardsPoint; 8] = [
EdwardsPoint{
X: FieldElement32([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
Y: FieldElement32([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]),
diff --git a/src/backend/u64/constants.rs b/src/backend/u64/constants.rs
index 046e1dc..254c81c 100644
--- a/src/backend/u64/constants.rs
+++ b/src/backend/u64/constants.rs
@@ -54,8 +54,10 @@ pub(crate) const R: Scalar64 = Scalar64([ 0x000f48bd6721e6ed, 0x0003bab5ac67e45a
/// `RR` = (R^2) % L where R = 2^260
pub(crate) const RR: Scalar64 = Scalar64([ 0x0009d265e952d13b, 0x000d63c715bea69f, 0x0005be65cb687604, 0x0003dceec73d217f, 0x000009411b7c309a ]);
-/// The Ed25519 basepoint has y = 4/5. This is called `_POINT` to
-/// distinguish it from `_TABLE`, which should be used for scalar
+/// The Ed25519 basepoint, as an `EdwardsPoint`.
+///
+/// This is called `_POINT` to distinguish it from
+/// `ED25519_BASEPOINT_TABLE`, which should be used for scalar
/// multiplication (it's much faster).
pub const ED25519_BASEPOINT_POINT: EdwardsPoint = EdwardsPoint{
X: FieldElement64([1738742601995546, 1146398526822698, 2070867633025821, 562264141797630, 587772402128613]),
@@ -64,14 +66,19 @@ pub const ED25519_BASEPOINT_POINT: EdwardsPoint = EdwardsPoint{
T: FieldElement64([1841354044333475, 16398895984059, 755974180946558, 900171276175154, 1821297809914039]),
};
-/// The 8-torsion subgroup Ɛ[8].
+/// The 8-torsion subgroup \\(\mathcal E [8]\\).
///
-/// In the case of Curve25519, it is cyclic; the `i`th element of the
-/// array is `i*P`, where `P` is a point of order 8 generating Ɛ[8].
+/// In the case of Curve25519, it is cyclic; the \\(i\\)-th element of
+/// the array is \\([i]P\\), where \\(P\\) is a point of order \\(8\\)
+/// generating \\(\mathcal E[8]\\).
///
-/// Thus Ɛ[4] is the points indexed by 0,2,4,6 and Ɛ[2] is the points
-/// indexed by 0,4.
-pub const EIGHT_TORSION: [EdwardsPoint; 8] = [
+/// Thus \\(\mathcal E[8]\\) is the points indexed by `0,2,4,6`, and
+/// \\(\mathcal E[2]\\) is the points indexed by `0,4`.
+pub const EIGHT_TORSION: [EdwardsPoint; 8] = EIGHT_TORSION_INNER_DOC_HIDDEN;
+
+/// Inner item used to hide limb constants from cargo doc output.
+#[doc(hidden)]
+pub const EIGHT_TORSION_INNER_DOC_HIDDEN: [EdwardsPoint; 8] = [
EdwardsPoint {
X: FieldElement64([0, 0, 0, 0, 0]),
Y: FieldElement64([1, 0, 0, 0, 0]),
diff --git a/src/constants.rs b/src/constants.rs
index b4c4646..16edb4f 100644
--- a/src/constants.rs
+++ b/src/constants.rs
@@ -8,7 +8,7 @@
// - Isis Agora Lovecruft
// - Henry de Valence
-//! This module contains various constants, such as the Ristretto and Ed25519 basepoints.
+//! Various constants, such as the Ristretto and Ed25519 basepoints.
//!
//! Most of the constants are given with
//! `LONG_DESCRIPTIVE_UPPER_CASE_NAMES`, but they can be brought into
@@ -38,30 +38,36 @@ pub use backend::u64::constants::*;
#[cfg(not(feature="radix_51"))]
pub use backend::u32::constants::*;
-/// Basepoint has y = 4/5.
+/// The Ed25519 basepoint, in `CompressedEdwardsY` format.
///
-/// Generated with Sage: these are the bytes of 4/5 in 𝔽_p. The
-/// sign bit is 0 since the basepoint has x chosen to be positive.
-pub const BASE_CMPRSSD: CompressedEdwardsY =
+/// This is the little-endian byte encoding of \\( 4/5 \pmod p \\),
+/// which is the \\(y\\)-coordinate of the Ed25519 basepoint.
+///
+/// The sign bit is 0 since the basepoint has \\(x\\) chosen to be positive.
+pub const ED25519_BASEPOINT_COMPRESSED: CompressedEdwardsY =
CompressedEdwardsY([0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66]);
-/// The X25519 basepoint, in compressed Montgomery form.
-pub const BASE_COMPRESSED_MONTGOMERY: CompressedMontgomeryU =
+/// The X25519 basepoint, in `CompressedMontgomeryU` format.
+pub const X25519_BASEPOINT_COMPRESSED: CompressedMontgomeryU =
CompressedMontgomeryU([0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
-/// The Ed25519 basepoint, as a `RistrettoPoint`. This is called `_POINT` to distinguish it from
-/// `_TABLE`, which provides fast scalar multiplication.
+/// The Ristretto basepoint, as a `RistrettoPoint`.
+///
+/// This is called `_POINT` to distinguish it from `_TABLE`, which
+/// provides fast scalar multiplication.
pub const RISTRETTO_BASEPOINT_POINT: RistrettoPoint = RistrettoPoint(ED25519_BASEPOINT_POINT);
-/// `BASEPOINT_ORDER` is the order of base point, i.e. `l = 2^252 +
-/// 27742317777372353535851937790883648493`, in little-endian bytes.
+/// `BASEPOINT_ORDER` is the order of the Ristretto group and of the Ed25519 basepoint, i.e.,
+/// $$
+/// \ell = 2^\{252\} + 27742317777372353535851937790883648493.
+/// $$
pub const BASEPOINT_ORDER: Scalar = Scalar{
bytes: [
0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
@@ -71,26 +77,6 @@ pub const BASEPOINT_ORDER: Scalar = Scalar{
],
};
-/// `BASEPOINT_ORDER_MINUS_1` is the order of base point minus one, i.e. `l-1`, in little-endian bytes.
-pub const BASEPOINT_ORDER_MINUS_1: Scalar = Scalar{
- bytes: [
- 0xec, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
- 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
- ],
-};
-
-/// `BASEPOINT_ORDER_MINUS_2` is the order of base point minus two, i.e. `l-2`, in little-endian bytes.
-pub const BASEPOINT_ORDER_MINUS_2: Scalar = Scalar{
- bytes: [
- 0xeb, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58,
- 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
- ],
-};
-
// Precomputed basepoint table is generated into a file by build.rs
#[cfg(feature="precomputed_tables")]
@@ -98,7 +84,8 @@ include!(concat!(env!("OUT_DIR"), "/basepoint_table.rs"));
#[cfg(feature="precomputed_tables")]
use ristretto::RistrettoBasepointTable;
-/// The Ed25519 basepoint, as a RistrettoPoint
+
+/// The Ristretto basepoint, as a `RistrettoBasepointTable` for scalar multiplication.
#[cfg(feature="precomputed_tables")]
pub const RISTRETTO_BASEPOINT_TABLE: RistrettoBasepointTable
= RistrettoBasepointTable(ED25519_BASEPOINT_TABLE);
diff --git a/src/curve_models/mod.rs b/src/curve_models/mod.rs
index bc89d16..f9b29d8 100644
--- a/src/curve_models/mod.rs
+++ b/src/curve_models/mod.rs
@@ -8,8 +8,7 @@
// - Isis Agora Lovecruft
// - Henry de Valence
-//! This module contains internal curve representations which are not part
-//! of the public API.
+//! Internal curve representations which are not part of the public API.
//!
//! # Curve representations
//!
diff --git a/src/edwards.rs b/src/edwards.rs
index 4b130dc..8f95323 100644
--- a/src/edwards.rs
+++ b/src/edwards.rs
@@ -9,6 +9,77 @@
// - Henry de Valence
//! Group operations for Curve25519, in Edwards form.
+//!
+//! ## Encoding and Decoding
+//!
+//! Encoding is done by converting to and from a `CompressedEdwardsY`
+//! struct, which is a typed wrapper around `[u8; 32]`.
+//!
+//! ## Equality Testing
+//!
+//! The `EdwardsPoint` struct implements the `subtle::Equal` trait for
+//! constant-time equality checking, and the Rust `Eq` trait for
+//! variable-time equality checking.
+//!
+//! ## Cofactor-related functions
+//!
+//! The order of the group of points on the curve \\(\mathcal E\\)
+//! is \\(|\mathcal E| = 8\ell \\), so its structure is \\( \mathcal
+//! E = \mathcal E[8] \times \mathcal E[\ell]\\). The torsion
+//! subgroup \\( \mathcal E[8] \\) consists of eight points of small
+//! order. Technically, all of \\(\mathcal E\\) is torsion, but we
+//! use the word only to refer to the small \\(\mathcal E[8]\\) part, not
+//! the large prime-order \\(\mathcal E[\ell]\\) part.
+//!
+//! To test if a point is in \\( \mathcal E[8] \\), use
+//! `EdwardsPoint::is_small_order()`.
+//!
+//! To test if a point is in \\( \mathcal E[\ell] \\), use
+//! `EdwardsPoint::is_torsion_free()`.
+//!
+//! To multiply by the cofactor, use `EdwardsPoint::mult_by_cofactor()`.
+//!
+//! To avoid dealing with cofactors entirely, consider using Ristretto.
+//!
+//! ## Scalars
+//!
+//! Scalars are represented by the `Scalar` struct. To construct a scalar with a specific bit
+//! pattern, see `Scalar::from_bits()`.
+//!
+//! ## Scalar Multiplication
+//!
+//! Scalar multiplication on Edwards points is provided by:
+//!
+//! * the `*` operator between a `Scalar` and a `EdwardsPoint`, which
+//! performs constant-time variable-base scalar multiplication;
+//!
+//! * the `*` operator between a `Scalar` and a
+//! `EdwardsBasepointTable`, which performs constant-time fixed-base
+//! scalar multiplication;
+//!
+//! * the `edwards::multiscalar_mult` function, which performs
+//! constant-time variable-base multiscalar multiplication;
+//!
+//! * the `edwards::vartime::multiscalar_mult` function, which
+//! performs variable-time variable-base multiscalar multiplication.
+//!
+//! ## Implementation
+//!
+//! The Edwards arithmetic is implemented using the “extended twisted
+//! coordinates” of Hisil, Wong, Carter, and Dawson, and the
+//! corresponding complete formulas. For more details,
+//! see the `curve_models` submodule of the internal documentation.
+//!
+//! ## Validity Checking
+//!
+//! There is no function for checking whether a point is valid.
+//! Instead, the `EdwardsPoint` struct is guaranteed to hold a valid
+//! point on the curve.
+//!
+//! We use the Rust type system to make invalid points
+//! unrepresentable: `EdwardsPoint` objects can only be created via
+//! successful decompression of a compressed point, or else by
+//! operations on other (valid) `EdwardsPoint`s.
// We allow non snake_case names because coordinates in projective space are
// traditionally denoted by the capitalisation of their respective
@@ -690,14 +761,14 @@ impl EdwardsBasepointTable {
}
impl EdwardsPoint {
- /// Multiply by the cofactor: compute `8 * self`.
+ /// Multiply by the cofactor: return \\([8]P\\).
pub fn mult_by_cofactor(&self) -> EdwardsPoint {
self.mult_by_pow_2(3)
}
- /// Compute `2^k * self` by successive doublings.
- /// Requires `k > 0`.
+ /// Compute \\([2\^k] P \\) by successive doublings. Requires \\( k > 0 \\).
pub(crate) fn mult_by_pow_2(&self, k: u32) -> EdwardsPoint {
+ debug_assert!( k > 0 );
let mut r: CompletedPoint;
let mut s = self.to_projective();
for _ in 0..(k-1) {
@@ -709,22 +780,59 @@ impl EdwardsPoint {
/// Determine if this point is of small order.
///
- /// The order of the group of points on the curve \\(\mathcal E\\)
- /// is \\(|\mathcal E| = 8\ell \\), so its structure is \\( \mathcal
- /// E = \mathcal E[8] \times \mathcal E[\ell]\\). The torsion
- /// subgroup \\( \mathcal E[8] \\) consists of eight points of small
- /// order. (Technically all of \\(\mathcal E\\) is torsion, but we
- /// use the word only to refer to the \\(\mathcal E[8]\\) part, not
- /// the prime-order subgroup \\(\mathcal E[\ell]\\).
+ /// # Return
///
- /// For more information on cofactors and the group structure, see
- /// the internal `curve25519-dalek` documentation on Ristretto.
+ /// * `true` if `self` is in the torsion subgroup \\( \mathcal E[8] \\);
+ /// * `false` if `self` is not in the torsion subgroup \\( \mathcal E[8] \\).
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use curve25519_dalek::constants;
+ ///
+ /// // Generator of the prime-order subgroup
+ /// let P = constants::ED25519_BASEPOINT_POINT;
+ /// // Generator of the torsion subgroup
+ /// let Q = constants::EIGHT_TORSION[1];
+ ///
+ /// // P has large order
+ /// assert_eq!(P.is_small_order(), false);
+ ///
+ /// // Q has small order
+ /// assert_eq!(Q.is_small_order(), true);
+ /// ```
+ pub fn is_small_order(&self) -> bool {
+ self.mult_by_cofactor().is_identity()
+ }
+
+ /// Determine if this point is “torsion-free”, i.e., is contained in
+ /// the prime-order subgroup.
///
/// # Return
///
- /// True if `self` is of small order; false otherwise.
- pub fn is_small_order(&self) -> bool {
- self.mult_by_cofactor().is_identity()
+ /// * `true` if `self` has zero torsion component and is in the
+ /// prime-order subgroup;
+ /// * `false` if `self` has a nonzero torsion component and is not
+ /// in the prime-order subgroup.
+ ///
+ /// # Example
+ ///
+ /// ```
+ /// use curve25519_dalek::constants;
+ ///
+ /// // Generator of the prime-order subgroup
+ /// let P = constants::ED25519_BASEPOINT_POINT;
+ /// // Generator of the torsion subgroup
+ /// let Q = constants::EIGHT_TORSION[1];
+ ///
+ /// // P is torsion-free
+ /// assert_eq!(P.is_torsion_free(), true);
+ ///
+ /// // P + Q is not torsion-free
+ /// assert_eq!((P+Q).is_torsion_free(), false);
+ /// ```
+ pub fn is_torsion_free(&self) -> bool {
+ (self * &constants::BASEPOINT_ORDER).is_identity()
}
}
@@ -989,18 +1097,18 @@ mod test {
#[test]
fn basepoint_decompression_compression() {
let base_X = FieldElement::from_bytes(&BASE_X_COORD_BYTES);
- let bp = constants::BASE_CMPRSSD.decompress().unwrap();
+ let bp = constants::ED25519_BASEPOINT_COMPRESSED.decompress().unwrap();
assert!(bp.is_valid());
// Check that decompression actually gives the correct X coordinate
assert_eq!(base_X, bp.X);
- assert_eq!(bp.compress(), constants::BASE_CMPRSSD);
+ assert_eq!(bp.compress(), constants::ED25519_BASEPOINT_COMPRESSED);
}
/// Test sign handling in decompression
#[test]
fn decompression_sign_handling() {
// Manually set the high bit of the last byte to flip the sign
- let mut minus_basepoint_bytes = constants::BASE_CMPRSSD.as_bytes().clone();
+ let mut minus_basepoint_bytes = constants::ED25519_BASEPOINT_COMPRESSED.as_bytes().clone();
minus_basepoint_bytes[31] |= 1 << 7;
let minus_basepoint = CompressedEdwardsY(minus_basepoint_bytes)
.decompress().unwrap();
@@ -1018,7 +1126,7 @@ mod test {
fn basepoint_mult_one_vs_basepoint() {
let bp = &constants::ED25519_BASEPOINT_TABLE * &Scalar::one();
let compressed = bp.compress();
- assert_eq!(compressed, constants::BASE_CMPRSSD);
+ assert_eq!(compressed, constants::ED25519_BASEPOINT_COMPRESSED);
}
/// Test that `EdwardsBasepointTable::basepoint()` gives the correct basepoint.
@@ -1026,7 +1134,7 @@ mod test {
#[cfg(feature="precomputed_tables")]
fn basepoint_table_basepoint_function_correct() {
let bp = constants::ED25519_BASEPOINT_TABLE.basepoint();
- assert_eq!(bp.compress(), constants::BASE_CMPRSSD);
+ assert_eq!(bp.compress(), constants::ED25519_BASEPOINT_COMPRESSED);
}
/// Test `impl Add for EdwardsPoint`
@@ -1139,7 +1247,7 @@ mod test {
fn basepoint_projective_extended_round_trip() {
assert_eq!(constants::ED25519_BASEPOINT_POINT
.to_projective().to_extended().compress(),
- constants::BASE_CMPRSSD);
+ constants::ED25519_BASEPOINT_COMPRESSED);
}
/// Test computing 16*basepoint vs mult_by_pow_2(4)
@@ -1262,7 +1370,7 @@ mod test {
fn serde_cbor_basepoint_roundtrip() {
let output = serde_cbor::to_vec(&constants::ED25519_BASEPOINT_POINT).unwrap();
let parsed: EdwardsPoint = serde_cbor::from_slice(&output).unwrap();
- assert_eq!(parsed.compress(), constants::BASE_CMPRSSD);
+ assert_eq!(parsed.compress(), constants::ED25519_BASEPOINT_COMPRESSED);
}
#[test]
@@ -1291,7 +1399,7 @@ mod bench {
#[bench]
fn edwards_decompress(b: &mut Bencher) {
- let B = &constants::BASE_CMPRSSD;
+ let B = &constants::ED25519_BASEPOINT_COMPRESSED;
b.iter(|| B.decompress().unwrap());
}
diff --git a/src/lib.rs b/src/lib.rs
index 0baf368..7df436c 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -9,29 +9,22 @@
// - Henry de Valence
#![cfg_attr(not(feature = "std"), no_std)]
+
#![cfg_attr(feature = "alloc", feature(alloc))]
-#![cfg_attr(feature = "nightly", feature(i128_type))]
-#![cfg_attr(feature = "nightly", feature(cfg_target_feature))]
#![cfg_attr(feature = "bench", feature(test))]
-#![deny(missing_docs)] // refuse to compile if documentation is missing
+#![cfg_attr(feature = "nightly", feature(i128_type))]
+#![cfg_attr(feature = "nightly", feature(cfg_target_feature))]
+#![cfg_attr(feature = "nightly", feature(external_doc))]
-//! # curve25519-dalek
-//!
-//! **A high-performance, pure-Rust implementation of group operations for Ristretto and Curve25519.**
-//!
-//! **[SPOILER ALERT]** The Twelfth Doctor's first encounter with the Daleks is
-//! in his second full episode, "Into the Dalek". A beleaguered ship of the
-//! "Combined Galactic Resistance" has discovered a broken Dalek that has
-//! turned "good", desiring to kill all other Daleks. The Doctor, Clara and a
-//! team of soldiers are miniaturized and enter the Dalek, which the Doctor
-//! names Rusty. They repair the damage, but accidentally restore it to its
-//! original nature, causing it to go on the rampage and alert the Dalek fleet
-//! to the whereabouts of the rebel ship. However, the Doctor manages to
-//! return Rusty to its previous state by linking his mind with the Dalek's:
-//! Rusty shares the Doctor's view of the universe's beauty, but also his deep
-//! hatred of the Daleks. Rusty destroys the other Daleks and departs the
-//! ship, determined to track down and bring an end to the Dalek race.
+// Refuse to compile if documentation is missing, but only on nightly.
+//
+// This means that missing docs will still fail CI, but means we can use
+// README.md as the crate documentation.
+#![cfg_attr(feature = "nightly", deny(missing_docs))]
+
+#![cfg_attr(feature = "nightly", doc(include = "../README.md"))]
+#![doc(html_logo_url = "https://user-images.githubusercontent.com/797/34898472-83686016-f7f3-11e7-967b-24b2aadd623a.png")]
//------------------------------------------------------------------------
// External dependencies:
diff --git a/src/montgomery.rs b/src/montgomery.rs
index a71e8a8..c7406ef 100644
--- a/src/montgomery.rs
+++ b/src/montgomery.rs
@@ -395,7 +395,7 @@ impl<'a, 'b> Mul<&'b MontgomeryPoint> for &'a Scalar {
#[cfg(test)]
mod test {
- use constants::BASE_COMPRESSED_MONTGOMERY;
+ use constants::X25519_BASEPOINT_COMPRESSED;
use traits::Identity;
use super::*;
@@ -405,14 +405,14 @@ mod test {
#[test]
fn basepoint_to_montgomery() {
assert_eq!(constants::ED25519_BASEPOINT_POINT.to_montgomery().compress(),
- BASE_COMPRESSED_MONTGOMERY);
+ X25519_BASEPOINT_COMPRESSED);
}
/// Test Montgomery conversion against the X25519 basepoint.
#[test]
fn basepoint_from_montgomery() {
- assert_eq!(BASE_COMPRESSED_MONTGOMERY,
- constants::BASE_CMPRSSD.decompress().unwrap().to_montgomery().compress());
+ assert_eq!(X25519_BASEPOINT_COMPRESSED,
+ constants::ED25519_BASEPOINT_COMPRESSED.decompress().unwrap().to_montgomery().compress());
}
/// If u = -1, then v^2 = u*(u^2+486662*u+1) = 486660.
@@ -438,8 +438,8 @@ mod test {
#[test]
fn projective_to_affine_roundtrips() {
- assert_eq!(BASE_COMPRESSED_MONTGOMERY.decompress().compress(),
- BASE_COMPRESSED_MONTGOMERY);
+ assert_eq!(X25519_BASEPOINT_COMPRESSED.decompress().compress(),
+ X25519_BASEPOINT_COMPRESSED);
}
@@ -483,7 +483,7 @@ mod test {
#[test]
fn ladder_basepoint_times_two_matches_double() {
let two: Scalar = Scalar::from_u64(2u64);
- let result: MontgomeryPoint = &BASE_COMPRESSED_MONTGOMERY.decompress() * &two;
+ let result: MontgomeryPoint = &X25519_BASEPOINT_COMPRESSED.decompress() * &two;
let expected: EdwardsPoint = constants::ED25519_BASEPOINT_POINT.double();
assert_eq!(result.compress(), expected.to_montgomery().compress());
@@ -495,7 +495,7 @@ mod test {
mod bench {
use rand::OsRng;
use constants::ED25519_BASEPOINT_TABLE;
- use constants::BASE_COMPRESSED_MONTGOMERY;
+ use constants::X25519_BASEPOINT_COMPRESSED;
use test::Bencher;
use super::*;
@@ -512,12 +512,12 @@ mod bench {
#[bench]
fn montgomery_decompress(b: &mut Bencher) {
- b.iter(| | BASE_COMPRESSED_MONTGOMERY.decompress());
+ b.iter(| | X25519_BASEPOINT_COMPRESSED.decompress());
}
#[bench]
fn montgomery_compress(b: &mut Bencher) {
- let p: MontgomeryPoint = BASE_COMPRESSED_MONTGOMERY.decompress();
+ let p: MontgomeryPoint = X25519_BASEPOINT_COMPRESSED.decompress();
b.iter(| | p.compress());
}
diff --git a/src/ristretto.rs b/src/ristretto.rs
index 67f183a..a7564be 100644
--- a/src/ristretto.rs
+++ b/src/ristretto.rs
@@ -8,37 +8,101 @@
// - Isis Agora Lovecruft
// - Henry de Valence
+// We allow non snake_case names because coordinates in projective space are
+// traditionally denoted by the capitalisation of their respective
+// counterparts in affine space. Yeah, you heard me, rustc, I'm gonna have my
+// affine and projective cakes and eat both of them too.
+#![allow(non_snake_case)]
+
//! An implementation of Ristretto, which provides a prime-order group.
//!
-//! Ristretto is a modification of Mike Hamburg's [Decaf
-//! cofactor-eliminating point-compression
-//! scheme](https://eprint.iacr.org/2015/673.pdf) to work on top of the
-//! Curve25519 group.
+//! # The Ristretto Group
//!
-//! Below are some notes on Ristretto, which are *NOT* a full writeup and which may have errors.
-//!
-//! # Notes on Ristretto
-//!
-//! ## Decaf
-//!
-//! The introduction of the Decaf paper, [_Decaf: Eliminating cofactors
-//! through point compression_](https://eprint.iacr.org/2015/673.pdf)
-//! notes that while most cryptographic systems require a group of prime
-//! order, most concrete implementations using elliptic curve groups
-//! fall short -- they either provide a group of prime order, but with
-//! incomplete or variable-time addition formulae (for instance, most
-//! Weierstrass models), or else they provide a fast and safe
-//! implementation of a group whose order is not quite a prime \\(q\\),
-//! but \\(hq\\) for a small cofactor \\(h\\) (for instance, Edwards
-//! curves, which have cofactor at least \\(4\\)).
+//! Ristretto is a modification of Mike Hamburg's Decaf scheme to work
+//! with Curve25519. The introduction of the Decaf paper, [_Decaf:
+//! Eliminating cofactors through point
+//! compression_](https://eprint.iacr.org/2015/673.pdf), notes that while
+//! most cryptographic systems require a group of prime order, most
+//! concrete implementations using elliptic curve groups fall short --
+//! they either provide a group of prime order, but with incomplete or
+//! variable-time addition formulae (for instance, most Weierstrass
+//! models), or else they provide a fast and safe implementation of a
+//! group whose order is not quite a prime \\(q\\), but \\(hq\\) for a
+//! small cofactor \\(h\\) (for instance, Edwards curves, which have
+//! cofactor at least \\(4\\)).
//!
//! This abstraction mismatch requires ad-hoc protocol modifications to
//! ensure security; these modifications require careful analysis and
-//! are a recurring source of vulnerabilities.
+//! are a recurring source of [vulnerabilities][cryptonote] and [design
+//! complications][ed25519_hkd].
+//!
+//! Instead, Ristretto uses a quotient group to implement a prime-order
+//! group using a non-prime-order curve. More details are described in
+//! the *Implementation* section below. Ristretto points are provided
+//! in `curve25519-dalek` by the `RistrettoPoint` struct.
+//!
+//! ## Encoding and Decoding
+//!
+//! Encoding is done by converting to and from a `CompressedRistretto`
+//! struct, which is a typed wrapper around `[u8; 32]`.
+//!
+//! The encoding is not batchable, but it is possible to
+//! double-and-encode in a batch using
+//! `RistrettoPoint::double_and_compress_batch`.
+//!
+//! ## Equality Testing
+//!
+//! Testing equality of points on an Edwards curve in projective
+//! coordinates requires an expensive inversion. By contrast, equality
+//! checking in the Ristretto group can be done in projective
+//! coordinates without requiring an inversion, so it is much faster.
+//!
+//! The `RistrettoPoint` struct implements the `subtle::Equal` trait for
+//! constant-time equality checking, and the Rust `Eq` trait for
+//! variable-time equality checking.
+//!
+//! ## Scalars
+//!
+//! Scalars are represented by the `Scalar` struct. Each scalar has a
+//! canonical representative mod the group order; see
+//! `Scalar::from_canonical_bytes()` and `Scalar::is_canonical()`.
+//!
+//! ## Scalar Multiplication
+//!
+//! Scalar multiplication on Ristretto points is provided by:
+//!
+//! * the `*` operator between a `Scalar` and a `RistrettoPoint`, which
+//! performs constant-time variable-base scalar multiplication;
+//!
+//! * the `*` operator between a `Scalar` and a
+//! `RistrettoBasepointTable`, which performs constant-time fixed-base
+//! scalar multiplication;
+//!
+//! * the `ristretto::multiscalar_mult` function, which performs
+//! constant-time variable-base multiscalar multiplication;
+//!
+//! * the `ristretto::vartime::multiscalar_mult` function, which
+//! performs variable-time variable-base multiscalar multiplication.
+//!
+//! ## Random Points and Hashing to Ristretto
+//!
+//! The Ristretto group comes equipped with an Elligator map. This is
+//! used to implement
+//!
+//! * `RistrettoPoint::random()`, which generates random points from an
+//! RNG;
+//!
+//! * `RistrettoPoint::from_hash()` and
+//! `RistrettoPoint::hash_from_bytes()`, which perform hashing to the
+//! group.
+//!
+//! The Elligator map itself is not currently exposed.
+//!
+//! ## Implementation
//!
//! The Decaf suggestion is to use a quotient group, such as \\(\mathcal
//! E / \mathcal E[4]\\) or \\(2 \mathcal E / \mathcal E[2] \\), to
-//! implement a prime-order group.
+//! implement a prime-order group using a non-prime-order curve.
//!
//! This requires only changing
//!
@@ -61,8 +125,25 @@
//! explains the name: Decaf is named "after the procedure which divides
//! the effect of coffee by \\(4\\)". However, Curve25519 has a
//! cofactor of \\(8\\). To eliminate its cofactor, we tweak Decaf to
-//! restrict further. This gives the
-//! [Ristretto](https://en.wikipedia.org/wiki/Ristretto) encoding.
+//! restrict further. This [additional restriction][ristretto_coffee]
+//! gives the _Ristretto_ encoding.
+//!
+//! Notes on the details of the encoding can be found in the
+//! `ristretto::notes` submodule of the internal `curve25519-dalek`
+//! documentation.
+//!
+//! [cryptonote]:
+//! https://moderncrypto.org/mail-archive/curves/2017/000898.html
+//! [ed25519_hkd]:
+//! https://moderncrypto.org/mail-archive/curves/2017/000858.html
+//! [ristretto_coffee]:
+//! https://en.wikipedia.org/wiki/Ristretto
+
+mod notes {
+
+//! Below are some notes on Ristretto, which are *NOT* a full writeup and which may have errors.
+//!
+//! # Notes on Ristretto
//!
//! ## The Jacobi Quartic
//!
@@ -379,11 +460,7 @@
//!
//! ## ???
-// We allow non snake_case names because coordinates in projective space are
-// traditionally denoted by the capitalisation of their respective
-// counterparts in affine space. Yeah, you heard me, rustc, I'm gonna have my
-// affine and projective cakes and eat both of them too.
-#![allow(non_snake_case)]
+}
use core::fmt::Debug;
@@ -419,29 +496,31 @@ use traits::Identity;
// Compressed points
// ------------------------------------------------------------------------
-/// A point serialized using Mike Hamburg's Ristretto scheme.
+/// A Ristretto point, in compressed wire format.
///
-/// XXX think about how this API should work
+/// The Ristretto encoding is canonical, so two points are equal if and
+/// only if their encodings are equal.
#[derive(Copy, Clone, Eq, PartialEq)]
pub struct CompressedRistretto(pub [u8; 32]);
-/// The result of compressing a `RistrettoPoint`.
impl CompressedRistretto {
- /// Convert this `CompressedRistretto` to its underlying array of bytes.
+ /// Copy the bytes of this `CompressedRistretto`.
pub fn to_bytes(&self) -> [u8; 32] {
self.0
}
/// View this `CompressedRistretto` as an array of bytes.
- pub fn as_bytes<'a>(&'a self) -> &'a [u8; 32] {
+ pub fn as_bytes(&self) -> &[u8; 32] {
&self.0
}
/// Attempt to decompress to an `RistrettoPoint`.
///
- /// This function executes in constant time for all valid inputs.
- /// Inputs which do not decode to a RistrettoPoint may return
- /// early.
+ /// # Return
+ ///
+ /// - `Some(RistrettoPoint)` if `self` was the canonical encoding of a point;
+ ///
+ /// - `None` if `self` was not the canonical encoding of a point.
pub fn decompress(&self) -> Option {
// Step 1. Check s for validity:
// 1.a) s must be 32 bytes (we get this from the type system)
@@ -562,75 +641,17 @@ impl<'de> Deserialize<'de> for RistrettoPoint {
/// prime-order group as a quotient group of a subgroup of (the
/// Edwards form of) Curve25519.
///
-/// Internally, a `RistrettoPoint` is a wrapper type around
-/// `EdwardsPoint`, with custom equality, compression, and
-/// decompression routines to account for the quotient.
+/// Internally, a `RistrettoPoint` is implemented as a wrapper type
+/// around `EdwardsPoint`, with custom equality, compression, and
+/// decompression routines to account for the quotient. This means that
+/// operations on `RistrettoPoint`s are exactly as fast as operations on
+/// `EdwardsPoint`s.
+///
#[derive(Copy, Clone)]
pub struct RistrettoPoint(pub(crate) EdwardsPoint);
impl RistrettoPoint {
- /// Compress in Ristretto format.
- ///
- /// # Implementation Notes
- ///
- /// The Ristretto encoding is as follows, on input in affine coordinates `(x,y)`:
- ///
- /// 1. If `xy` is negative or `x = 0`, "rotate" the point by
- /// setting `(x,y) = (iy, ix)`.
- /// 2. If `x` is negative, set `(x,y) = (-x, -y)`.
- /// 3. Compute `s = +sqrt((1-y)/(1+y))`.
- /// 4. Return the little-endian 32-byte encoding of `s`.
- ///
- /// However, our input is in extended twisted Edwards coordinates
- /// `(X:Y:Z:T)` with `x = X/Z`, `y = Y/Z`, `xy = T/Z` (see the
- /// module-level documentation on curve representations for more
- /// details). Since inversions are expensive, we'd like to be
- /// able to do this whole computation with only one inversion.
- ///
- /// Since `y = Y/Z`, in extended coordinates the formula for `s` becomes
- ///
- /// s = sqrt((1 - Y/Z)/(1 + Y/Z)) = sqrt((Z-Y)/(Z+Y)). (1)
- ///
- /// We can compute this as
- ///
- /// s = (Z - Y) / sqrt((Z-Y)(Z+Y)). (1)
- ///
- /// The denominator is
- ///
- /// invsqrt((Z-Y)(Z+Y)) = invsqrt(Z² - Y²). (1)
- ///
- /// Write the input point as `(X₀:Y₀:Z₀:T₀)`. The rotation in
- /// step 1 of the encoding procedure replaces `(X₀:Y₀:Z₀:T₀)` by
- /// `(iY₀:iX₀:Z₀:-T₀)`. We therefore wish to relate the
- /// computation of
- ///
- /// invsqrt(Z² - Y²) = invsqrt(Z₀² - Y₀²) [non-rotated case]
- ///
- /// with the computation of
- ///
- /// invsqrt(Z² - Y²) = invsqrt(Z₀² + X₀²). [rotated case]
- ///
- /// Recall the curve equation (in the 𝗣² model):
- ///
- /// (-X² + Y²)Z² = Z⁴ + dX²Y². (1)
- ///
- /// This means that, for any point `(X:Y:Z:T)` in extended coordinates, we have
- ///
- /// -dX²Y² = Z⁴ + Z²X² - Z²Y², (2)
- ///
- /// so that
- ///
- /// (-1-d)X²Y² = Z⁴ + Z²X² - Z²Y² - X²Y², (3)
- ///
- /// and hence
- ///
- /// (-1-d)X²Y² = (Z² - Y²)(Z² + X²). (4)
- ///
- /// Taking inverse square roots gives
- ///
- /// invsqrt(Z² + X²) = invsqrt(-1-d) sqrt((Z² - Y²)/(X²Y²)). (4)
- ///
- ///
+ /// Compress this point using the Ristretto encoding.
pub fn compress(&self) -> CompressedRistretto {
let mut X = self.0.X;
let mut Y = self.0.Y;
@@ -666,7 +687,37 @@ impl RistrettoPoint {
CompressedRistretto(s.to_bytes())
}
- /// Double-and-compress a batch of points.
+ /// Double-and-compress a batch of points. The Ristretto encoding
+ /// is not batchable, since it requires an inverse square root.
+ ///
+ /// However, given input points \\( P\_1, \ldots, P\_n, \\)
+ /// it is possible to compute the encodings of their doubles \\(
+ /// \mathrm{enc}( [2]P\_1), \ldots, \mathrm{enc}( [2]P\_n ) \\)
+ /// in a batch.
+ ///
+ /// This function has optimal performance when the batch size is a
+ /// power of two, but this is not a requirement.
+ ///
+ /// ```
+ /// # extern crate curve25519_dalek;
+ /// # use curve25519_dalek::ristretto::RistrettoPoint;
+ /// extern crate rand;
+ /// use rand::OsRng;
+ ///
+ /// # // Need fn main() here in comment so the doctest compiles
+ /// # // See https://doc.rust-lang.org/book/documentation.html#documentation-as-tests
+ /// # fn main() {
+ /// let mut rng = OsRng::new().unwrap();
+ /// let points: Vec =
+ /// (0..32).map(|_| RistrettoPoint::random(&mut rng)).collect();
+ ///
+ /// let compressed = RistrettoPoint::double_and_compress_batch(&points);
+ ///
+ /// for (P, P2_compressed) in points.iter().zip(compressed.iter()) {
+ /// assert_eq!(*P2_compressed, (P + P).compress());
+ /// }
+ /// # }
+ /// ```
#[cfg(any(feature = "alloc", feature = "std"))]
pub fn double_and_compress_batch<'a, I>(points: I) -> Vec
where I: IntoIterator-
@@ -762,7 +813,7 @@ impl RistrettoPoint {
///
/// This method is not public because it's just used for hashing
/// to a point -- proper elligator support is deferred for now.
- pub fn elligator_ristretto_flavour(r_0: &FieldElement) -> RistrettoPoint {
+ pub(crate) fn elligator_ristretto_flavour(r_0: &FieldElement) -> RistrettoPoint {
let (i, d) = (&constants::SQRT_M1, &constants::EDWARDS_D);
let one = FieldElement::one();
@@ -781,7 +832,7 @@ impl RistrettoPoint {
// s = sqrt(N/D) if N/D is square
s.conditional_assign(&maybe_s, N_over_D_is_square);
- // XXX how do we reuse the computation of sqrt(N/D) to find sqrt(rN/D) ?
+ // XXX how exactly do we reuse the computation of sqrt(N/D) to find sqrt(rN/D) ?
let (rN_over_D_is_square, mut maybe_s) = FieldElement::sqrt_ratio(&(&r*&N), &D);
maybe_s.negate();
@@ -999,15 +1050,18 @@ define_mul_variants!(LHS = RistrettoPoint, RHS = Scalar, Output = RistrettoPoint
define_mul_variants!(LHS = Scalar, RHS = RistrettoPoint, Output = RistrettoPoint);
-/// Given a vector of (possibly secret) scalars and a vector of
-/// (possibly secret) points, compute `c_1 P_1 + ... + c_n P_n`.
+/// Given an iterator of (possibly secret) scalars and an iterator of
+/// (possibly secret) points, compute
+/// $$
+/// Q = c\_1 P\_1 + \cdots + c\_n P\_n.
+/// $$
///
/// This function has the same behaviour as
/// `vartime::multiscalar_mult` but is constant-time.
///
/// # Input
///
-/// An iterable of `Scalar`s and a iterable of `DecafPoints`. It is an
+/// An iterable of `Scalar`s and a iterable of `RistrettoPoints`. It is an
/// error to call this function with two iterators of different lengths.
#[cfg(any(feature = "alloc", feature = "std"))]
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> RistrettoPoint
@@ -1018,9 +1072,10 @@ pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> RistrettoPoint
RistrettoPoint(edwards::multiscalar_mult(scalars, extended_points))
}
-/// Precomputation
+/// A precomputed table of multiples of a basepoint, used to accelerate
+/// scalar multiplication.
#[derive(Clone)]
-pub struct RistrettoBasepointTable(pub EdwardsBasepointTable);
+pub struct RistrettoBasepointTable(pub(crate) EdwardsBasepointTable);
impl<'a, 'b> Mul<&'b Scalar> for &'a RistrettoBasepointTable {
type Output = RistrettoPoint;
@@ -1114,15 +1169,16 @@ pub mod vartime {
//! Variable-time operations on ristretto points, useful for non-secret data.
use super::*;
- /// Given a vector of public scalars and a vector of (possibly secret)
+ /// Given an iterable of public scalars and an iterable of public
/// points, compute
- ///
- /// c_1 P_1 + ... + c_n P_n.
+ /// $$
+ /// Q = c\_1 P\_1 + \cdots + c\_n P\_n.
+ /// $$
///
/// # Input
///
- /// A vector of `Scalar`s and a vector of `RistrettoPoints`. It is an
- /// error to call this function with two vectors of different lengths.
+ /// A iterable of `Scalar`s and a iterable of `RistrettoPoints`. It is an
+ /// error to call this function with two iterators of different lengths.
#[cfg(any(feature = "alloc", feature = "std"))]
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> RistrettoPoint
where I: IntoIterator
- ,
diff --git a/src/scalar.rs b/src/scalar.rs
index 64a59bc..72b2b01 100644
--- a/src/scalar.rs
+++ b/src/scalar.rs
@@ -790,12 +790,6 @@ mod test {
assert_eq!(should_be_two, two);
}
- #[test]
- fn impl_sub() {
- let should_be_one = &constants::BASEPOINT_ORDER - &constants::BASEPOINT_ORDER_MINUS_1;
- assert_eq!(should_be_one, Scalar::one());
- }
-
#[allow(non_snake_case)]
#[test]
fn impl_mul() {