Merge remote-tracking branch 'hdevalence/feature/refactor-docs' into develop

This commit is contained in:
Isis Lovecruft 2018-01-31 02:11:46 +00:00
commit 5f1320bb3b
Failed to extract signature
13 changed files with 486 additions and 298 deletions

155
README.md
View file

@ -2,13 +2,91 @@
# curve25519-dalek [![](https://img.shields.io/crates/v/curve25519-dalek.svg)](https://crates.io/crates/curve25519-dalek) [![](https://docs.rs/curve25519-dalek/badge.svg)](https://docs.rs/curve25519-dalek) [![](https://travis-ci.org/dalek-cryptography/curve25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/curve25519-dalek)
<img
width="50%"
width="33%"
align="right"
src="https://user-images.githubusercontent.com/797/34898472-83686016-f7f3-11e7-967b-24b2aadd623a.png"/>
**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

View file

@ -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

View file

@ -6,5 +6,5 @@ document.addEventListener("DOMContentLoaded", function() { renderMathInElement(d
</script>
<style>
.katex { font-size: 1em !important; }
.docblock code, .dockblock-short code { font-size: 0.85em !important; }
pre.rust, .docblock code, .docblock-short code { font-size: 0.85em !important; }
</style>

View file

@ -8,8 +8,7 @@
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! 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

View file

@ -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]),

View file

@ -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]),

View file

@ -8,7 +8,7 @@
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! 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);

View file

@ -8,8 +8,7 @@
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
//! 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
//!

View file

@ -9,6 +9,77 @@
// - Henry de Valence <hdevalence@hdevalence.ca>
//! 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<EdwardsPoint> 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());
}

View file

@ -9,29 +9,22 @@
// - Henry de Valence <hdevalence@hdevalence.ca>
#![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:

View file

@ -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());
}

View file

@ -8,37 +8,101 @@
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
// - Henry de Valence <hdevalence@hdevalence.ca>
// 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<RistrettoPoint> {
// 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)). <span style="float: right">(1)</span>
///
/// We can compute this as
///
/// s = (Z - Y) / sqrt((Z-Y)(Z+Y)). <span style="float: right">(1)</span>
///
/// The denominator is
///
/// invsqrt((Z-Y)(Z+Y)) = invsqrt(Z² - Y²). <span style="float: right">(1)</span>
///
/// 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². <span style="float: right">(1)</span>
///
/// This means that, for any point `(X:Y:Z:T)` in extended coordinates, we have
///
/// -dX²Y² = Z⁴ + Z²X² - Z²Y², <span style="float: right">(2)</span>
///
/// so that
///
/// (-1-d)X²Y² = Z⁴ + Z²X² - Z²Y² - X²Y², <span style="float: right">(3)</span>
///
/// and hence
///
/// (-1-d)X²Y² = (Z² - Y²)(Z² + X²). <span style="float: right">(4)</span>
///
/// Taking inverse square roots gives
///
/// invsqrt(Z² + X²) = invsqrt(-1-d) sqrt((Z² - Y²)/(X²Y²)). <span style="float: right">(4)</span>
///
///
/// 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<RistrettoPoint> =
/// (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<CompressedRistretto>
where I: IntoIterator<Item = &'a RistrettoPoint>
@ -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<Item = &'a Scalar>,

View file

@ -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() {