mirror of
https://github.com/saymrwulf/curve25519-dalek-source.git
synced 2026-09-06 20:41:14 +00:00
Rename Decaf to Ristretto
This commit is contained in:
parent
3f52aa4df2
commit
58a55117be
4 changed files with 177 additions and 186 deletions
|
|
@ -20,7 +20,7 @@
|
||||||
|
|
||||||
use edwards::CompressedEdwardsY;
|
use edwards::CompressedEdwardsY;
|
||||||
#[cfg(feature = "yolocrypto")]
|
#[cfg(feature = "yolocrypto")]
|
||||||
use decaf::{DecafPoint, DecafBasepointTable};
|
use ristretto::{RistrettoPoint, RistrettoBasepointTable};
|
||||||
use montgomery::CompressedMontgomeryU;
|
use montgomery::CompressedMontgomeryU;
|
||||||
use scalar::Scalar;
|
use scalar::Scalar;
|
||||||
|
|
||||||
|
|
@ -61,10 +61,10 @@ pub const BASE_COMPRESSED_MONTGOMERY: CompressedMontgomeryU =
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]);
|
||||||
|
|
||||||
|
|
||||||
/// The Ed25519 basepoint, as a `DecafPoint`. This is called `_POINT` to distinguish it from
|
/// The Ed25519 basepoint, as a `RistrettoPoint`. This is called `_POINT` to distinguish it from
|
||||||
/// `_TABLE`, which provides fast scalar multiplication.
|
/// `_TABLE`, which provides fast scalar multiplication.
|
||||||
#[cfg(feature = "yolocrypto")] pub const DECAF_ED25519_BASEPOINT_POINT: DecafPoint =
|
#[cfg(feature = "yolocrypto")]
|
||||||
DecafPoint(ED25519_BASEPOINT_POINT);
|
pub const RISTRETTO_BASEPOINT_POINT: RistrettoPoint = RistrettoPoint(ED25519_BASEPOINT_POINT);
|
||||||
|
|
||||||
/// `l` is the order of base point, i.e. 2^252 +
|
/// `l` is the order of base point, i.e. 2^252 +
|
||||||
/// 27742317777372353535851937790883648493, in little-endian form
|
/// 27742317777372353535851937790883648493, in little-endian form
|
||||||
|
|
@ -88,9 +88,9 @@ pub const l_minus_2: Scalar = Scalar([ 0xeb, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 ]);
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10 ]);
|
||||||
|
|
||||||
#[cfg(feature = "yolocrypto")]
|
#[cfg(feature = "yolocrypto")]
|
||||||
/// The Ed25519 basepoint
|
/// The Ed25519 basepoint, as a RistrettoPoint
|
||||||
pub const DECAF_ED25519_BASEPOINT_TABLE: DecafBasepointTable
|
pub const RISTRETTO_BASEPOINT_TABLE: RistrettoBasepointTable
|
||||||
= DecafBasepointTable(ED25519_BASEPOINT_TABLE);
|
= RistrettoBasepointTable(ED25519_BASEPOINT_TABLE);
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
|
|
||||||
|
|
@ -1269,8 +1269,6 @@ pub mod vartime {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
#[cfg(feature = "yolocrypto")]
|
|
||||||
use decaf::DecafPoint;
|
|
||||||
use field::FieldElement;
|
use field::FieldElement;
|
||||||
use scalar::Scalar;
|
use scalar::Scalar;
|
||||||
use subtle::ConditionallyAssignable;
|
use subtle::ConditionallyAssignable;
|
||||||
|
|
@ -1550,18 +1548,6 @@ mod test {
|
||||||
assert!(P1.compress().to_bytes() == P2.compress().to_bytes());
|
assert!(P1.compress().to_bytes() == P2.compress().to_bytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[cfg(feature = "yolocrypto")]
|
|
||||||
fn scalarmult_decafpoint_works_both_ways() {
|
|
||||||
let P: DecafPoint = DecafPoint(constants::ED25519_BASEPOINT_POINT);
|
|
||||||
let s: Scalar = A_SCALAR;
|
|
||||||
|
|
||||||
let P1 = &P * &s;
|
|
||||||
let P2 = &s * &P;
|
|
||||||
|
|
||||||
assert!(P1.compress().as_bytes() == P2.compress().as_bytes());
|
|
||||||
}
|
|
||||||
|
|
||||||
mod vartime {
|
mod vartime {
|
||||||
use super::super::*;
|
use super::super::*;
|
||||||
use super::{A_SCALAR, B_SCALAR, A_TIMES_BASEPOINT, DOUBLE_SCALAR_MULT_RESULT};
|
use super::{A_SCALAR, B_SCALAR, A_TIMES_BASEPOINT, DOUBLE_SCALAR_MULT_RESULT};
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@ pub mod montgomery;
|
||||||
|
|
||||||
// Feature gate decaf while our implementation is unfinished and probably incorrect.
|
// Feature gate decaf while our implementation is unfinished and probably incorrect.
|
||||||
#[cfg(feature = "yolocrypto")]
|
#[cfg(feature = "yolocrypto")]
|
||||||
pub mod decaf;
|
pub mod ristretto;
|
||||||
|
|
||||||
// Other miscelaneous utilities.
|
// Other miscelaneous utilities.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
|
||||||
// - Henry de Valence <hdevalence@hdevalence.ca>
|
// - Henry de Valence <hdevalence@hdevalence.ca>
|
||||||
|
|
||||||
//! An implementation of Mike Hamburg's Decaf cofactor-eliminating
|
//! An implementation of Mike Hamburg's Ristretto cofactor-eliminating
|
||||||
//! point-compression scheme, providing a prime-order group on top of
|
//! point-compression scheme, providing a prime-order group on top of
|
||||||
//! a non-prime-order elliptic curve.
|
//! a non-prime-order elliptic curve.
|
||||||
//!
|
//!
|
||||||
|
|
@ -50,26 +50,21 @@ use subtle::ConditionallyNegatable;
|
||||||
// Compressed points
|
// Compressed points
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
/// A point serialized using Mike Hamburg's Decaf scheme.
|
/// A point serialized using Mike Hamburg's Ristretto scheme.
|
||||||
///
|
///
|
||||||
/// XXX think about how this API should work
|
/// XXX think about how this API should work
|
||||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
pub struct CompressedDecaf(pub [u8; 32]);
|
pub struct CompressedRistretto(pub [u8; 32]);
|
||||||
|
|
||||||
/// The result of compressing a `DecafPoint`.
|
/// The result of compressing a `RistrettoPoint`.
|
||||||
impl CompressedDecaf {
|
impl CompressedRistretto {
|
||||||
/// Convert this `CompressedDecaf` to an array of bytes.
|
/// View this `CompressedRistretto` as an array of bytes.
|
||||||
pub fn to_bytes(&self) -> [u8; 32] {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
/// View this `CompressedDecaf` as an array of bytes.
|
|
||||||
pub fn as_bytes<'a>(&'a self) -> &'a [u8; 32] {
|
pub fn as_bytes<'a>(&'a self) -> &'a [u8; 32] {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to decompress to an `DecafPoint`.
|
/// Attempt to decompress to an `RistrettoPoint`.
|
||||||
pub fn decompress(&self) -> Option<DecafPoint> {
|
pub fn decompress(&self) -> Option<RistrettoPoint> {
|
||||||
// XXX should decoding be CT ?
|
// XXX should decoding be CT ?
|
||||||
// XXX need to check that xy is nonnegative and reject otherwise
|
// XXX need to check that xy is nonnegative and reject otherwise
|
||||||
let s = FieldElement::from_bytes(self.as_bytes());
|
let s = FieldElement::from_bytes(self.as_bytes());
|
||||||
|
|
@ -116,25 +111,25 @@ impl CompressedDecaf {
|
||||||
// Use the value of 1/Z previously computed in the batch inversion
|
// Use the value of 1/Z previously computed in the batch inversion
|
||||||
let xy = &T * &Zinv;
|
let xy = &T * &Zinv;
|
||||||
if (Y.is_nonzero() & xy.is_nonnegative_decaf()) == 1u8 {
|
if (Y.is_nonzero() & xy.is_nonnegative_decaf()) == 1u8 {
|
||||||
Some(DecafPoint(ExtendedPoint{ X: X, Y: Y, Z: Z, T: T }))
|
Some(RistrettoPoint(ExtendedPoint{ X: X, Y: Y, Z: Z, T: T }))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Identity for CompressedDecaf {
|
impl Identity for CompressedRistretto {
|
||||||
fn identity() -> CompressedDecaf {
|
fn identity() -> CompressedRistretto {
|
||||||
CompressedDecaf([0u8; 32])
|
CompressedRistretto([0u8; 32])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Serde support
|
// Serde support
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Serializes to and from `DecafPoint` directly, doing compression
|
// Serializes to and from `RistrettoPoint` directly, doing compression
|
||||||
// and decompression internally. This means that users can create
|
// and decompression internally. This means that users can create
|
||||||
// structs containing `DecafPoint`s and use Serde's derived
|
// structs containing `RistrettoPoint`s and use Serde's derived
|
||||||
// serializers to serialize those structures.
|
// serializers to serialize those structures.
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
|
|
@ -143,7 +138,7 @@ use serde::{self, Serialize, Deserialize, Serializer, Deserializer};
|
||||||
use serde::de::Visitor;
|
use serde::de::Visitor;
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
impl Serialize for DecafPoint {
|
impl Serialize for RistrettoPoint {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where S: Serializer
|
where S: Serializer
|
||||||
{
|
{
|
||||||
|
|
@ -152,25 +147,25 @@ impl Serialize for DecafPoint {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
impl<'de> Deserialize<'de> for DecafPoint {
|
impl<'de> Deserialize<'de> for RistrettoPoint {
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where D: Deserializer<'de>
|
where D: Deserializer<'de>
|
||||||
{
|
{
|
||||||
struct DecafPointVisitor;
|
struct RistrettoPointVisitor;
|
||||||
|
|
||||||
impl<'de> Visitor<'de> for DecafPointVisitor {
|
impl<'de> Visitor<'de> for RistrettoPointVisitor {
|
||||||
type Value = DecafPoint;
|
type Value = RistrettoPoint;
|
||||||
|
|
||||||
fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||||
formatter.write_str("a valid point in Decaf format")
|
formatter.write_str("a valid point in Ristretto format")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_bytes<E>(self, v: &[u8]) -> Result<DecafPoint, E>
|
fn visit_bytes<E>(self, v: &[u8]) -> Result<RistrettoPoint, E>
|
||||||
where E: serde::de::Error
|
where E: serde::de::Error
|
||||||
{
|
{
|
||||||
if v.len() == 32 {
|
if v.len() == 32 {
|
||||||
let arr32 = array_ref!(v, 0, 32); // &[u8;32] from &[u8]
|
let arr32 = array_ref!(v, 0, 32); // &[u8;32] from &[u8]
|
||||||
CompressedDecaf(*arr32)
|
CompressedRistretto(*arr32)
|
||||||
.decompress()
|
.decompress()
|
||||||
.ok_or(serde::de::Error::custom("decompression failed"))
|
.ok_or(serde::de::Error::custom("decompression failed"))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -179,7 +174,7 @@ impl<'de> Deserialize<'de> for DecafPoint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
deserializer.deserialize_bytes(DecafPointVisitor)
|
deserializer.deserialize_bytes(RistrettoPointVisitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -191,11 +186,11 @@ impl<'de> Deserialize<'de> for DecafPoint {
|
||||||
///
|
///
|
||||||
// XXX think about how this API should work
|
// XXX think about how this API should work
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct DecafPoint(pub ExtendedPoint);
|
pub struct RistrettoPoint(pub ExtendedPoint);
|
||||||
|
|
||||||
impl DecafPoint {
|
impl RistrettoPoint {
|
||||||
/// Compress in Decaf format.
|
/// Compress in Ristretto format.
|
||||||
pub fn compress(&self) -> CompressedDecaf {
|
pub fn compress(&self) -> CompressedRistretto {
|
||||||
// Q: Do we want to encode twisted or untwisted?
|
// Q: Do we want to encode twisted or untwisted?
|
||||||
//
|
//
|
||||||
// Notes:
|
// Notes:
|
||||||
|
|
@ -205,7 +200,7 @@ impl DecafPoint {
|
||||||
//
|
//
|
||||||
// Internally, we operate on the curve with a = -1, d =
|
// Internally, we operate on the curve with a = -1, d =
|
||||||
// -121665/121666, a.k.a., the twist. But maybe we would like
|
// -121665/121666, a.k.a., the twist. But maybe we would like
|
||||||
// to use Decaf on the untwisted curve with a = 1, d =
|
// to use Ristretto on the untwisted curve with a = 1, d =
|
||||||
// 121665/121666. (why? interop?)
|
// 121665/121666. (why? interop?)
|
||||||
//
|
//
|
||||||
// Fix i, a square root of -1 (mod p).
|
// Fix i, a square root of -1 (mod p).
|
||||||
|
|
@ -215,7 +210,7 @@ impl DecafPoint {
|
||||||
// let untwisted_X = &self.X * &constants::MSQRT_M1;
|
// let untwisted_X = &self.X * &constants::MSQRT_M1;
|
||||||
// etc.
|
// etc.
|
||||||
//
|
//
|
||||||
// Step 0: pre-rotation, needed for Decaf with E[8] = Z/8.
|
// Step 0: pre-rotation, needed for Ristretto with E[8] = Z/8.
|
||||||
//
|
//
|
||||||
// We want to select a point (x,y) in the coset P + E[4] with
|
// We want to select a point (x,y) in the coset P + E[4] with
|
||||||
// y nonzero and xy nonnegative. The naive approach is as
|
// y nonzero and xy nonnegative. The naive approach is as
|
||||||
|
|
@ -341,7 +336,7 @@ impl DecafPoint {
|
||||||
let mut s = &u * &(&(&r * &(&minus_ZX - &dYT)) + &Y);
|
let mut s = &u * &(&(&r * &(&minus_ZX - &dYT)) + &Y);
|
||||||
let neg = s.is_negative_decaf();
|
let neg = s.is_negative_decaf();
|
||||||
s.conditional_negate(neg);
|
s.conditional_negate(neg);
|
||||||
CompressedDecaf(s.to_bytes())
|
CompressedRistretto(s.to_bytes())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the coset self + E[4], for debugging.
|
/// Return the coset self + E[4], for debugging.
|
||||||
|
|
@ -359,7 +354,7 @@ impl DecafPoint {
|
||||||
///
|
///
|
||||||
/// This method is not public because it's just used for hashing
|
/// This method is not public because it's just used for hashing
|
||||||
/// to a point -- proper elligator support is deferred for now.
|
/// to a point -- proper elligator support is deferred for now.
|
||||||
pub fn elligator_decaf_flavour(r_0: &FieldElement) -> DecafPoint {
|
pub fn elligator_decaf_flavour(r_0: &FieldElement) -> RistrettoPoint {
|
||||||
// Follows Appendix C of the Decaf paper.
|
// Follows Appendix C of the Decaf paper.
|
||||||
// Use n = 2 as the quadratic nonresidue so that n*x = x + x.
|
// Use n = 2 as the quadratic nonresidue so that n*x = x + x.
|
||||||
let minus_one = -&FieldElement::one();
|
let minus_one = -&FieldElement::one();
|
||||||
|
|
@ -418,10 +413,10 @@ impl DecafPoint {
|
||||||
};
|
};
|
||||||
|
|
||||||
// Convert to extended and return.
|
// Convert to extended and return.
|
||||||
DecafPoint(P.to_extended())
|
RistrettoPoint(P.to_extended())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a `DecafPoint` chosen uniformly at random using a user-provided RNG.
|
/// Return a `RistrettoPoint` chosen uniformly at random using a user-provided RNG.
|
||||||
///
|
///
|
||||||
/// # Inputs
|
/// # Inputs
|
||||||
///
|
///
|
||||||
|
|
@ -429,21 +424,21 @@ impl DecafPoint {
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
/// A random element of the Decaf group.
|
/// A random element of the Ristretto group.
|
||||||
///
|
///
|
||||||
/// # Implementation
|
/// # Implementation
|
||||||
///
|
///
|
||||||
/// Uses the Decaf-flavoured Elligator 2 map, so that the discrete log of the
|
/// Uses the Ristretto-flavoured Elligator 2 map, so that the discrete log of the
|
||||||
/// output point with respect to any other point should be unknown.
|
/// output point with respect to any other point should be unknown.
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub fn random<T: Rng>(rng: &mut T) -> Self {
|
pub fn random<T: Rng>(rng: &mut T) -> Self {
|
||||||
let mut field_bytes = [0u8; 32];
|
let mut field_bytes = [0u8; 32];
|
||||||
rng.fill_bytes(&mut field_bytes);
|
rng.fill_bytes(&mut field_bytes);
|
||||||
let r_0 = FieldElement::from_bytes(&field_bytes);
|
let r_0 = FieldElement::from_bytes(&field_bytes);
|
||||||
DecafPoint::elligator_decaf_flavour(&r_0)
|
RistrettoPoint::elligator_decaf_flavour(&r_0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Hash a slice of bytes into a `DecafPoint`.
|
/// Hash a slice of bytes into a `RistrettoPoint`.
|
||||||
///
|
///
|
||||||
/// Takes a type parameter `D`, which is any `Digest` producing 32
|
/// Takes a type parameter `D`, which is any `Digest` producing 32
|
||||||
/// bytes (256 bits) of output.
|
/// bytes (256 bits) of output.
|
||||||
|
|
@ -452,14 +447,14 @@ impl DecafPoint {
|
||||||
///
|
///
|
||||||
/// # Implementation
|
/// # Implementation
|
||||||
///
|
///
|
||||||
/// Uses the Decaf-flavoured Elligator 2 map, so that the discrete log of the
|
/// Uses the Ristretto-flavoured Elligator 2 map, so that the discrete log of the
|
||||||
/// output point with respect to any other point should be unknown.
|
/// output point with respect to any other point should be unknown.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// # extern crate curve25519_dalek;
|
/// # extern crate curve25519_dalek;
|
||||||
/// # use curve25519_dalek::decaf::DecafPoint;
|
/// # use curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
/// extern crate sha2;
|
/// extern crate sha2;
|
||||||
/// use sha2::Sha256;
|
/// use sha2::Sha256;
|
||||||
///
|
///
|
||||||
|
|
@ -467,37 +462,37 @@ impl DecafPoint {
|
||||||
/// # // See https://doc.rust-lang.org/book/documentation.html#documentation-as-tests
|
/// # // See https://doc.rust-lang.org/book/documentation.html#documentation-as-tests
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let msg = "To really appreciate architecture, you may even need to commit a murder";
|
/// let msg = "To really appreciate architecture, you may even need to commit a murder";
|
||||||
/// let P = DecafPoint::hash_from_bytes::<Sha256>(msg.as_bytes());
|
/// let P = RistrettoPoint::hash_from_bytes::<Sha256>(msg.as_bytes());
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
pub fn hash_from_bytes<D>(input: &[u8]) -> DecafPoint
|
pub fn hash_from_bytes<D>(input: &[u8]) -> RistrettoPoint
|
||||||
where D: Digest<OutputSize = U32> + Default
|
where D: Digest<OutputSize = U32> + Default
|
||||||
{
|
{
|
||||||
let mut hash = D::default();
|
let mut hash = D::default();
|
||||||
hash.input(input);
|
hash.input(input);
|
||||||
DecafPoint::from_hash(hash)
|
RistrettoPoint::from_hash(hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a `DecafPoint` from an existing `Digest` instance.
|
/// Construct a `RistrettoPoint` from an existing `Digest` instance.
|
||||||
///
|
///
|
||||||
/// Use this instead of `hash_from_bytes` if it is more convenient
|
/// Use this instead of `hash_from_bytes` if it is more convenient
|
||||||
/// to stream data into the `Digest` than to pass a single byte
|
/// to stream data into the `Digest` than to pass a single byte
|
||||||
/// slice.
|
/// slice.
|
||||||
pub fn from_hash<D>(hash: D) -> DecafPoint
|
pub fn from_hash<D>(hash: D) -> RistrettoPoint
|
||||||
where D: Digest<OutputSize = U32> + Default
|
where D: Digest<OutputSize = U32> + Default
|
||||||
{
|
{
|
||||||
// XXX this seems clumsy
|
// XXX this seems clumsy
|
||||||
let mut output = [0u8; 32];
|
let mut output = [0u8; 32];
|
||||||
output.copy_from_slice(hash.result().as_slice());
|
output.copy_from_slice(hash.result().as_slice());
|
||||||
let r_0 = FieldElement::from_bytes(&output);
|
let r_0 = FieldElement::from_bytes(&output);
|
||||||
DecafPoint::elligator_decaf_flavour(&r_0)
|
RistrettoPoint::elligator_decaf_flavour(&r_0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Identity for DecafPoint {
|
impl Identity for RistrettoPoint {
|
||||||
fn identity() -> DecafPoint {
|
fn identity() -> RistrettoPoint {
|
||||||
DecafPoint(ExtendedPoint::identity())
|
RistrettoPoint(ExtendedPoint::identity())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -507,77 +502,77 @@ impl Identity for DecafPoint {
|
||||||
|
|
||||||
/// XXX check whether there's a simple way to do equality checking
|
/// XXX check whether there's a simple way to do equality checking
|
||||||
/// with cofactor 8, not just cofactor 4, and add a CT equality function?
|
/// with cofactor 8, not just cofactor 4, and add a CT equality function?
|
||||||
impl PartialEq for DecafPoint {
|
impl PartialEq for RistrettoPoint {
|
||||||
fn eq(&self, other: &DecafPoint) -> bool {
|
fn eq(&self, other: &RistrettoPoint) -> bool {
|
||||||
let self_compressed = self.compress();
|
let self_compressed = self.compress();
|
||||||
let other_compressed = other.compress();
|
let other_compressed = other.compress();
|
||||||
self_compressed == other_compressed
|
self_compressed == other_compressed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Eq for DecafPoint {}
|
impl Eq for RistrettoPoint {}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Arithmetic
|
// Arithmetic
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
impl<'a, 'b> Add<&'b DecafPoint> for &'a DecafPoint {
|
impl<'a, 'b> Add<&'b RistrettoPoint> for &'a RistrettoPoint {
|
||||||
type Output = DecafPoint;
|
type Output = RistrettoPoint;
|
||||||
|
|
||||||
fn add(self, other: &'b DecafPoint) -> DecafPoint {
|
fn add(self, other: &'b RistrettoPoint) -> RistrettoPoint {
|
||||||
DecafPoint(&self.0 + &other.0)
|
RistrettoPoint(&self.0 + &other.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> AddAssign<&'b DecafPoint> for DecafPoint {
|
impl<'b> AddAssign<&'b RistrettoPoint> for RistrettoPoint {
|
||||||
fn add_assign(&mut self, _rhs: &DecafPoint) {
|
fn add_assign(&mut self, _rhs: &RistrettoPoint) {
|
||||||
*self = (self as &DecafPoint) + _rhs;
|
*self = (self as &RistrettoPoint) + _rhs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> Sub<&'b DecafPoint> for &'a DecafPoint {
|
impl<'a, 'b> Sub<&'b RistrettoPoint> for &'a RistrettoPoint {
|
||||||
type Output = DecafPoint;
|
type Output = RistrettoPoint;
|
||||||
|
|
||||||
fn sub(self, other: &'b DecafPoint) -> DecafPoint {
|
fn sub(self, other: &'b RistrettoPoint) -> RistrettoPoint {
|
||||||
DecafPoint(&self.0 - &other.0)
|
RistrettoPoint(&self.0 - &other.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> SubAssign<&'b DecafPoint> for DecafPoint {
|
impl<'b> SubAssign<&'b RistrettoPoint> for RistrettoPoint {
|
||||||
fn sub_assign(&mut self, _rhs: &DecafPoint) {
|
fn sub_assign(&mut self, _rhs: &RistrettoPoint) {
|
||||||
*self = (self as &DecafPoint) - _rhs;
|
*self = (self as &RistrettoPoint) - _rhs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Neg for &'a DecafPoint {
|
impl<'a> Neg for &'a RistrettoPoint {
|
||||||
type Output = DecafPoint;
|
type Output = RistrettoPoint;
|
||||||
|
|
||||||
fn neg(self) -> DecafPoint {
|
fn neg(self) -> RistrettoPoint {
|
||||||
DecafPoint(-&self.0)
|
RistrettoPoint(-&self.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> MulAssign<&'b Scalar> for DecafPoint {
|
impl<'b> MulAssign<&'b Scalar> for RistrettoPoint {
|
||||||
fn mul_assign(&mut self, scalar: &'b Scalar) {
|
fn mul_assign(&mut self, scalar: &'b Scalar) {
|
||||||
let result = (self as &DecafPoint) * scalar;
|
let result = (self as &RistrettoPoint) * scalar;
|
||||||
*self = result;
|
*self = result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> Mul<&'b Scalar> for &'a DecafPoint {
|
impl<'a, 'b> Mul<&'b Scalar> for &'a RistrettoPoint {
|
||||||
type Output = DecafPoint;
|
type Output = RistrettoPoint;
|
||||||
/// Scalar multiplication: compute `scalar * self`.
|
/// Scalar multiplication: compute `scalar * self`.
|
||||||
fn mul(self, scalar: &'b Scalar) -> DecafPoint {
|
fn mul(self, scalar: &'b Scalar) -> RistrettoPoint {
|
||||||
DecafPoint(&self.0 * scalar)
|
RistrettoPoint(&self.0 * scalar)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> Mul<&'b DecafPoint> for &'a Scalar {
|
impl<'a, 'b> Mul<&'b RistrettoPoint> for &'a Scalar {
|
||||||
type Output = DecafPoint;
|
type Output = RistrettoPoint;
|
||||||
|
|
||||||
/// Scalar multiplication: compute `self * scalar`.
|
/// Scalar multiplication: compute `self * scalar`.
|
||||||
fn mul(self, point: &'b DecafPoint) -> DecafPoint {
|
fn mul(self, point: &'b RistrettoPoint) -> RistrettoPoint {
|
||||||
DecafPoint(self * &point.0)
|
RistrettoPoint(self * &point.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -589,46 +584,46 @@ impl<'a, 'b> Mul<&'b DecafPoint> for &'a Scalar {
|
||||||
///
|
///
|
||||||
/// # Input
|
/// # Input
|
||||||
///
|
///
|
||||||
/// A vector of `Scalar`s and a vector of `DecafPoints`. It is an
|
/// An iterable of `Scalar`s and a iterable of `DecafPoints`. It is an
|
||||||
/// error to call this function with two vectors of different lengths.
|
/// error to call this function with two iterators of different lengths.
|
||||||
#[cfg(any(feature = "alloc", feature = "std"))]
|
#[cfg(any(feature = "alloc", feature = "std"))]
|
||||||
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> DecafPoint
|
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> RistrettoPoint
|
||||||
where I: IntoIterator<Item = &'a Scalar>,
|
where I: IntoIterator<Item = &'a Scalar>,
|
||||||
J: IntoIterator<Item = &'b DecafPoint>,
|
J: IntoIterator<Item = &'b RistrettoPoint>,
|
||||||
{
|
{
|
||||||
let extended_points = points.into_iter().map(|P| &P.0);
|
let extended_points = points.into_iter().map(|P| &P.0);
|
||||||
DecafPoint(edwards::multiscalar_mult(scalars, extended_points))
|
RistrettoPoint(edwards::multiscalar_mult(scalars, extended_points))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Precomputation
|
/// Precomputation
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct DecafBasepointTable(pub EdwardsBasepointTable);
|
pub struct RistrettoBasepointTable(pub EdwardsBasepointTable);
|
||||||
|
|
||||||
impl<'a, 'b> Mul<&'b Scalar> for &'a DecafBasepointTable {
|
impl<'a, 'b> Mul<&'b Scalar> for &'a RistrettoBasepointTable {
|
||||||
type Output = DecafPoint;
|
type Output = RistrettoPoint;
|
||||||
|
|
||||||
fn mul(self, scalar: &'b Scalar) -> DecafPoint {
|
fn mul(self, scalar: &'b Scalar) -> RistrettoPoint {
|
||||||
DecafPoint(&self.0 * scalar)
|
RistrettoPoint(&self.0 * scalar)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> Mul<&'a DecafBasepointTable> for &'b Scalar {
|
impl<'a, 'b> Mul<&'a RistrettoBasepointTable> for &'b Scalar {
|
||||||
type Output = DecafPoint;
|
type Output = RistrettoPoint;
|
||||||
|
|
||||||
fn mul(self, basepoint_table: &'a DecafBasepointTable) -> DecafPoint {
|
fn mul(self, basepoint_table: &'a RistrettoBasepointTable) -> RistrettoPoint {
|
||||||
DecafPoint(self * &basepoint_table.0)
|
RistrettoPoint(self * &basepoint_table.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DecafBasepointTable {
|
impl RistrettoBasepointTable {
|
||||||
/// Create a precomputed table of multiples of the given `basepoint`.
|
/// Create a precomputed table of multiples of the given `basepoint`.
|
||||||
pub fn create(basepoint: &DecafPoint) -> DecafBasepointTable {
|
pub fn create(basepoint: &RistrettoPoint) -> RistrettoBasepointTable {
|
||||||
DecafBasepointTable(EdwardsBasepointTable::create(&basepoint.0))
|
RistrettoBasepointTable(EdwardsBasepointTable::create(&basepoint.0))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the basepoint for this table as a `DecafPoint`.
|
/// Get the basepoint for this table as a `RistrettoPoint`.
|
||||||
pub fn basepoint(&self) -> DecafPoint {
|
pub fn basepoint(&self) -> RistrettoPoint {
|
||||||
DecafPoint(self.0.basepoint())
|
RistrettoPoint(self.0.basepoint())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -636,7 +631,7 @@ impl DecafBasepointTable {
|
||||||
// Constant-time conditional assignment
|
// Constant-time conditional assignment
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
impl ConditionallyAssignable for DecafPoint {
|
impl ConditionallyAssignable for RistrettoPoint {
|
||||||
/// Conditionally assign `other` to `self`, if `choice == 1u8`.
|
/// Conditionally assign `other` to `self`, if `choice == 1u8`.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
|
|
@ -648,11 +643,11 @@ impl ConditionallyAssignable for DecafPoint {
|
||||||
/// # use subtle::ConditionallyAssignable;
|
/// # use subtle::ConditionallyAssignable;
|
||||||
/// #
|
/// #
|
||||||
/// # use curve25519_dalek::edwards::Identity;
|
/// # use curve25519_dalek::edwards::Identity;
|
||||||
/// # use curve25519_dalek::decaf::DecafPoint;
|
/// # use curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
/// # use curve25519_dalek::constants;
|
/// # use curve25519_dalek::constants;
|
||||||
/// # fn main() {
|
/// # fn main() {
|
||||||
/// let A = DecafPoint::identity();
|
/// let A = RistrettoPoint::identity();
|
||||||
/// let B = constants::DECAF_ED25519_BASEPOINT_POINT;
|
/// let B = constants::RISTRETTO_BASEPOINT_POINT;
|
||||||
///
|
///
|
||||||
/// let mut P = A;
|
/// let mut P = A;
|
||||||
///
|
///
|
||||||
|
|
@ -662,7 +657,7 @@ impl ConditionallyAssignable for DecafPoint {
|
||||||
/// assert!(P == B);
|
/// assert!(P == B);
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
fn conditional_assign(&mut self, other: &DecafPoint, choice: u8) {
|
fn conditional_assign(&mut self, other: &RistrettoPoint, choice: u8) {
|
||||||
self.0.X.conditional_assign(&other.0.X, choice);
|
self.0.X.conditional_assign(&other.0.X, choice);
|
||||||
self.0.Y.conditional_assign(&other.0.Y, choice);
|
self.0.Y.conditional_assign(&other.0.Y, choice);
|
||||||
self.0.Z.conditional_assign(&other.0.Z, choice);
|
self.0.Z.conditional_assign(&other.0.Z, choice);
|
||||||
|
|
@ -674,16 +669,16 @@ impl ConditionallyAssignable for DecafPoint {
|
||||||
// Debug traits
|
// Debug traits
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
impl Debug for CompressedDecaf {
|
impl Debug for CompressedRistretto {
|
||||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||||
write!(f, "CompressedDecaf: {:?}", self.as_bytes())
|
write!(f, "CompressedRistretto: {:?}", self.as_bytes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for DecafPoint {
|
impl Debug for RistrettoPoint {
|
||||||
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
|
||||||
let coset = self.coset4();
|
let coset = self.coset4();
|
||||||
write!(f, "DecafPoint: coset \n{:?}\n{:?}\n{:?}\n{:?}",
|
write!(f, "RistrettoPoint: coset \n{:?}\n{:?}\n{:?}\n{:?}",
|
||||||
coset[0], coset[1], coset[2], coset[3])
|
coset[0], coset[1], coset[2], coset[3])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -693,7 +688,7 @@ impl Debug for DecafPoint {
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
pub mod vartime {
|
pub mod vartime {
|
||||||
//! Variable-time operations on decaf points, useful for non-secret data.
|
//! Variable-time operations on ristretto points, useful for non-secret data.
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// Given a vector of public scalars and a vector of (possibly secret)
|
/// Given a vector of public scalars and a vector of (possibly secret)
|
||||||
|
|
@ -703,14 +698,14 @@ pub mod vartime {
|
||||||
///
|
///
|
||||||
/// # Input
|
/// # Input
|
||||||
///
|
///
|
||||||
/// A vector of `Scalar`s and a vector of `ExtendedPoints`. It is an
|
/// A vector of `Scalar`s and a vector of `RistrettoPoints`. It is an
|
||||||
/// error to call this function with two vectors of different lengths.
|
/// error to call this function with two vectors of different lengths.
|
||||||
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> DecafPoint
|
pub fn multiscalar_mult<'a, 'b, I, J>(scalars: I, points: J) -> RistrettoPoint
|
||||||
where I: IntoIterator<Item = &'a Scalar>,
|
where I: IntoIterator<Item = &'a Scalar>,
|
||||||
J: IntoIterator<Item = &'b DecafPoint>
|
J: IntoIterator<Item = &'b RistrettoPoint>
|
||||||
{
|
{
|
||||||
let extended_points = points.into_iter().map(|P| &P.0);
|
let extended_points = points.into_iter().map(|P| &P.0);
|
||||||
DecafPoint(edwards::vartime::multiscalar_mult(scalars, extended_points))
|
RistrettoPoint(edwards::vartime::multiscalar_mult(scalars, extended_points))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -735,39 +730,49 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
fn serde_cbor_basepoint_roundtrip() {
|
fn serde_cbor_basepoint_roundtrip() {
|
||||||
let output = serde_cbor::to_vec(&constants::DECAF_ED25519_BASEPOINT_POINT).unwrap();
|
let output = serde_cbor::to_vec(&constants::RISTRETTO_BASEPOINT_POINT).unwrap();
|
||||||
let parsed: DecafPoint = serde_cbor::from_slice(&output).unwrap();
|
let parsed: RistrettoPoint = serde_cbor::from_slice(&output).unwrap();
|
||||||
assert_eq!(parsed, constants::DECAF_ED25519_BASEPOINT_POINT);
|
assert_eq!(parsed, constants::RISTRETTO_BASEPOINT_POINT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn scalarmult_ristrettopoint_works_both_ways() {
|
||||||
|
let P = constants::RISTRETTO_BASEPOINT_POINT;
|
||||||
|
let s = Scalar::from_u64(999);
|
||||||
|
|
||||||
|
let P1 = &P * &s;
|
||||||
|
let P2 = &s * &P;
|
||||||
|
|
||||||
|
assert!(P1.compress().as_bytes() == P2.compress().as_bytes());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decaf_decompress_negative_s_fails() {
|
fn decompress_negative_s_fails() {
|
||||||
// constants::d is neg, so decompression should fail as |d| != d.
|
// constants::d is neg, so decompression should fail as |d| != d.
|
||||||
let bad_compressed = CompressedDecaf(constants::d.to_bytes());
|
let bad_compressed = CompressedRistretto(constants::d.to_bytes());
|
||||||
assert!(bad_compressed.decompress().is_none());
|
assert!(bad_compressed.decompress().is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decaf_decompress_id() {
|
fn decompress_id() {
|
||||||
let compressed_id = CompressedDecaf::identity();
|
let compressed_id = CompressedRistretto::identity();
|
||||||
let id = compressed_id.decompress().unwrap();
|
let id = compressed_id.decompress().unwrap();
|
||||||
assert_eq!(id.0.compress(), CompressedEdwardsY::identity());
|
assert_eq!(id.0.compress(), CompressedEdwardsY::identity());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decaf_compress_id() {
|
fn compress_id() {
|
||||||
let id = DecafPoint::identity();
|
let id = RistrettoPoint::identity();
|
||||||
assert_eq!(id.compress(), CompressedDecaf::identity());
|
assert_eq!(id.compress(), CompressedRistretto::identity());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decaf_basepoint_roundtrip() {
|
fn basepoint_roundtrip() {
|
||||||
let bp_compressed_decaf = constants::DECAF_ED25519_BASEPOINT_POINT.compress();
|
let bp_compressed_ristretto = constants::RISTRETTO_BASEPOINT_POINT.compress();
|
||||||
let bp_recaf = bp_compressed_decaf.decompress().unwrap().0;
|
let bp_recaf = bp_compressed_ristretto.decompress().unwrap().0;
|
||||||
// Check that bp_recaf differs from bp by a point of order 4
|
// Check that bp_recaf differs from bp by a point of order 4
|
||||||
let diff = &constants::ED25519_BASEPOINT_POINT - &bp_recaf;
|
let diff = &constants::RISTRETTO_BASEPOINT_POINT.0 - &bp_recaf;
|
||||||
let diff4 = diff.mult_by_pow_2(4); // XXX this is wrong
|
let diff4 = diff.mult_by_pow_2(2);
|
||||||
assert_eq!(diff4.compress(), CompressedEdwardsY::identity());
|
assert_eq!(diff4.compress(), CompressedEdwardsY::identity());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -776,54 +781,54 @@ mod test {
|
||||||
// Table of encodings of (1+i)*basepoint
|
// Table of encodings of (1+i)*basepoint
|
||||||
// Generated using the previous naive implementation.
|
// Generated using the previous naive implementation.
|
||||||
let compressed = [
|
let compressed = [
|
||||||
CompressedDecaf([141, 190, 226, 107, 177, 201, 35, 118, 14, 55, 160, 165, 242, 207, 121, 161, 177, 80, 8, 132, 205, 254, 101, 169, 233, 65, 124, 96, 255, 182, 249, 40]),
|
CompressedRistretto([141, 190, 226, 107, 177, 201, 35, 118, 14, 55, 160, 165, 242, 207, 121, 161, 177, 80, 8, 132, 205, 254, 101, 169, 233, 65, 124, 96, 255, 182, 249, 40]),
|
||||||
CompressedDecaf([131, 57, 148, 16, 8, 196, 141, 82, 144, 220, 105, 112, 66, 33, 48, 16, 182, 198, 173, 35, 248, 181, 92, 231, 222, 35, 85, 56, 5, 252, 91, 40]),
|
CompressedRistretto([131, 57, 148, 16, 8, 196, 141, 82, 144, 220, 105, 112, 66, 33, 48, 16, 182, 198, 173, 35, 248, 181, 92, 231, 222, 35, 85, 56, 5, 252, 91, 40]),
|
||||||
CompressedDecaf([199, 132, 32, 144, 156, 143, 81, 170, 240, 56, 232, 6, 178, 37, 118, 190, 110, 201, 26, 173, 156, 97, 59, 162, 240, 247, 226, 107, 197, 111, 107, 26]),
|
CompressedRistretto([199, 132, 32, 144, 156, 143, 81, 170, 240, 56, 232, 6, 178, 37, 118, 190, 110, 201, 26, 173, 156, 97, 59, 162, 240, 247, 226, 107, 197, 111, 107, 26]),
|
||||||
CompressedDecaf([210, 120, 34, 214, 175, 27, 61, 6, 229, 181, 216, 36, 11, 245, 146, 232, 130, 215, 77, 29, 210, 30, 54, 155, 191, 81, 59, 124, 174, 3, 135, 36]),
|
CompressedRistretto([210, 120, 34, 214, 175, 27, 61, 6, 229, 181, 216, 36, 11, 245, 146, 232, 130, 215, 77, 29, 210, 30, 54, 155, 191, 81, 59, 124, 174, 3, 135, 36]),
|
||||||
CompressedDecaf([155, 52, 159, 52, 189, 27, 181, 0, 245, 131, 0, 197, 79, 208, 252, 122, 104, 161, 245, 143, 67, 94, 13, 129, 153, 173, 129, 179, 118, 231, 90, 52]),
|
CompressedRistretto([155, 52, 159, 52, 189, 27, 181, 0, 245, 131, 0, 197, 79, 208, 252, 122, 104, 161, 245, 143, 67, 94, 13, 129, 153, 173, 129, 179, 118, 231, 90, 52]),
|
||||||
CompressedDecaf([42, 117, 252, 118, 8, 1, 72, 25, 111, 246, 247, 103, 236, 86, 235, 29, 100, 156, 186, 209, 159, 21, 61, 26, 249, 25, 137, 228, 84, 23, 10, 27]),
|
CompressedRistretto([42, 117, 252, 118, 8, 1, 72, 25, 111, 246, 247, 103, 236, 86, 235, 29, 100, 156, 186, 209, 159, 21, 61, 26, 249, 25, 137, 228, 84, 23, 10, 27]),
|
||||||
CompressedDecaf([21, 126, 181, 117, 58, 90, 216, 28, 184, 57, 9, 23, 158, 68, 159, 171, 109, 150, 232, 140, 144, 73, 139, 122, 124, 105, 125, 160, 94, 185, 150, 52]),
|
CompressedRistretto([21, 126, 181, 117, 58, 90, 216, 28, 184, 57, 9, 23, 158, 68, 159, 171, 109, 150, 232, 140, 144, 73, 139, 122, 124, 105, 125, 160, 94, 185, 150, 52]),
|
||||||
CompressedDecaf([232, 167, 112, 233, 126, 33, 105, 63, 151, 6, 88, 225, 181, 17, 223, 12, 116, 138, 203, 47, 243, 225, 50, 171, 21, 220, 186, 179, 132, 20, 48, 6]),
|
CompressedRistretto([232, 167, 112, 233, 126, 33, 105, 63, 151, 6, 88, 225, 181, 17, 223, 12, 116, 138, 203, 47, 243, 225, 50, 171, 21, 220, 186, 179, 132, 20, 48, 6]),
|
||||||
CompressedDecaf([99, 44, 97, 48, 242, 174, 78, 198, 112, 154, 146, 36, 239, 34, 94, 4, 0, 244, 175, 34, 46, 0, 83, 187, 5, 163, 225, 63, 51, 237, 234, 22]),
|
CompressedRistretto([99, 44, 97, 48, 242, 174, 78, 198, 112, 154, 146, 36, 239, 34, 94, 4, 0, 244, 175, 34, 46, 0, 83, 187, 5, 163, 225, 63, 51, 237, 234, 22]),
|
||||||
CompressedDecaf([2, 33, 89, 176, 178, 123, 159, 75, 235, 172, 251, 11, 137, 177, 90, 122, 149, 186, 52, 243, 153, 190, 185, 202, 59, 137, 204, 160, 150, 152, 148, 55]),
|
CompressedRistretto([2, 33, 89, 176, 178, 123, 159, 75, 235, 172, 251, 11, 137, 177, 90, 122, 149, 186, 52, 243, 153, 190, 185, 202, 59, 137, 204, 160, 150, 152, 148, 55]),
|
||||||
CompressedDecaf([245, 79, 78, 226, 114, 69, 247, 112, 18, 54, 90, 225, 176, 77, 231, 235, 196, 123, 49, 221, 34, 205, 151, 228, 244, 112, 82, 58, 30, 31, 58, 12]),
|
CompressedRistretto([245, 79, 78, 226, 114, 69, 247, 112, 18, 54, 90, 225, 176, 77, 231, 235, 196, 123, 49, 221, 34, 205, 151, 228, 244, 112, 82, 58, 30, 31, 58, 12]),
|
||||||
CompressedDecaf([135, 53, 175, 167, 13, 94, 62, 31, 29, 248, 13, 132, 29, 69, 7, 188, 145, 49, 62, 55, 181, 109, 214, 11, 248, 162, 70, 15, 236, 126, 100, 60]),
|
CompressedRistretto([135, 53, 175, 167, 13, 94, 62, 31, 29, 248, 13, 132, 29, 69, 7, 188, 145, 49, 62, 55, 181, 109, 214, 11, 248, 162, 70, 15, 236, 126, 100, 60]),
|
||||||
CompressedDecaf([98, 150, 69, 229, 144, 122, 237, 107, 127, 177, 33, 64, 59, 173, 210, 102, 74, 34, 23, 16, 252, 117, 14, 97, 231, 178, 63, 193, 157, 28, 178, 17]),
|
CompressedRistretto([98, 150, 69, 229, 144, 122, 237, 107, 127, 177, 33, 64, 59, 173, 210, 102, 74, 34, 23, 16, 252, 117, 14, 97, 231, 178, 63, 193, 157, 28, 178, 17]),
|
||||||
CompressedDecaf([222, 104, 6, 1, 72, 12, 72, 178, 204, 238, 128, 70, 41, 150, 235, 96, 153, 150, 18, 4, 141, 206, 0, 38, 122, 112, 249, 51, 94, 251, 20, 57]),
|
CompressedRistretto([222, 104, 6, 1, 72, 12, 72, 178, 204, 238, 128, 70, 41, 150, 235, 96, 153, 150, 18, 4, 141, 206, 0, 38, 122, 112, 249, 51, 94, 251, 20, 57]),
|
||||||
CompressedDecaf([7, 221, 140, 57, 13, 146, 248, 27, 56, 4, 128, 23, 145, 120, 126, 4, 158, 173, 52, 213, 164, 250, 26, 55, 89, 96, 187, 111, 211, 18, 63, 19]),
|
CompressedRistretto([7, 221, 140, 57, 13, 146, 248, 27, 56, 4, 128, 23, 145, 120, 126, 4, 158, 173, 52, 213, 164, 250, 26, 55, 89, 96, 187, 111, 211, 18, 63, 19]),
|
||||||
CompressedDecaf([91, 213, 193, 10, 102, 92, 199, 124, 61, 176, 1, 47, 111, 59, 183, 91, 79, 56, 208, 109, 172, 209, 17, 167, 229, 216, 3, 236, 200, 208, 15, 20]),
|
CompressedRistretto([91, 213, 193, 10, 102, 92, 199, 124, 61, 176, 1, 47, 111, 59, 183, 91, 79, 56, 208, 109, 172, 209, 17, 167, 229, 216, 3, 236, 200, 208, 15, 20]),
|
||||||
];
|
];
|
||||||
let mut bp = constants::DECAF_ED25519_BASEPOINT_POINT;
|
let mut bp = RistrettoPoint::identity();
|
||||||
for i in 0..16 {
|
for i in 0..16 {
|
||||||
assert_eq!(bp.compress(), compressed[i]);
|
assert_eq!(bp.compress(), compressed[i]);
|
||||||
bp = &bp + &constants::DECAF_ED25519_BASEPOINT_POINT;
|
bp = &bp + &constants::RISTRETTO_BASEPOINT_POINT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decaf_four_torsion_basepoint() {
|
fn four_torsion_basepoint() {
|
||||||
let bp = constants::DECAF_ED25519_BASEPOINT_POINT;
|
let bp = constants::RISTRETTO_BASEPOINT_POINT;
|
||||||
let bp_coset = bp.coset4();
|
let bp_coset = bp.coset4();
|
||||||
for i in 0..4 {
|
for i in 0..4 {
|
||||||
assert_eq!(bp, DecafPoint(bp_coset[i]));
|
assert_eq!(bp, RistrettoPoint(bp_coset[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decaf_four_torsion_random() {
|
fn four_torsion_random() {
|
||||||
let mut rng = OsRng::new().unwrap();
|
let mut rng = OsRng::new().unwrap();
|
||||||
let B = &constants::DECAF_ED25519_BASEPOINT_TABLE;
|
let B = &constants::RISTRETTO_BASEPOINT_TABLE;
|
||||||
let P = B * &Scalar::random(&mut rng);
|
let P = B * &Scalar::random(&mut rng);
|
||||||
let P_coset = P.coset4();
|
let P_coset = P.coset4();
|
||||||
for i in 0..4 {
|
for i in 0..4 {
|
||||||
assert_eq!(P, DecafPoint(P_coset[i]));
|
assert_eq!(P, RistrettoPoint(P_coset[i]));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decaf_random_roundtrip() {
|
fn random_roundtrip() {
|
||||||
let mut rng = OsRng::new().unwrap();
|
let mut rng = OsRng::new().unwrap();
|
||||||
let B = &constants::DECAF_ED25519_BASEPOINT_TABLE;
|
let B = &constants::RISTRETTO_BASEPOINT_TABLE;
|
||||||
for _ in 0..100 {
|
for _ in 0..100 {
|
||||||
let P = B * &Scalar::random(&mut rng);
|
let P = B * &Scalar::random(&mut rng);
|
||||||
let compressed_P = P.compress();
|
let compressed_P = P.compress();
|
||||||
|
|
@ -833,13 +838,13 @@ mod test {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn decaf_random_is_valid() {
|
fn random_is_valid() {
|
||||||
let mut rng = OsRng::new().unwrap();
|
let mut rng = OsRng::new().unwrap();
|
||||||
for _ in 0..100 {
|
for _ in 0..100 {
|
||||||
let P = DecafPoint::random(&mut rng);
|
let P = RistrettoPoint::random(&mut rng);
|
||||||
// Check that P is on the curve
|
// Check that P is on the curve
|
||||||
assert!(P.0.is_valid());
|
assert!(P.0.is_valid());
|
||||||
// Check that P is in the image of the decaf map
|
// Check that P is in the image of the ristretto map
|
||||||
P.compress();
|
P.compress();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -855,7 +860,7 @@ mod bench {
|
||||||
#[bench]
|
#[bench]
|
||||||
fn decompression(b: &mut Bencher) {
|
fn decompression(b: &mut Bencher) {
|
||||||
let mut rng = OsRng::new().unwrap();
|
let mut rng = OsRng::new().unwrap();
|
||||||
let B = &constants::DECAF_ED25519_BASEPOINT_TABLE;
|
let B = &constants::RISTRETTO_BASEPOINT_TABLE;
|
||||||
let P = B * &Scalar::random(&mut rng);
|
let P = B * &Scalar::random(&mut rng);
|
||||||
let P_compressed = P.compress();
|
let P_compressed = P.compress();
|
||||||
b.iter(|| P_compressed.decompress().unwrap());
|
b.iter(|| P_compressed.decompress().unwrap());
|
||||||
|
|
@ -864,7 +869,7 @@ mod bench {
|
||||||
#[bench]
|
#[bench]
|
||||||
fn compression(b: &mut Bencher) {
|
fn compression(b: &mut Bencher) {
|
||||||
let mut rng = OsRng::new().unwrap();
|
let mut rng = OsRng::new().unwrap();
|
||||||
let B = &constants::DECAF_ED25519_BASEPOINT_TABLE;
|
let B = &constants::RISTRETTO_BASEPOINT_TABLE;
|
||||||
let P = B * &Scalar::random(&mut rng);
|
let P = B * &Scalar::random(&mut rng);
|
||||||
b.iter(|| P.compress());
|
b.iter(|| P.compress());
|
||||||
}
|
}
|
||||||
Loading…
Reference in a new issue