Compare commits

...

8 Commits

Author SHA1 Message Date
Jordan Rose
b3329ed05c Use ok_or_else instead of ok_or in serde decoding
Serde errors are not simple enums; they format a full error string
from their arguments. It's worth not doing that up front.
2022-01-31 17:05:47 -08:00
Trevor Perrin
2694ad3b78 simply map-to-single-elligator 2021-02-19 15:01:40 -05:00
Trevor Perrin
2b64289b51 Single-elligator hash-to-point 2021-02-19 15:01:40 -05:00
Trevor Perrin
4493441a62 Remove extraneous check on lizard encode 2021-02-19 15:01:40 -05:00
Trevor Perrin
f3f2ccb099 Changes for benchmarking 2021-02-19 15:01:39 -05:00
Trevor Perrin
825c6caf23 Improve encode_253 2021-02-19 15:01:21 -05:00
Trevor Perrin
8195bda00e encode_253 2021-02-19 15:01:21 -05:00
Trevor Perrin
ce6e6ff9c7 Adding Lizard files 2021-02-19 15:01:21 -05:00
12 changed files with 544 additions and 12 deletions

View File

@ -14,6 +14,7 @@ extern crate curve25519_dalek;
use curve25519_dalek::constants;
use curve25519_dalek::scalar::Scalar;
use curve25519_dalek::field::FieldElement;
static BATCH_SIZES: [usize; 5] = [1, 2, 4, 8, 16];
static MULTISCALAR_SIZES: [usize; 13] = [1, 2, 4, 8, 16, 32, 64, 128, 256, 384, 512, 768, 1024];
@ -243,6 +244,15 @@ mod ristretto_benches {
});
}
fn elligator(c: &mut Criterion) {
let fe_bytes = [0u8; 32];
let fe = FieldElement::from_bytes(&fe_bytes);
c.bench_function("RistrettoPoint Elligator", |b| {
b.iter(|| RistrettoPoint::elligator_ristretto_flavor(&fe));
});
}
fn double_and_compress_batch(c: &mut Criterion) {
c.bench_function_over_inputs(
"Batch Ristretto double-and-encode",
@ -263,6 +273,7 @@ mod ristretto_benches {
targets =
compress,
decompress,
elligator,
double_and_compress_batch,
}
}

View File

@ -260,11 +260,11 @@ impl<'de> Deserialize<'de> for EdwardsPoint {
let mut bytes = [0u8; 32];
for i in 0..32 {
bytes[i] = seq.next_element()?
.ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
.ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
}
CompressedEdwardsY(bytes)
.decompress()
.ok_or(serde::de::Error::custom("decompression failed"))
.ok_or_else(|| serde::de::Error::custom("decompression failed"))
}
}
@ -292,7 +292,7 @@ impl<'de> Deserialize<'de> for CompressedEdwardsY {
let mut bytes = [0u8; 32];
for i in 0..32 {
bytes[i] = seq.next_element()?
.ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
.ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
}
Ok(CompressedEdwardsY(bytes))
}

View File

@ -18,7 +18,7 @@
//
// 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", deny(missing_docs))]
#![cfg_attr(feature = "nightly", doc(include = "../README.md"))]
#![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")]
@ -48,7 +48,7 @@ extern crate rand_core;
extern crate zeroize;
// Used for traits related to constant-time code.
extern crate subtle;
pub extern crate subtle;
#[cfg(all(test, feature = "serde"))]
extern crate bincode;
@ -81,12 +81,15 @@ pub mod constants;
// External (and internal) traits.
pub mod traits;
// All the lizard code is here, for now
pub mod lizard;
//------------------------------------------------------------------------
// curve25519-dalek internal modules
//------------------------------------------------------------------------
// Finite field arithmetic mod p = 2^255 - 19
pub(crate) mod field;
pub mod field;
// Arithmetic backends (using u32, u64, etc) live here
pub(crate) mod backend;

21
src/lizard/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Bas Westerbaan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,74 @@
//! Helper functions for use with Lizard
#![allow(non_snake_case)]
use subtle::Choice;
use subtle::ConstantTimeEq;
use subtle::ConditionallyNegatable;
use subtle::ConditionallySelectable;
use constants;
use lizard::lizard_constants;
use field::FieldElement;
/// Represents a point (s,t) on the the Jacobi quartic associated
/// to the Edwards curve.
#[derive(Copy, Clone)]
#[allow(missing_docs)]
pub struct JacobiPoint {
pub S: FieldElement,
pub T: FieldElement,
}
impl JacobiPoint {
/// Elligator2 is defined in two steps: first a field element is converted
/// to a point (s,t) on the Jacobi quartic associated to the Edwards curve.
/// Then this point is mapped to a point on the Edwards curve.
/// This function computes a field element that is mapped to a given (s,t)
/// with Elligator2 if it exists.
pub(crate) fn elligator_inv(&self) -> (Choice, FieldElement) {
let mut out = FieldElement::zero();
// Special case: s = 0. If s is zero, either t = 1 or t = -1.
// If t=1, then sqrt(i*d) is the preimage. Otherwise it's 0.
let s_is_zero = self.S.is_zero();
let t_equals_one = self.T.ct_eq(&FieldElement::one());
out.conditional_assign(&lizard_constants::SQRT_ID, t_equals_one);
let mut ret = s_is_zero;
let mut done = s_is_zero;
// a := (t+1) (d+1)/(d-1)
let a = &(&self.T + &FieldElement::one()) * &lizard_constants::DP1_OVER_DM1;
let a2 = a.square();
// y := 1/sqrt(i (s^4 - a^2)).
let s2 = self.S.square();
let s4 = s2.square();
let invSqY = &(&s4 - &a2) * &constants::SQRT_M1;
// There is no preimage if the square root of i*(s^4-a^2) does not exist.
let (sq, y) = invSqY.invsqrt();
ret |= sq;
done |= !sq;
// x := (a + sign(s)*s^2) y
let mut pms2 = s2;
pms2.conditional_negate(self.S.is_negative());
let mut x = &(&a + &pms2) * &y;
let x_is_negative = x.is_negative();
x.conditional_negate(x_is_negative);
out.conditional_assign(&x, !done);
(ret, out)
}
pub(crate) fn dual(&self) -> JacobiPoint {
JacobiPoint {
S: -(&self.S),
T: -(&self.T),
}
}
}

View File

@ -0,0 +1,54 @@
//! Constants for use in Lizard
//!
//! Could be moved into backend/serial/u??/constants.rs
#[cfg(feature = "u64_backend")]
pub(crate) use lizard::u64_constants::*;
#[cfg(feature = "u32_backend")]
pub(crate) use lizard::u32_constants::*;
// ------------------------------------------------------------------------
// Tests
// ------------------------------------------------------------------------
#[cfg(all(test, feature = "stage2_build"))]
mod test {
use super::*;
use constants;
use field::FieldElement;
#[test]
fn test_lizard_constants() {
let (_, sqrt_id) = FieldElement::sqrt_ratio_i(
&(&constants::SQRT_M1 * &constants::EDWARDS_D),
&FieldElement::one()
);
assert_eq!(sqrt_id, SQRT_ID);
assert_eq!(
&(&constants::EDWARDS_D + &FieldElement::one())
* &(&constants::EDWARDS_D - &FieldElement::one()).invert(),
DP1_OVER_DM1
);
assert_eq!(
MDOUBLE_INVSQRT_A_MINUS_D,
-&(&constants::INVSQRT_A_MINUS_D + &constants::INVSQRT_A_MINUS_D)
);
assert_eq!(
MIDOUBLE_INVSQRT_A_MINUS_D,
&MDOUBLE_INVSQRT_A_MINUS_D * &constants::SQRT_M1
);
let (_, invsqrt_one_plus_d) = (
&constants::EDWARDS_D + &FieldElement::one()).invsqrt();
assert_eq!(
-&invsqrt_one_plus_d,
MINVSQRT_ONE_PLUS_D
);
}
}

View File

@ -0,0 +1,305 @@
//! Defines additional methods on RistrettoPoint for Lizard
#![allow(non_snake_case)]
use digest::Digest;
use digest::generic_array::typenum::U32;
use constants;
use field::FieldElement;
use subtle::ConditionallySelectable;
use subtle::ConstantTimeEq;
use subtle::Choice;
use edwards::EdwardsPoint;
use lizard::jacobi_quartic::JacobiPoint;
use lizard::lizard_constants;
#[allow(unused_imports)]
use prelude::*;
use ristretto::RistrettoPoint;
impl RistrettoPoint {
pub fn from_uniform_bytes_single_elligator(bytes: &[u8; 32]) -> RistrettoPoint {
RistrettoPoint::elligator_ristretto_flavor(&FieldElement::from_bytes(&bytes))
}
/// Encode 16 bytes of data to a RistrettoPoint, using the Lizard method
pub fn lizard_encode<D: Digest>(data: &[u8; 16]) -> RistrettoPoint
where D: Digest<OutputSize = U32>
{
let mut fe_bytes: [u8;32] = Default::default();
let digest = D::digest(data);
fe_bytes[0..32].copy_from_slice(digest.as_slice());
fe_bytes[8..24].copy_from_slice(data);
fe_bytes[0] &= 254; // make positive since Elligator on r and -r is the same
fe_bytes[31] &= 63;
let fe = FieldElement::from_bytes(&fe_bytes);
RistrettoPoint::elligator_ristretto_flavor(&fe)
}
/// Decode 16 bytes of data from a RistrettoPoint, using the Lizard method
pub fn lizard_decode<D: Digest>(&self) -> Option<[u8; 16]>
where D: Digest<OutputSize = U32>
{
let mut result: [u8; 16] = Default::default();
let mut h: [u8;32] = Default::default();
let (mask, fes) = self.elligator_ristretto_flavor_inverse();
let mut n_found = 0;
for j in 0..8 {
let mut ok = Choice::from((mask >> j) & 1);
let buf2 = fes[j].to_bytes(); // array
h.copy_from_slice(&D::digest(&buf2[8..24])); // array
h[8..24].copy_from_slice(&buf2[8..24]);
h[0] &= 254;
h[31] &= 63;
ok &= h.ct_eq(&buf2);
for i in 0..16 {
result[i] = u8::conditional_select(&result[i], &buf2[8+i], ok);
}
n_found += ok.unwrap_u8();
}
if n_found == 1 {
return Some(result);
}
else {
return None;
}
}
pub fn encode_253_bits(data: &[u8; 32]) -> Option<RistrettoPoint>
{
if data.len() != 32 {
return None;
}
let fe = FieldElement::from_bytes(data);
let p = RistrettoPoint::elligator_ristretto_flavor(&fe);
Some(p)
}
pub fn decode_253_bits(&self) -> (u8, [[u8; 32]; 8])
{
let mut ret = [ [0u8; 32]; 8];
let (mask, fes) = self.elligator_ristretto_flavor_inverse();
for j in 0..8 {
ret[j] = fes[j].to_bytes();
}
(mask, ret)
}
/// Return the coset self + E[4], for debugging.
pub fn xcoset4(&self) -> [EdwardsPoint; 4] {
[ self.0
, &self.0 + &constants::EIGHT_TORSION[2]
, &self.0 + &constants::EIGHT_TORSION[4]
, &self.0 + &constants::EIGHT_TORSION[6]
]
}
/// Computes the at most 8 positive FieldElements f such that
/// self == elligator_ristretto_flavor(f).
/// Assumes self is even.
///
/// Returns a bitmask of which elements in fes are set.
pub fn elligator_ristretto_flavor_inverse(&self) -> (u8, [FieldElement; 8]) {
// Elligator2 computes a Point from a FieldElement in two steps: first
// it computes a (s,t) on the Jacobi quartic and then computes the
// corresponding even point on the Edwards curve.
//
// We invert in three steps. Any Ristretto point has four representatives
// as even Edwards points. For each of those even Edwards points,
// there are two points on the Jacobi quartic that map to it.
// Each of those eight points on the Jacobi quartic might have an
// Elligator2 preimage.
//
// Essentially we first loop over the four representatives of our point,
// then for each of them consider both points on the Jacobi quartic and
// check whether they have an inverse under Elligator2. We take the
// following shortcut though.
//
// We can compute two Jacobi quartic points for (x,y) and (-x,-y)
// at the same time. The four Jacobi quartic points are two of
// such pairs.
let mut mask : u8 = 0;
let jcs = self.to_jacobi_quartic_ristretto();
let mut ret = [FieldElement::one(); 8];
for i in 0..4 {
let (ok, fe) = jcs[i].elligator_inv();
let mut tmp : u8 = 0;
ret[2*i] = fe;
tmp.conditional_assign(&1, ok);
mask |= tmp << (2 * i);
let jc = jcs[i].dual();
let (ok, fe) = jc.elligator_inv();
let mut tmp : u8 = 0;
ret[2*i+1] = fe;
tmp.conditional_assign(&1, ok);
mask |= tmp << (2 * i + 1);
}
return (mask, ret)
}
/// Find a point on the Jacobi quartic associated to each of the four
/// points Ristretto equivalent to p.
///
/// There is one exception: for (0,-1) there is no point on the quartic and
/// so we repeat one on the quartic equivalent to (0,1).
fn to_jacobi_quartic_ristretto(&self) -> [JacobiPoint; 4] {
let x2 = self.0.X.square(); // X^2
let y2 = self.0.Y.square(); // Y^2
let y4 = y2.square(); // Y^4
let z2 = self.0.Z.square(); // Z^2
let z_min_y = &self.0.Z - &self.0.Y; // Z - Y
let z_pl_y = &self.0.Z + &self.0.Y; // Z + Y
let z2_min_y2 = &z2 - &y2; // Z^2 - Y^2
// gamma := 1/sqrt( Y^4 X^2 (Z^2 - Y^2) )
let (_, gamma) = (&(&y4 * &x2) * &z2_min_y2).invsqrt();
let den = &gamma * &y2;
let s_over_x = &den * &z_min_y;
let sp_over_xp = &den * &z_pl_y;
let s0 = &s_over_x * &self.0.X;
let s1 = &(-(&sp_over_xp)) * &self.0.X;
// t_0 := -2/sqrt(-d-1) * Z * sOverX
// t_1 := -2/sqrt(-d-1) * Z * spOverXp
let tmp = &lizard_constants::MDOUBLE_INVSQRT_A_MINUS_D * &self.0.Z;
let mut t0 = &tmp * &s_over_x;
let mut t1 = &tmp * &sp_over_xp;
// den := -1/sqrt(1+d) (Y^2 - Z^2) gamma
let den = &(&(-(&z2_min_y2)) * &lizard_constants::MINVSQRT_ONE_PLUS_D) * &gamma;
// Same as before but with the substitution (X, Y, Z) = (Y, X, i*Z)
let iz = &constants::SQRT_M1 * &self.0.Z; // iZ
let iz_min_x = &iz - &self.0.X; // iZ - X
let iz_pl_x = &iz + &self.0.X; // iZ + X
let s_over_y = &den * &iz_min_x;
let sp_over_yp = &den * &iz_pl_x;
let mut s2 = &s_over_y * &self.0.Y;
let mut s3 = &(-(&sp_over_yp)) * &self.0.Y;
// t_2 := -2/sqrt(-d-1) * i*Z * sOverY
// t_3 := -2/sqrt(-d-1) * i*Z * spOverYp
let tmp = &lizard_constants::MDOUBLE_INVSQRT_A_MINUS_D * &iz;
let mut t2 = &tmp * &s_over_y;
let mut t3 = &tmp * &sp_over_yp;
// Special case: X=0 or Y=0. Then return
//
// (0,1) (1,-2i/sqrt(-d-1) (-1,-2i/sqrt(-d-1))
//
// Note that if X=0 or Y=0, then s_i = t_i = 0.
let x_or_y_is_zero = self.0.X.is_zero() | self.0.Y.is_zero();
t0.conditional_assign(&FieldElement::one(), x_or_y_is_zero);
t1.conditional_assign(&FieldElement::one(), x_or_y_is_zero);
t2.conditional_assign(&lizard_constants::MIDOUBLE_INVSQRT_A_MINUS_D, x_or_y_is_zero);
t3.conditional_assign(&lizard_constants::MIDOUBLE_INVSQRT_A_MINUS_D, x_or_y_is_zero);
s2.conditional_assign(&FieldElement::one(), x_or_y_is_zero);
s3.conditional_assign(&(-(&FieldElement::one())), x_or_y_is_zero);
return [
JacobiPoint{S: s0, T: t0},
JacobiPoint{S: s1, T: t1},
JacobiPoint{S: s2, T: t2},
JacobiPoint{S: s3, T: t3},
]
}
}
// ------------------------------------------------------------------------
// Tests
// ------------------------------------------------------------------------
#[cfg(all(test, feature = "stage2_build"))]
mod test {
extern crate sha2;
#[cfg(feature = "rand")]
use rand_os::OsRng;
use rand_core::{RngCore};
use self::sha2::{Sha256};
use ristretto::CompressedRistretto;
use super::*;
fn test_lizard_encode_helper(data: &[u8; 16], result: &[u8; 32]) {
let p = RistrettoPoint::lizard_encode::<Sha256>(data).unwrap();
let p_bytes = p.compress().to_bytes();
assert!(&p_bytes == result);
let p = CompressedRistretto::from_slice(&p_bytes).decompress().unwrap();
let data_out = p.lizard_decode::<Sha256>().unwrap();
assert!(&data_out == data);
}
#[test]
fn test_lizard_encode() {
test_lizard_encode_helper(&[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
&[0xf0, 0xb7, 0xe3, 0x44, 0x84, 0xf7, 0x4c, 0xf0, 0xf, 0x15, 0x2, 0x4b, 0x73, 0x85, 0x39, 0x73, 0x86, 0x46, 0xbb, 0xbe, 0x1e, 0x9b, 0xc7, 0x50, 0x9a, 0x67, 0x68, 0x15, 0x22, 0x7e, 0x77, 0x4f]);
test_lizard_encode_helper(&[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
&[0xcc, 0x92, 0xe8, 0x1f, 0x58, 0x5a, 0xfc, 0x5c, 0xaa, 0xc8, 0x86, 0x60, 0xd8, 0xd1, 0x7e, 0x90, 0x25, 0xa4, 0x44, 0x89, 0xa3, 0x63, 0x4, 0x21, 0x23, 0xf6, 0xaf, 0x7, 0x2, 0x15, 0x6e, 0x65]);
test_lizard_encode_helper(&[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15],
&[0xc8, 0x30, 0x57, 0x3f, 0x8a, 0x8e, 0x77, 0x78, 0x67, 0x1f, 0x76, 0xcd, 0xc7, 0x96, 0xdc, 0xa, 0x23, 0x5c, 0xf1, 0x77, 0xf1, 0x97, 0xd9, 0xfc, 0xba, 0x6, 0xe8, 0x4e, 0x96, 0x24, 0x74, 0x44]);
}
#[test]
fn test_elligator_inv() {
let mut rng = rand::thread_rng();
for i in 0..100 {
let mut fe_bytes = [0u8; 32];
if i == 0 {
// Test for first corner-case: fe = 0
fe_bytes = [0u8; 32];
} else if i == 1 {
// Test for second corner-case: fe = +sqrt(i*d)
fe_bytes = [168, 27, 92, 74, 203, 42, 48, 117, 170, 109, 234,
14, 45, 169, 188, 205, 21, 110, 235, 115, 153, 84,
52, 117, 151, 235, 123, 244, 88, 85, 179, 5];
} else {
// For the rest, just generate a random field element to test.
rng.fill_bytes(&mut fe_bytes);
}
fe_bytes[0] &= 254; // positive
fe_bytes[31] &= 127; // < 2^255-19
let fe = FieldElement::from_bytes(&fe_bytes);
let pt = RistrettoPoint::elligator_ristretto_flavor(&fe);
for pt2 in &pt.xcoset4() {
let (mask, fes) = RistrettoPoint(*pt2).elligator_ristretto_flavor_inverse();
let mut found = false;
for j in 0..8 {
if mask & (1 << j) != 0 {
assert_eq!(RistrettoPoint::elligator_ristretto_flavor(&fes[j]), pt);
if fes[j] == fe {
found = true;
}
}
}
assert!(found);
}
}
}
}

13
src/lizard/mod.rs Normal file
View File

@ -0,0 +1,13 @@
//! The Lizard method for encoding/decoding 16 bytes into Ristretto points.
#![allow(non_snake_case)]
#[cfg(feature = "u32_backend")]
mod u32_constants;
#[cfg(feature = "u64_backend")]
mod u64_constants;
pub mod lizard_constants;
pub mod jacobi_quartic;
pub mod lizard_ristretto;

View File

@ -0,0 +1,33 @@
use backend::serial::u32::field::FieldElement2625;
use edwards::EdwardsPoint;
/// `= sqrt(i*d)`, where `i = +sqrt(-1)` and `d` is the Edwards curve parameter.
pub const SQRT_ID: FieldElement2625 = FieldElement2625([
39590824, 701138, 28659366, 23623507, 53932708,
32206357, 36326585, 24309414, 26167230, 1494357,
]);
/// `= (d+1)/(d-1)`, where `d` is the Edwards curve parameter.
pub const DP1_OVER_DM1: FieldElement2625 = FieldElement2625([
58833708, 32184294, 62457071, 26110240, 19032991,
27203620, 7122892, 18068959, 51019405, 3776288,
]);
/// `= -2/sqrt(a-d)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters.
pub const MDOUBLE_INVSQRT_A_MINUS_D: FieldElement2625 = FieldElement2625([
54885894, 25242303, 55597453, 9067496, 51808079,
33312638, 25456129, 14121551, 54921728, 3972023,
]);
/// `= -2i/sqrt(a-d)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters
/// and `i = +sqrt(-1)`.
pub const MIDOUBLE_INVSQRT_A_MINUS_D: FieldElement2625 = FieldElement2625([
58178520, 23970840, 26444491, 29801899, 41064376,
743696, 2900628, 27920316, 41968995, 5270573,
]);
/// `= -1/sqrt(1+d)`, where `d` is the Edwards curve parameters.
pub const MINVSQRT_ONE_PLUS_D: FieldElement2625 = FieldElement2625([
38019585, 4791795, 20332186, 18653482, 46576675,
33182583, 65658549, 2817057, 12569934, 30919145,
]);

View File

@ -0,0 +1,18 @@
use backend::serial::u64::field::FieldElement51;
/// `= sqrt(i*d)`, where `i = +sqrt(-1)` and `d` is the Edwards curve parameter.
pub const SQRT_ID: FieldElement51 = FieldElement51([2298852427963285, 3837146560810661, 4413131899466403, 3883177008057528, 2352084440532925]);
/// `= (d+1)/(d-1)`, where `d` is the Edwards curve parameter.
pub const DP1_OVER_DM1: FieldElement51 = FieldElement51([2159851467815724, 1752228607624431, 1825604053920671, 1212587319275468, 253422448836237]);
/// `= -2/sqrt(a-d)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters.
pub const MDOUBLE_INVSQRT_A_MINUS_D: FieldElement51 = FieldElement51([1693982333959686, 608509411481997, 2235573344831311, 947681270984193, 266558006233600]);
/// `= -2i/sqrt(a-d)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters
/// and `i = +sqrt(-1)`.
pub const MIDOUBLE_INVSQRT_A_MINUS_D: FieldElement51 = FieldElement51([1608655899704280, 1999971613377227, 49908634785720, 1873700692181652, 353702208628067]);
/// `= -1/sqrt(1+d)`, where `d` is the Edwards curve parameters.
pub const MINVSQRT_ONE_PLUS_D: FieldElement51 = FieldElement51([321571956990465, 1251814006996634, 2226845496292387, 189049560751797, 2074948709371214]);

View File

@ -377,11 +377,11 @@ impl<'de> Deserialize<'de> for RistrettoPoint {
let mut bytes = [0u8; 32];
for i in 0..32 {
bytes[i] = seq.next_element()?
.ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
.ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
}
CompressedRistretto(bytes)
.decompress()
.ok_or(serde::de::Error::custom("decompression failed"))
.ok_or_else(|| serde::de::Error::custom("decompression failed"))
}
}
@ -409,7 +409,7 @@ impl<'de> Deserialize<'de> for CompressedRistretto {
let mut bytes = [0u8; 32];
for i in 0..32 {
bytes[i] = seq.next_element()?
.ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
.ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
}
Ok(CompressedRistretto(bytes))
}
@ -597,7 +597,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(crate) fn elligator_ristretto_flavor(r_0: &FieldElement) -> RistrettoPoint {
pub fn elligator_ristretto_flavor(r_0: &FieldElement) -> RistrettoPoint {
let i = &constants::SQRT_M1;
let d = &constants::EDWARDS_D;
let one_minus_d_sq = &constants::ONE_MINUS_EDWARDS_D_SQUARED;

View File

@ -416,10 +416,10 @@ impl<'de> Deserialize<'de> for Scalar {
let mut bytes = [0u8; 32];
for i in 0..32 {
bytes[i] = seq.next_element()?
.ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
.ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?;
}
Scalar::from_canonical_bytes(bytes)
.ok_or(serde::de::Error::custom(
.ok_or_else(|| serde::de::Error::custom(
&"scalar was not canonically encoded"
))
}