mirror of
https://github.com/saymrwulf/betrusted-curve25519-dalek-source.git
synced 2026-09-06 20:41:11 +00:00
Merge remote-tracking branch 'hdevalence/feature/refactor-docs' into develop
This commit is contained in:
commit
5f1320bb3b
13 changed files with 486 additions and 298 deletions
155
README.md
155
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)
|
||||
|
||||
<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
|
||||
|
|
|
|||
12
build.rs
12
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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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]),
|
||||
|
|
|
|||
|
|
@ -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]),
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
//!
|
||||
|
|
|
|||
154
src/edwards.rs
154
src/edwards.rs
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
|||
31
src/lib.rs
31
src/lib.rs
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
286
src/ristretto.rs
286
src/ristretto.rs
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
Loading…
Reference in a new issue