Group improvements (#28)
* Implement `ConstantTimeEq` for `Group` and `Group::Scalar` * Changed `expand_message_xmd` `dst` parameter to `GenericArray<u8, D>` * Remove allocation for `dst_prime` in `expand_message_xmd` * Remove allocation for `msg_prime` and `b` in `expand_message_xmd` * Remove unnecessary references in `expand_message_xmd` * Return `GenericArray` from `expand_message_xmd` * Oxidize loop in `expand_message_xmd` * Remove allocation for `b` in `expand_message_xmd` * Remove allocation for `xor` * De-duplicate code in `expand_message_xmd` * Remove unnecessary features * Make ristretto optional and export all backends * Make `rand` optional * Fix wrong documentation * Document `rand` feature * Remove empty line * Fix rustfmt * Fix testing with other backends * Iterate by value in `expand_message_xmd` * Fix typo * Rename `ristretto_x` features to `ristretto255_x` * Remove `rand` re-export * Improve `expand_message_xmd` loop * Remove unnecessary `#[doc(cfg())]` * Remove unnecessary `pub(crate)` for `mod p256` * Fix `p256` only build * Rename `serialize` feature to `serde` * Fix missing `Cargo.toml` update
This commit is contained in:
@@ -13,11 +13,11 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
backend_feature:
|
backend_feature:
|
||||||
- u64_backend
|
- ristretto255_u64
|
||||||
- u32_backend
|
- ristretto255_u32
|
||||||
- p256,u64_backend
|
- p256,ristretto255_u64
|
||||||
frontend_feature:
|
frontend_feature:
|
||||||
- serialize
|
- serde
|
||||||
toolchain:
|
toolchain:
|
||||||
- stable
|
- stable
|
||||||
- 1.51.0
|
- 1.51.0
|
||||||
@@ -57,16 +57,18 @@ jobs:
|
|||||||
# for any no_std target
|
# for any no_std target
|
||||||
- thumbv6m-none-eabi
|
- thumbv6m-none-eabi
|
||||||
backend_feature:
|
backend_feature:
|
||||||
- u64_backend
|
-
|
||||||
- u32_backend
|
- --features ristretto255_u64
|
||||||
- p256,u64_backend
|
- --features ristretto255_u32
|
||||||
|
- --features p256
|
||||||
frontend_feature:
|
frontend_feature:
|
||||||
- serialize
|
-
|
||||||
|
- --features serde
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: hecrj/setup-rust-action@v1
|
- uses: hecrj/setup-rust-action@v1
|
||||||
- run: rustup target add ${{ matrix.target }}
|
- run: rustup target add ${{ matrix.target }}
|
||||||
- run: cargo build --verbose --target=${{ matrix.target }} --no-default-features --features ${{ matrix.frontend_feature }} --features ${{ matrix.backend_feature }}
|
- run: cargo build --verbose --target=${{ matrix.target }} --no-default-features ${{ matrix.frontend_feature }} ${{ matrix.backend_feature }}
|
||||||
|
|
||||||
|
|
||||||
clippy:
|
clippy:
|
||||||
|
|||||||
+14
-14
@@ -12,37 +12,37 @@ readme = "README.md"
|
|||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["u64_backend", "serialize"]
|
default = ["ristretto255_u64", "serde"]
|
||||||
|
ristretto255_u64 = ["curve25519-dalek/u64_backend"]
|
||||||
|
ristretto255_u32 = ["curve25519-dalek/u32_backend"]
|
||||||
|
ristretto255_fiat_u64 = ["curve25519-dalek/fiat_u64_backend"]
|
||||||
|
ristretto255_fiat_u32 = ["curve25519-dalek/fiat_u32_backend"]
|
||||||
|
ristretto255_simd = ["curve25519-dalek/simd_backend"]
|
||||||
p256 = ["num-bigint", "num-integer", "num-traits", "once_cell", "p256_"]
|
p256 = ["num-bigint", "num-integer", "num-traits", "once_cell", "p256_"]
|
||||||
std = ["curve25519-dalek/std", "getrandom", "rand/std", "rand/std_rng", "num-bigint/std", "num-integer/std", "num-traits/std"]
|
std = []
|
||||||
u64_backend = ["curve25519-dalek/u64_backend"]
|
serde = ["serde_", "base64"]
|
||||||
u32_backend = ["curve25519-dalek/u32_backend"]
|
|
||||||
simd_backend = ["curve25519-dalek/simd_backend"]
|
|
||||||
serialize = ["serde", "base64", "generic-array/serde", "curve25519-dalek/serde"]
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
base64 = { version = "0.13", default-features = false, features = ["alloc"], optional = true }
|
base64 = { version = "0.13", default-features = false, features = ["alloc"], optional = true }
|
||||||
curve25519-dalek = { version = "3", default-features = false }
|
curve25519-dalek = { version = "3", default-features = false, optional = true }
|
||||||
digest = "0.9"
|
digest = "0.9"
|
||||||
displaydoc = { version = "0.2", default-features = false }
|
displaydoc = { version = "0.2", default-features = false }
|
||||||
generic-array = "0.14"
|
generic-array = "0.14"
|
||||||
getrandom = { version = "0.2", optional = true }
|
|
||||||
num-bigint = { version = "0.4", default-features = false, optional = true }
|
num-bigint = { version = "0.4", default-features = false, optional = true }
|
||||||
num-integer = { version = "0.1", default-features = false, optional = true }
|
num-integer = { version = "0.1", default-features = false, optional = true }
|
||||||
num-traits = { version = "0.2", default-features = false, optional = true }
|
num-traits = { version = "0.2", default-features = false, optional = true }
|
||||||
once_cell = { version = "1", default-features = false, optional = true }
|
once_cell = { version = "1", default-features = false, optional = true }
|
||||||
p256_ = { package = "p256", version = "0.9", default-features = false, features = ["arithmetic", "zeroize"], optional = true }
|
p256_ = { package = "p256", version = "0.9", default-features = false, features = ["arithmetic", "zeroize"], optional = true }
|
||||||
rand = { version = "0.8", default-features = false }
|
rand_core = { version = "0.6", default-features = false }
|
||||||
serde = { version = "1", default-features = false, features = ["alloc", "derive"], optional = true }
|
serde_ = { version = "1", package = "serde", default-features = false, optional = true }
|
||||||
subtle = { version = "2.3", default-features = false }
|
subtle = { version = "2.3", default-features = false }
|
||||||
zeroize = { version = "1", features = ["zeroize_derive"] }
|
zeroize = { version = "1", default-features = false }
|
||||||
|
|
||||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
|
||||||
getrandom = { version = "0.2", features = ["js"], optional = true }
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
generic-array = { version = "0.14", features = ["more_lengths"] }
|
||||||
hex = "0.4"
|
hex = "0.4"
|
||||||
json = "0.12"
|
json = "0.12"
|
||||||
|
rand = "0.8"
|
||||||
sha2 = "0.9"
|
sha2 = "0.9"
|
||||||
regex = "1"
|
regex = "1"
|
||||||
voprf = { path = "", default-features = false, features = ["std"] }
|
voprf = { path = "", default-features = false, features = ["std"] }
|
||||||
|
|||||||
@@ -38,5 +38,4 @@ pub enum InternalError {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
|
|
||||||
impl Error for InternalError {}
|
impl Error for InternalError {}
|
||||||
|
|||||||
+53
-43
@@ -7,9 +7,13 @@
|
|||||||
|
|
||||||
use crate::errors::InternalError;
|
use crate::errors::InternalError;
|
||||||
use crate::serialization::i2osp;
|
use crate::serialization::i2osp;
|
||||||
use alloc::vec::Vec;
|
use core::ops::Add;
|
||||||
use digest::{BlockInput, Digest};
|
use digest::{BlockInput, Digest};
|
||||||
use generic_array::typenum::{Unsigned, U1, U2};
|
use generic_array::{
|
||||||
|
sequence::Concat,
|
||||||
|
typenum::{Unsigned, U1, U2},
|
||||||
|
ArrayLength, GenericArray,
|
||||||
|
};
|
||||||
|
|
||||||
// Computes ceil(x / y)
|
// Computes ceil(x / y)
|
||||||
fn div_ceil(x: usize, y: usize) -> usize {
|
fn div_ceil(x: usize, y: usize) -> usize {
|
||||||
@@ -17,61 +21,65 @@ fn div_ceil(x: usize, y: usize) -> usize {
|
|||||||
x / y + additive
|
x / y + additive
|
||||||
}
|
}
|
||||||
|
|
||||||
fn xor(x: &[u8], y: &[u8]) -> Result<Vec<u8>, InternalError> {
|
fn xor<L: ArrayLength<u8>>(x: GenericArray<u8, L>, y: GenericArray<u8, L>) -> GenericArray<u8, L> {
|
||||||
if x.len() != y.len() {
|
x.into_iter().zip(y).map(|(x1, x2)| x1 ^ x2).collect()
|
||||||
return Err(InternalError::HashToCurveError);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(x.iter().zip(y).map(|(&x1, &x2)| x1 ^ x2).collect())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Corresponds to the expand_message_xmd() function defined in
|
/// Corresponds to the expand_message_xmd() function defined in
|
||||||
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-10.txt>
|
/// <https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-10.txt>
|
||||||
pub fn expand_message_xmd<H: BlockInput + Digest>(
|
pub fn expand_message_xmd<
|
||||||
|
H: BlockInput + Digest,
|
||||||
|
L: ArrayLength<u8>,
|
||||||
|
D: ArrayLength<u8> + Add<U1>,
|
||||||
|
>(
|
||||||
msg: &[u8],
|
msg: &[u8],
|
||||||
dst: &[u8],
|
dst: GenericArray<u8, D>,
|
||||||
len_in_bytes: usize,
|
) -> Result<GenericArray<u8, L>, InternalError>
|
||||||
) -> Result<Vec<u8>, InternalError> {
|
where
|
||||||
let ell = div_ceil(len_in_bytes, <H as Digest>::OutputSize::USIZE);
|
<D as Add<U1>>::Output: ArrayLength<u8>,
|
||||||
|
{
|
||||||
|
let digest_len = <H as Digest>::OutputSize::USIZE;
|
||||||
|
let ell = div_ceil(L::USIZE, digest_len);
|
||||||
if ell > 255 {
|
if ell > 255 {
|
||||||
return Err(InternalError::HashToCurveError);
|
return Err(InternalError::HashToCurveError);
|
||||||
}
|
}
|
||||||
let dst_prime = [dst, &i2osp::<U1>(dst.len())?].concat();
|
let dst_prime = dst.concat(i2osp::<U1>(D::USIZE)?);
|
||||||
let z_pad = i2osp::<<H as BlockInput>::BlockSize>(0)?;
|
let z_pad = i2osp::<<H as BlockInput>::BlockSize>(0)?;
|
||||||
let l_i_b_str = i2osp::<U2>(len_in_bytes)?;
|
let l_i_b_str = i2osp::<U2>(L::USIZE)?;
|
||||||
let msg_prime = [
|
let msg_0 = i2osp::<U1>(0)?;
|
||||||
&z_pad,
|
let msg_prime =
|
||||||
msg,
|
core::array::IntoIter::new([z_pad.as_slice(), msg, &l_i_b_str, &msg_0, &dst_prime]);
|
||||||
&l_i_b_str,
|
|
||||||
i2osp::<U1>(0)?.as_slice(),
|
|
||||||
&dst_prime,
|
|
||||||
]
|
|
||||||
.concat();
|
|
||||||
|
|
||||||
let mut b: Vec<Vec<u8>> = alloc::vec![H::digest(&msg_prime).to_vec()]; // b[0]
|
|
||||||
|
|
||||||
let mut h = H::new();
|
let mut h = H::new();
|
||||||
h.update(&b[0]);
|
// b[0]
|
||||||
h.update(&i2osp::<U1>(1)?);
|
let b_0 = msg_prime
|
||||||
h.update(&dst_prime);
|
.into_iter()
|
||||||
b.push(h.finalize_reset().to_vec()); // b[1]
|
.fold(&mut h, |h, msg| {
|
||||||
|
h.update(msg);
|
||||||
|
h
|
||||||
|
})
|
||||||
|
.finalize_reset();
|
||||||
|
let mut b_i = GenericArray::default();
|
||||||
|
|
||||||
let mut uniform_bytes: Vec<u8> = Vec::new();
|
let mut uniform_bytes = GenericArray::default();
|
||||||
uniform_bytes.extend_from_slice(&b[1]);
|
|
||||||
|
|
||||||
for i in 2..(ell + 1) {
|
for (i, chunk) in (1..(ell + 1)).zip(uniform_bytes.chunks_mut(digest_len)) {
|
||||||
h.update(xor(&b[0], &b[i - 1])?);
|
h.update(xor(b_0.clone(), b_i.clone()));
|
||||||
h.update(&i2osp::<U1>(i)?);
|
h.update(i2osp::<U1>(i)?);
|
||||||
h.update(&dst_prime);
|
h.update(&dst_prime);
|
||||||
b.push(h.finalize_reset().to_vec()); // b[i]
|
b_i = h.finalize_reset();
|
||||||
uniform_bytes.extend_from_slice(&b[i]);
|
chunk.copy_from_slice(&b_i[..digest_len.min(chunk.len())]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(uniform_bytes[..len_in_bytes].to_vec())
|
Ok(uniform_bytes)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use generic_array::{
|
||||||
|
typenum::{U128, U32},
|
||||||
|
GenericArray,
|
||||||
|
};
|
||||||
|
|
||||||
struct Params {
|
struct Params {
|
||||||
msg: &'static str,
|
msg: &'static str,
|
||||||
@@ -180,14 +188,16 @@ mod tests {
|
|||||||
378fba044a31f5cb44583a892f5969dcd73b3fa128816e",
|
378fba044a31f5cb44583a892f5969dcd73b3fa128816e",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
let dst = "QUUX-V01-CS02-with-expander";
|
let dst = GenericArray::from(*b"QUUX-V01-CS02-with-expander");
|
||||||
|
|
||||||
for tv in test_vectors {
|
for tv in test_vectors {
|
||||||
let uniform_bytes = super::expand_message_xmd::<sha2::Sha256>(
|
let uniform_bytes = match tv.len_in_bytes {
|
||||||
tv.msg.as_bytes(),
|
32 => super::expand_message_xmd::<sha2::Sha256, U32, _>(tv.msg.as_bytes(), dst)
|
||||||
dst.as_bytes(),
|
.map(|bytes| bytes.to_vec()),
|
||||||
tv.len_in_bytes,
|
128 => super::expand_message_xmd::<sha2::Sha256, U128, _>(tv.msg.as_bytes(), dst)
|
||||||
)
|
.map(|bytes| bytes.to_vec()),
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(tv.uniform_bytes, hex::encode(uniform_bytes));
|
assert_eq!(tv.uniform_bytes, hex::encode(uniform_bytes));
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-18
@@ -7,17 +7,32 @@
|
|||||||
|
|
||||||
//! Defines the Group trait to specify the underlying prime order group
|
//! Defines the Group trait to specify the underlying prime order group
|
||||||
|
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "ristretto255_u64",
|
||||||
|
feature = "ristretto255_u32",
|
||||||
|
feature = "ristretto255_fiat_u64",
|
||||||
|
feature = "ristretto255_fiat_u32",
|
||||||
|
feature = "ristretto255_simd",
|
||||||
|
feature = "p256",
|
||||||
|
))]
|
||||||
mod expand;
|
mod expand;
|
||||||
#[cfg(feature = "p256")]
|
#[cfg(feature = "p256")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "p256")))]
|
mod p256;
|
||||||
pub(crate) mod p256;
|
#[cfg(any(
|
||||||
|
feature = "ristretto255_u64",
|
||||||
|
feature = "ristretto255_u32",
|
||||||
|
feature = "ristretto255_fiat_u64",
|
||||||
|
feature = "ristretto255_fiat_u32",
|
||||||
|
feature = "ristretto255_simd",
|
||||||
|
))]
|
||||||
mod ristretto;
|
mod ristretto;
|
||||||
|
|
||||||
use crate::errors::InternalError;
|
use crate::errors::InternalError;
|
||||||
use core::ops::{Add, Mul, Sub};
|
use core::ops::{Add, Mul, Sub};
|
||||||
use digest::{BlockInput, Digest};
|
use digest::{BlockInput, Digest};
|
||||||
use generic_array::{ArrayLength, GenericArray};
|
use generic_array::{typenum::U1, ArrayLength, GenericArray};
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand_core::{CryptoRng, RngCore};
|
||||||
|
use subtle::ConstantTimeEq;
|
||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
|
|
||||||
/// A prime-order subgroup of a base field (EC, prime-order field ...). This
|
/// A prime-order subgroup of a base field (EC, prime-order field ...). This
|
||||||
@@ -25,6 +40,7 @@ use zeroize::Zeroize;
|
|||||||
pub trait Group:
|
pub trait Group:
|
||||||
Copy
|
Copy
|
||||||
+ Sized
|
+ Sized
|
||||||
|
+ ConstantTimeEq
|
||||||
+ for<'a> Mul<&'a <Self as Group>::Scalar, Output = Self>
|
+ for<'a> Mul<&'a <Self as Group>::Scalar, Output = Self>
|
||||||
+ for<'a> Add<&'a Self, Output = Self>
|
+ for<'a> Add<&'a Self, Output = Self>
|
||||||
{
|
{
|
||||||
@@ -33,18 +49,25 @@ pub trait Group:
|
|||||||
const SUITE_ID: usize;
|
const SUITE_ID: usize;
|
||||||
|
|
||||||
/// transforms a password and domain separation tag (DST) into a curve point
|
/// transforms a password and domain separation tag (DST) into a curve point
|
||||||
fn hash_to_curve<H: BlockInput + Digest>(msg: &[u8], dst: &[u8])
|
fn hash_to_curve<H: BlockInput + Digest, D: ArrayLength<u8> + Add<U1>>(
|
||||||
-> Result<Self, InternalError>;
|
msg: &[u8],
|
||||||
|
dst: GenericArray<u8, D>,
|
||||||
|
) -> Result<Self, InternalError>
|
||||||
|
where
|
||||||
|
<D as Add<U1>>::Output: ArrayLength<u8>;
|
||||||
|
|
||||||
/// Hashes a slice of pseudo-random bytes to a scalar
|
/// Hashes a slice of pseudo-random bytes to a scalar
|
||||||
fn hash_to_scalar<H: BlockInput + Digest>(
|
fn hash_to_scalar<H: BlockInput + Digest, D: ArrayLength<u8> + Add<U1>>(
|
||||||
input: &[u8],
|
input: &[u8],
|
||||||
dst: &[u8],
|
dst: GenericArray<u8, D>,
|
||||||
) -> Result<Self::Scalar, InternalError>;
|
) -> Result<Self::Scalar, InternalError>
|
||||||
|
where
|
||||||
|
<D as Add<U1>>::Output: ArrayLength<u8>;
|
||||||
|
|
||||||
/// The type of base field scalars
|
/// The type of base field scalars
|
||||||
type Scalar: Zeroize
|
type Scalar: Zeroize
|
||||||
+ Copy
|
+ Copy
|
||||||
|
+ ConstantTimeEq
|
||||||
+ for<'a> Add<&'a Self::Scalar, Output = Self::Scalar>
|
+ for<'a> Add<&'a Self::Scalar, Output = Self::Scalar>
|
||||||
+ for<'a> Sub<&'a Self::Scalar, Output = Self::Scalar>
|
+ for<'a> Sub<&'a Self::Scalar, Output = Self::Scalar>
|
||||||
+ for<'a> Mul<&'a Self::Scalar, Output = Self::Scalar>;
|
+ for<'a> Mul<&'a Self::Scalar, Output = Self::Scalar>;
|
||||||
@@ -63,7 +86,7 @@ pub trait Group:
|
|||||||
scalar_bits: impl Into<&'a GenericArray<u8, Self::ScalarLen>>,
|
scalar_bits: impl Into<&'a GenericArray<u8, Self::ScalarLen>>,
|
||||||
) -> Result<Self::Scalar, InternalError> {
|
) -> Result<Self::Scalar, InternalError> {
|
||||||
let scalar = Self::from_scalar_slice_unchecked(scalar_bits.into())?;
|
let scalar = Self::from_scalar_slice_unchecked(scalar_bits.into())?;
|
||||||
if Self::ct_equal_scalar(&scalar, &Self::scalar_zero()) {
|
if scalar.ct_eq(&Self::scalar_zero()).into() {
|
||||||
return Err(InternalError::ZeroScalarError);
|
return Err(InternalError::ZeroScalarError);
|
||||||
}
|
}
|
||||||
Ok(scalar)
|
Ok(scalar)
|
||||||
@@ -93,7 +116,7 @@ pub trait Group:
|
|||||||
) -> Result<Self, InternalError> {
|
) -> Result<Self, InternalError> {
|
||||||
let elem = Self::from_element_slice_unchecked(element_bits.into())?;
|
let elem = Self::from_element_slice_unchecked(element_bits.into())?;
|
||||||
|
|
||||||
if Self::ct_equal(&elem, &<Self as Group>::identity()) {
|
if Self::ct_eq(&elem, &<Self as Group>::identity()).into() {
|
||||||
// found the identity element
|
// found the identity element
|
||||||
return Err(InternalError::PointError);
|
return Err(InternalError::PointError);
|
||||||
}
|
}
|
||||||
@@ -109,7 +132,7 @@ pub trait Group:
|
|||||||
|
|
||||||
/// Returns if the group element is equal to the identity (1)
|
/// Returns if the group element is equal to the identity (1)
|
||||||
fn is_identity(&self) -> bool {
|
fn is_identity(&self) -> bool {
|
||||||
self.ct_equal(&<Self as Group>::identity())
|
self.ct_eq(&<Self as Group>::identity()).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the identity group element
|
/// Returns the identity group element
|
||||||
@@ -118,12 +141,6 @@ pub trait Group:
|
|||||||
/// Returns the scalar representing zero
|
/// Returns the scalar representing zero
|
||||||
fn scalar_zero() -> Self::Scalar;
|
fn scalar_zero() -> Self::Scalar;
|
||||||
|
|
||||||
/// Compares in constant time if the group elements are equal
|
|
||||||
fn ct_equal(&self, other: &Self) -> bool;
|
|
||||||
|
|
||||||
/// Compares in constant time if the scalars are equal
|
|
||||||
fn ct_equal_scalar(s1: &Self::Scalar, s2: &Self::Scalar) -> bool;
|
|
||||||
|
|
||||||
/// Set the contents of self to the identity value
|
/// Set the contents of self to the identity value
|
||||||
fn zeroize(&mut self) {
|
fn zeroize(&mut self) {
|
||||||
*self = <Self as Group>::identity();
|
*self = <Self as Group>::identity();
|
||||||
|
|||||||
+27
-26
@@ -18,7 +18,7 @@ use crate::errors::InternalError;
|
|||||||
use core::ops::{Add, Div, Mul, Neg};
|
use core::ops::{Add, Div, Mul, Neg};
|
||||||
use core::str::FromStr;
|
use core::str::FromStr;
|
||||||
use digest::{BlockInput, Digest};
|
use digest::{BlockInput, Digest};
|
||||||
use generic_array::typenum::{U32, U33};
|
use generic_array::typenum::{Unsigned, U1, U2, U32, U33, U48};
|
||||||
use generic_array::{ArrayLength, GenericArray};
|
use generic_array::{ArrayLength, GenericArray};
|
||||||
use num_bigint::{BigInt, Sign};
|
use num_bigint::{BigInt, Sign};
|
||||||
use num_integer::Integer;
|
use num_integer::Integer;
|
||||||
@@ -29,21 +29,26 @@ use p256_::elliptic_curve::group::GroupEncoding;
|
|||||||
use p256_::elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint};
|
use p256_::elliptic_curve::sec1::{FromEncodedPoint, ToEncodedPoint};
|
||||||
use p256_::elliptic_curve::Field;
|
use p256_::elliptic_curve::Field;
|
||||||
use p256_::{AffinePoint, EncodedPoint, ProjectivePoint};
|
use p256_::{AffinePoint, EncodedPoint, ProjectivePoint};
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand_core::{CryptoRng, RngCore};
|
||||||
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
|
use subtle::{Choice, ConditionallySelectable};
|
||||||
|
|
||||||
|
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-8.2
|
||||||
// `L: 48`
|
// `L: 48`
|
||||||
pub const L: usize = 48;
|
pub type L = U48;
|
||||||
|
|
||||||
|
#[cfg(feature = "p256")]
|
||||||
impl Group for ProjectivePoint {
|
impl Group for ProjectivePoint {
|
||||||
const SUITE_ID: usize = 0x0003;
|
const SUITE_ID: usize = 0x0003;
|
||||||
|
|
||||||
// Implements the `hash_to_curve()` function from
|
// Implements the `hash_to_curve()` function from
|
||||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3
|
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-3
|
||||||
fn hash_to_curve<H: BlockInput + Digest>(
|
fn hash_to_curve<H: BlockInput + Digest, D: ArrayLength<u8> + Add<U1>>(
|
||||||
msg: &[u8],
|
msg: &[u8],
|
||||||
dst: &[u8],
|
dst: GenericArray<u8, D>,
|
||||||
) -> Result<Self, InternalError> {
|
) -> Result<Self, InternalError>
|
||||||
|
where
|
||||||
|
<D as Add<U1>>::Output: ArrayLength<u8>,
|
||||||
|
{
|
||||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-8.2
|
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-8.2
|
||||||
// `p: 2^256 - 2^224 + 2^192 + 2^96 - 1`
|
// `p: 2^256 - 2^224 + 2^192 + 2^96 - 1`
|
||||||
const P: Lazy<BigInt> = Lazy::new(|| {
|
const P: Lazy<BigInt> = Lazy::new(|| {
|
||||||
@@ -69,11 +74,12 @@ impl Group for ProjectivePoint {
|
|||||||
// `hash_to_curve` calls `hash_to_field` with a `count` of `2`
|
// `hash_to_curve` calls `hash_to_field` with a `count` of `2`
|
||||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3
|
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3
|
||||||
// `hash_to_field` calls `expand_message` with a `len_in_bytes` of `count * L`
|
// `hash_to_field` calls `expand_message` with a `len_in_bytes` of `count * L`
|
||||||
let uniform_bytes = super::expand::expand_message_xmd::<H>(msg, dst, 2 * L)?;
|
let uniform_bytes =
|
||||||
|
super::expand::expand_message_xmd::<H, <L as Mul<U2>>::Output, _>(msg, dst)?;
|
||||||
|
|
||||||
// hash to curve
|
// hash to curve
|
||||||
let (q0x, q0y) = hash_to_curve_simple_swu(&uniform_bytes[..L], &A, &B, &P, &Z);
|
let (q0x, q0y) = hash_to_curve_simple_swu(&uniform_bytes[..L::USIZE], &A, &B, &P, &Z);
|
||||||
let (q1x, q1y) = hash_to_curve_simple_swu(&uniform_bytes[L..], &A, &B, &P, &Z);
|
let (q1x, q1y) = hash_to_curve_simple_swu(&uniform_bytes[L::USIZE..], &A, &B, &P, &Z);
|
||||||
|
|
||||||
// convert to `p256` types
|
// convert to `p256` types
|
||||||
let p0 = AffinePoint::from_encoded_point(&EncodedPoint::from_affine_coordinates(
|
let p0 = AffinePoint::from_encoded_point(&EncodedPoint::from_affine_coordinates(
|
||||||
@@ -91,10 +97,13 @@ impl Group for ProjectivePoint {
|
|||||||
|
|
||||||
// Implements the `HashToScalar()` function from
|
// Implements the `HashToScalar()` function from
|
||||||
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-07.html#section-4.3
|
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-07.html#section-4.3
|
||||||
fn hash_to_scalar<H: BlockInput + Digest>(
|
fn hash_to_scalar<H: BlockInput + Digest, D: ArrayLength<u8> + Add<U1>>(
|
||||||
input: &[u8],
|
input: &[u8],
|
||||||
dst: &[u8],
|
dst: GenericArray<u8, D>,
|
||||||
) -> Result<Self::Scalar, InternalError> {
|
) -> Result<Self::Scalar, InternalError>
|
||||||
|
where
|
||||||
|
<D as Add<U1>>::Output: ArrayLength<u8>,
|
||||||
|
{
|
||||||
// https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf#[{%22num%22:211,%22gen%22:0},{%22name%22:%22XYZ%22},70,700,0]
|
// https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf#[{%22num%22:211,%22gen%22:0},{%22name%22:%22XYZ%22},70,700,0]
|
||||||
// P-256 `n` is defined as `115792089210356248762697446949407573529996955224135760342 422259061068512044369`
|
// P-256 `n` is defined as `115792089210356248762697446949407573529996955224135760342 422259061068512044369`
|
||||||
const N: Lazy<BigInt> = Lazy::new(|| {
|
const N: Lazy<BigInt> = Lazy::new(|| {
|
||||||
@@ -106,7 +115,7 @@ impl Group for ProjectivePoint {
|
|||||||
|
|
||||||
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3
|
// https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-hash-to-curve-11#section-5.3
|
||||||
// `HashToScalar` is `hash_to_field`
|
// `HashToScalar` is `hash_to_field`
|
||||||
let uniform_bytes = super::expand::expand_message_xmd::<H>(input, dst, L)?;
|
let uniform_bytes = super::expand::expand_message_xmd::<H, L, _>(input, dst)?;
|
||||||
let bytes = BigInt::from_bytes_be(Sign::Plus, &uniform_bytes)
|
let bytes = BigInt::from_bytes_be(Sign::Plus, &uniform_bytes)
|
||||||
.mod_floor(&N)
|
.mod_floor(&N)
|
||||||
.to_bytes_be()
|
.to_bytes_be()
|
||||||
@@ -164,14 +173,6 @@ impl Group for ProjectivePoint {
|
|||||||
fn scalar_zero() -> Self::Scalar {
|
fn scalar_zero() -> Self::Scalar {
|
||||||
Self::Scalar::zero()
|
Self::Scalar::zero()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ct_equal(&self, other: &Self) -> bool {
|
|
||||||
self.ct_eq(other).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ct_equal_scalar(s1: &Self::Scalar, s2: &Self::Scalar) -> bool {
|
|
||||||
s1.ct_eq(s2).into()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Corresponds to the hash_to_curve_simple_swu() function defined in
|
/// Corresponds to the hash_to_curve_simple_swu() function defined in
|
||||||
@@ -431,6 +432,7 @@ fn hash_to_curve_simple_swu<N: ArrayLength<u8>>(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use generic_array::typenum::U96;
|
||||||
|
|
||||||
struct Params {
|
struct Params {
|
||||||
msg: &'static str,
|
msg: &'static str,
|
||||||
@@ -531,13 +533,12 @@ mod tests {
|
|||||||
q1y: "f6ed88a7aab56a488100e6f1174fa9810b47db13e86be999644922961206e184",
|
q1y: "f6ed88a7aab56a488100e6f1174fa9810b47db13e86be999644922961206e184",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
let dst = "QUUX-V01-CS02-with-P256_XMD:SHA-256_SSWU_RO_";
|
let dst = GenericArray::from(*b"QUUX-V01-CS02-with-P256_XMD:SHA-256_SSWU_RO_");
|
||||||
|
|
||||||
for tv in test_vectors {
|
for tv in test_vectors {
|
||||||
let uniform_bytes = super::super::expand::expand_message_xmd::<sha2::Sha256>(
|
let uniform_bytes = super::super::expand::expand_message_xmd::<sha2::Sha256, U96, _>(
|
||||||
tv.msg.as_bytes(),
|
tv.msg.as_bytes(),
|
||||||
dst.as_bytes(),
|
dst,
|
||||||
96,
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|||||||
+27
-19
@@ -8,6 +8,7 @@
|
|||||||
use super::Group;
|
use super::Group;
|
||||||
use crate::errors::InternalError;
|
use crate::errors::InternalError;
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
|
use core::ops::Add;
|
||||||
use curve25519_dalek::{
|
use curve25519_dalek::{
|
||||||
constants::RISTRETTO_BASEPOINT_POINT,
|
constants::RISTRETTO_BASEPOINT_POINT,
|
||||||
ristretto::{CompressedRistretto, RistrettoPoint},
|
ristretto::{CompressedRistretto, RistrettoPoint},
|
||||||
@@ -15,21 +16,33 @@ use curve25519_dalek::{
|
|||||||
traits::Identity,
|
traits::Identity,
|
||||||
};
|
};
|
||||||
use digest::{BlockInput, Digest};
|
use digest::{BlockInput, Digest};
|
||||||
use generic_array::{typenum::U32, GenericArray};
|
use generic_array::{
|
||||||
use rand::{CryptoRng, RngCore};
|
typenum::{U1, U32, U64},
|
||||||
use subtle::ConstantTimeEq;
|
ArrayLength, GenericArray,
|
||||||
|
};
|
||||||
|
use rand_core::{CryptoRng, RngCore};
|
||||||
|
|
||||||
/// The implementation of such a subgroup for Ristretto
|
/// The implementation of such a subgroup for Ristretto
|
||||||
|
#[cfg(any(
|
||||||
|
feature = "ristretto255_u64",
|
||||||
|
feature = "ristretto255_u32",
|
||||||
|
feature = "ristretto255_fiat_u64",
|
||||||
|
feature = "ristretto255_fiat_u32",
|
||||||
|
feature = "ristretto255_simd",
|
||||||
|
))]
|
||||||
impl Group for RistrettoPoint {
|
impl Group for RistrettoPoint {
|
||||||
const SUITE_ID: usize = 0x0001;
|
const SUITE_ID: usize = 0x0001;
|
||||||
|
|
||||||
// Implements the `hash_to_ristretto255()` function from
|
// Implements the `hash_to_ristretto255()` function from
|
||||||
// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-10.txt
|
// https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-10.txt
|
||||||
fn hash_to_curve<H: BlockInput + Digest>(
|
fn hash_to_curve<H: BlockInput + Digest, D: ArrayLength<u8> + Add<U1>>(
|
||||||
msg: &[u8],
|
msg: &[u8],
|
||||||
dst: &[u8],
|
dst: GenericArray<u8, D>,
|
||||||
) -> Result<Self, InternalError> {
|
) -> Result<Self, InternalError>
|
||||||
let uniform_bytes = super::expand::expand_message_xmd::<H>(msg, dst, 64)?;
|
where
|
||||||
|
<D as Add<U1>>::Output: ArrayLength<u8>,
|
||||||
|
{
|
||||||
|
let uniform_bytes = super::expand::expand_message_xmd::<H, U64, _>(msg, dst)?;
|
||||||
|
|
||||||
Ok(RistrettoPoint::from_uniform_bytes(
|
Ok(RistrettoPoint::from_uniform_bytes(
|
||||||
uniform_bytes
|
uniform_bytes
|
||||||
@@ -41,11 +54,14 @@ impl Group for RistrettoPoint {
|
|||||||
|
|
||||||
// Implements the `HashToScalar()` function from
|
// Implements the `HashToScalar()` function from
|
||||||
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-07.html#section-4.1
|
// https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-07.html#section-4.1
|
||||||
fn hash_to_scalar<H: BlockInput + Digest>(
|
fn hash_to_scalar<H: BlockInput + Digest, D: ArrayLength<u8> + Add<U1>>(
|
||||||
input: &[u8],
|
input: &[u8],
|
||||||
dst: &[u8],
|
dst: GenericArray<u8, D>,
|
||||||
) -> Result<Self::Scalar, InternalError> {
|
) -> Result<Self::Scalar, InternalError>
|
||||||
let uniform_bytes = super::expand::expand_message_xmd::<H>(input, dst, 64)?;
|
where
|
||||||
|
<D as Add<U1>>::Output: ArrayLength<u8>,
|
||||||
|
{
|
||||||
|
let uniform_bytes = super::expand::expand_message_xmd::<H, U64, _>(input, dst)?;
|
||||||
|
|
||||||
Ok(Scalar::from_bytes_mod_order_wide(
|
Ok(Scalar::from_bytes_mod_order_wide(
|
||||||
uniform_bytes
|
uniform_bytes
|
||||||
@@ -121,12 +137,4 @@ impl Group for RistrettoPoint {
|
|||||||
fn scalar_zero() -> Self::Scalar {
|
fn scalar_zero() -> Self::Scalar {
|
||||||
Self::Scalar::zero()
|
Self::Scalar::zero()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ct_equal(&self, other: &Self) -> bool {
|
|
||||||
ConstantTimeEq::ct_eq(self, other).into()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ct_equal_scalar(s1: &Self::Scalar, s2: &Self::Scalar) -> bool {
|
|
||||||
ConstantTimeEq::ct_eq(s1, s2).into()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-9
@@ -118,12 +118,11 @@ macro_rules! impl_traits_for {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serialize")]
|
#[cfg(feature = "serde")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
|
impl$(<$($gen$(: $bound1 $(+ $bound2)*)?),+>)? serde_::Serialize for $name$(<$($gen),+>)? {
|
||||||
impl$(<$($gen$(: $bound1 $(+ $bound2)*)?),+>)? serde::Serialize for $name$(<$($gen),+>)? {
|
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: serde::Serializer,
|
S: serde_::Serializer,
|
||||||
{
|
{
|
||||||
if serializer.is_human_readable() {
|
if serializer.is_human_readable() {
|
||||||
serializer.serialize_str(&base64::encode(&self.serialize()))
|
serializer.serialize_str(&base64::encode(&self.serialize()))
|
||||||
@@ -133,14 +132,13 @@ macro_rules! impl_traits_for {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "serialize")]
|
#[cfg(feature = "serde")]
|
||||||
#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
|
impl<'de, $($($gen$(: $bound1 $(+ $bound2)*)?),+)?> serde_::Deserialize<'de> for $name$(<$($gen),+>)? {
|
||||||
impl<'de, $($($gen$(: $bound1 $(+ $bound2)*)?),+)?> serde::Deserialize<'de> for $name$(<$($gen),+>)? {
|
|
||||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
where
|
where
|
||||||
D: serde::Deserializer<'de>,
|
D: serde_::Deserializer<'de>,
|
||||||
{
|
{
|
||||||
use serde::de::Error;
|
use serde_::de::Error;
|
||||||
|
|
||||||
if deserializer.is_human_readable() {
|
if deserializer.is_human_readable() {
|
||||||
let s = <&str>::deserialize(deserializer)?;
|
let s = <&str>::deserialize(deserializer)?;
|
||||||
|
|||||||
+6
-7
@@ -398,16 +398,17 @@
|
|||||||
//! - The `p256` feature enables using p256 as the underlying group for the [Group](group::Group) choice.
|
//! - The `p256` feature enables using p256 as the underlying group for the [Group](group::Group) choice.
|
||||||
//! Note that this is currently an experimental feature ⚠️, and is not yet ready for production use.
|
//! Note that this is currently an experimental feature ⚠️, and is not yet ready for production use.
|
||||||
//!
|
//!
|
||||||
//! - The `serialize` feature, enabled by default, provides convenience functions for serializing and deserializing with
|
//! - The `serde` feature, enabled by default, provides convenience functions for serializing and deserializing with
|
||||||
//! [serde](https://serde.rs/).
|
//! [serde](https://serde.rs/).
|
||||||
//!
|
//!
|
||||||
//! - The `u32_backend` and `u64_backend` features are re-exported from
|
//! - The backend features are re-exported from
|
||||||
//! [curve25519-dalek](https://doc.dalek.rs/curve25519_dalek/index.html#backends-and-features) and allow for selecting
|
//! [curve25519-dalek](https://doc.dalek.rs/curve25519_dalek/index.html#backends-and-features) and allow for selecting
|
||||||
//! the corresponding backend for the curve arithmetic used. The `u64_backend` feature is included as the default.
|
//! the corresponding backend for the curve arithmetic used. The `ristretto255_u64` feature is included as the default.
|
||||||
|
//! Other features are mapped as `ristretto255_u32`, `ristretto255_fiat_u64` and `ristretto255_fiat_u32`.
|
||||||
//!
|
//!
|
||||||
//! - The `simd_backend` feature is re-exported from
|
//! - The `ristretto255_simd` feature is re-exported from
|
||||||
//! [curve25519-dalek](https://doc.dalek.rs/curve25519_dalek/index.html#backends-and-features) and enables parallel formulas,
|
//! [curve25519-dalek](https://doc.dalek.rs/curve25519_dalek/index.html#backends-and-features) and enables parallel formulas,
|
||||||
//! using either AVX2 or AVX512-IFMA. This will automatically enable the `u64_backend` and requires Rust nightly.
|
//! using either AVX2 or AVX512-IFMA. This will automatically enable the `ristretto255_u64` and requires Rust nightly.
|
||||||
|
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
#![warn(clippy::cargo, missing_docs)]
|
#![warn(clippy::cargo, missing_docs)]
|
||||||
@@ -429,8 +430,6 @@ mod tests;
|
|||||||
|
|
||||||
// Exports
|
// Exports
|
||||||
|
|
||||||
pub use rand;
|
|
||||||
|
|
||||||
pub use crate::voprf::{
|
pub use crate::voprf::{
|
||||||
BlindedElement, EvaluationElement, NonVerifiableClient, NonVerifiableClientBlindResult,
|
BlindedElement, EvaluationElement, NonVerifiableClient, NonVerifiableClientBlindResult,
|
||||||
NonVerifiableServer, NonVerifiableServerEvaluateResult, VerifiableClient,
|
NonVerifiableServer, NonVerifiableServerEvaluateResult, VerifiableClient,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use core::cmp::min;
|
use core::cmp::min;
|
||||||
use rand::{CryptoRng, Error, RngCore};
|
use rand_core::{CryptoRng, Error, RngCore};
|
||||||
|
|
||||||
/// A simple implementation of `RngCore` for testing purposes.
|
/// A simple implementation of `RngCore` for testing purposes.
|
||||||
///
|
///
|
||||||
|
|||||||
+17
-16
@@ -21,7 +21,8 @@ use generic_array::{
|
|||||||
typenum::{U1, U11, U2},
|
typenum::{U1, U11, U2},
|
||||||
GenericArray,
|
GenericArray,
|
||||||
};
|
};
|
||||||
use rand::{CryptoRng, RngCore};
|
use rand_core::{CryptoRng, RngCore};
|
||||||
|
use subtle::ConstantTimeEq;
|
||||||
|
|
||||||
///////////////
|
///////////////
|
||||||
// Constants //
|
// Constants //
|
||||||
@@ -366,7 +367,7 @@ impl<G: Group, H: BlockInput + Digest> NonVerifiableServer<G, H> {
|
|||||||
pub fn new_from_seed(seed: &[u8]) -> Result<Self, InternalError> {
|
pub fn new_from_seed(seed: &[u8]) -> Result<Self, InternalError> {
|
||||||
let dst =
|
let dst =
|
||||||
GenericArray::from(*STR_HASH_TO_SCALAR).concat(get_context_string::<G>(Mode::Base)?);
|
GenericArray::from(*STR_HASH_TO_SCALAR).concat(get_context_string::<G>(Mode::Base)?);
|
||||||
let sk = G::hash_to_scalar::<H>(seed, &dst)?;
|
let sk = G::hash_to_scalar::<H, _>(seed, dst)?;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
sk,
|
sk,
|
||||||
hash: PhantomData,
|
hash: PhantomData,
|
||||||
@@ -394,7 +395,7 @@ impl<G: Group, H: BlockInput + Digest> NonVerifiableServer<G, H> {
|
|||||||
.concat();
|
.concat();
|
||||||
let dst =
|
let dst =
|
||||||
GenericArray::from(*STR_HASH_TO_SCALAR).concat(get_context_string::<G>(Mode::Base)?);
|
GenericArray::from(*STR_HASH_TO_SCALAR).concat(get_context_string::<G>(Mode::Base)?);
|
||||||
let m = G::hash_to_scalar::<H>(&context, &dst)?;
|
let m = G::hash_to_scalar::<H, _>(&context, dst)?;
|
||||||
let t = self.sk + &m;
|
let t = self.sk + &m;
|
||||||
let evaluation_element = blinded_element.value * &G::scalar_invert(&t);
|
let evaluation_element = blinded_element.value * &G::scalar_invert(&t);
|
||||||
Ok(NonVerifiableServerEvaluateResult {
|
Ok(NonVerifiableServerEvaluateResult {
|
||||||
@@ -439,7 +440,7 @@ impl<G: Group, H: BlockInput + Digest> VerifiableServer<G, H> {
|
|||||||
pub fn new_from_seed(seed: &[u8]) -> Result<Self, InternalError> {
|
pub fn new_from_seed(seed: &[u8]) -> Result<Self, InternalError> {
|
||||||
let dst = GenericArray::from(*STR_HASH_TO_SCALAR)
|
let dst = GenericArray::from(*STR_HASH_TO_SCALAR)
|
||||||
.concat(get_context_string::<G>(Mode::Verifiable)?);
|
.concat(get_context_string::<G>(Mode::Verifiable)?);
|
||||||
let sk = G::hash_to_scalar::<H>(seed, &dst)?;
|
let sk = G::hash_to_scalar::<H, _>(seed, dst)?;
|
||||||
let pk = G::base_point() * &sk;
|
let pk = G::base_point() * &sk;
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
sk,
|
sk,
|
||||||
@@ -490,7 +491,7 @@ impl<G: Group, H: BlockInput + Digest> VerifiableServer<G, H> {
|
|||||||
.concat();
|
.concat();
|
||||||
let dst = GenericArray::from(*STR_HASH_TO_SCALAR)
|
let dst = GenericArray::from(*STR_HASH_TO_SCALAR)
|
||||||
.concat(get_context_string::<G>(Mode::Verifiable)?);
|
.concat(get_context_string::<G>(Mode::Verifiable)?);
|
||||||
let m = G::hash_to_scalar::<H>(&context, &dst)?;
|
let m = G::hash_to_scalar::<H, _>(&context, dst)?;
|
||||||
let t = self.sk + &m;
|
let t = self.sk + &m;
|
||||||
let evaluation_elements: Vec<EvaluationElement<G, H>> = blinded_elements
|
let evaluation_elements: Vec<EvaluationElement<G, H>> = blinded_elements
|
||||||
.into_iter()
|
.into_iter()
|
||||||
@@ -640,7 +641,7 @@ fn blind<G: Group, H: BlockInput + Digest, R: RngCore + CryptoRng>(
|
|||||||
// Choose a random scalar that must be non-zero
|
// Choose a random scalar that must be non-zero
|
||||||
let blind = <G as Group>::random_nonzero_scalar(blinding_factor_rng);
|
let blind = <G as Group>::random_nonzero_scalar(blinding_factor_rng);
|
||||||
let dst = GenericArray::from(*STR_HASH_TO_GROUP).concat(get_context_string::<G>(mode)?);
|
let dst = GenericArray::from(*STR_HASH_TO_GROUP).concat(get_context_string::<G>(mode)?);
|
||||||
let hashed_point = <G as Group>::hash_to_curve::<H>(input, &dst)?;
|
let hashed_point = <G as Group>::hash_to_curve::<H, _>(input, dst)?;
|
||||||
let blinded_element = hashed_point * &blind;
|
let blinded_element = hashed_point * &blind;
|
||||||
Ok((blind, blinded_element))
|
Ok((blind, blinded_element))
|
||||||
}
|
}
|
||||||
@@ -664,7 +665,7 @@ where
|
|||||||
|
|
||||||
let dst =
|
let dst =
|
||||||
GenericArray::from(*STR_HASH_TO_SCALAR).concat(get_context_string::<G>(Mode::Verifiable)?);
|
GenericArray::from(*STR_HASH_TO_SCALAR).concat(get_context_string::<G>(Mode::Verifiable)?);
|
||||||
let m = G::hash_to_scalar::<H>(&context, &dst)?;
|
let m = G::hash_to_scalar::<H, _>(&context, dst)?;
|
||||||
|
|
||||||
let g = G::base_point();
|
let g = G::base_point();
|
||||||
let t = g * &m;
|
let t = g * &m;
|
||||||
@@ -713,7 +714,7 @@ fn generate_proof<G: Group, H: BlockInput + Digest, R: RngCore + CryptoRng>(
|
|||||||
let hash_to_scalar_dst =
|
let hash_to_scalar_dst =
|
||||||
GenericArray::from(*STR_HASH_TO_SCALAR).concat(get_context_string::<G>(Mode::Verifiable)?);
|
GenericArray::from(*STR_HASH_TO_SCALAR).concat(get_context_string::<G>(Mode::Verifiable)?);
|
||||||
|
|
||||||
let c_scalar = G::hash_to_scalar::<H>(&h2_input, &hash_to_scalar_dst)?;
|
let c_scalar = G::hash_to_scalar::<H, _>(&h2_input, hash_to_scalar_dst)?;
|
||||||
let s_scalar = r - &(c_scalar * &k);
|
let s_scalar = r - &(c_scalar * &k);
|
||||||
|
|
||||||
Ok(Proof {
|
Ok(Proof {
|
||||||
@@ -749,9 +750,9 @@ fn verify_proof<G: Group, H: BlockInput + Digest>(
|
|||||||
|
|
||||||
let hash_to_scalar_dst =
|
let hash_to_scalar_dst =
|
||||||
GenericArray::from(*STR_HASH_TO_SCALAR).concat(get_context_string::<G>(Mode::Verifiable)?);
|
GenericArray::from(*STR_HASH_TO_SCALAR).concat(get_context_string::<G>(Mode::Verifiable)?);
|
||||||
let c = G::hash_to_scalar::<H>(&h2_input, &hash_to_scalar_dst)?;
|
let c = G::hash_to_scalar::<H, _>(&h2_input, hash_to_scalar_dst)?;
|
||||||
|
|
||||||
match G::ct_equal_scalar(&c, &proof.c_scalar) {
|
match c.ct_eq(&proof.c_scalar).into() {
|
||||||
true => Ok(()),
|
true => Ok(()),
|
||||||
false => Err(InternalError::ProofVerificationError),
|
false => Err(InternalError::ProofVerificationError),
|
||||||
}
|
}
|
||||||
@@ -815,7 +816,7 @@ fn compute_composites<G: Group, H: BlockInput + Digest>(
|
|||||||
.concat();
|
.concat();
|
||||||
let dst = GenericArray::from(*STR_HASH_TO_SCALAR)
|
let dst = GenericArray::from(*STR_HASH_TO_SCALAR)
|
||||||
.concat(get_context_string::<G>(Mode::Verifiable)?);
|
.concat(get_context_string::<G>(Mode::Verifiable)?);
|
||||||
let di = G::hash_to_scalar::<H>(&h2_input, &dst)?;
|
let di = G::hash_to_scalar::<H, _>(&h2_input, dst)?;
|
||||||
m = c.value * &di + &m;
|
m = c.value * &di + &m;
|
||||||
z = match k_option {
|
z = match k_option {
|
||||||
Some(_) => z,
|
Some(_) => z,
|
||||||
@@ -860,7 +861,7 @@ mod tests {
|
|||||||
) -> GenericArray<u8, <H as Digest>::OutputSize> {
|
) -> GenericArray<u8, <H as Digest>::OutputSize> {
|
||||||
let dst =
|
let dst =
|
||||||
GenericArray::from(*STR_HASH_TO_GROUP).concat(get_context_string::<G>(mode).unwrap());
|
GenericArray::from(*STR_HASH_TO_GROUP).concat(get_context_string::<G>(mode).unwrap());
|
||||||
let point = G::hash_to_curve::<H>(input, &dst).unwrap();
|
let point = G::hash_to_curve::<H, _>(input, dst).unwrap();
|
||||||
|
|
||||||
let context = [
|
let context = [
|
||||||
STR_CONTEXT,
|
STR_CONTEXT,
|
||||||
@@ -870,7 +871,7 @@ mod tests {
|
|||||||
.concat();
|
.concat();
|
||||||
let dst =
|
let dst =
|
||||||
GenericArray::from(*STR_HASH_TO_SCALAR).concat(get_context_string::<G>(mode).unwrap());
|
GenericArray::from(*STR_HASH_TO_SCALAR).concat(get_context_string::<G>(mode).unwrap());
|
||||||
let m = <G as Group>::hash_to_scalar::<H>(&context, &dst).unwrap();
|
let m = <G as Group>::hash_to_scalar::<H, _>(&context, dst).unwrap();
|
||||||
|
|
||||||
let res = point * &<G as Group>::scalar_invert(&(key + &m));
|
let res = point * &<G as Group>::scalar_invert(&(key + &m));
|
||||||
|
|
||||||
@@ -931,7 +932,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let wrong_pk = {
|
let wrong_pk = {
|
||||||
// Choose a group element that is unlikely to be the right public key
|
// Choose a group element that is unlikely to be the right public key
|
||||||
G::hash_to_curve::<H>(b"msg", b"dst").unwrap()
|
G::hash_to_curve::<H, _>(b"msg", (*b"dst").into()).unwrap()
|
||||||
};
|
};
|
||||||
let client_finalize_result = client_blind_result.state.finalize(
|
let client_finalize_result = client_blind_result.state.finalize(
|
||||||
server_result.message,
|
server_result.message,
|
||||||
@@ -1000,7 +1001,7 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let wrong_pk = {
|
let wrong_pk = {
|
||||||
// Choose a group element that is unlikely to be the right public key
|
// Choose a group element that is unlikely to be the right public key
|
||||||
G::hash_to_curve::<H>(b"msg", b"dst").unwrap()
|
G::hash_to_curve::<H, _>(b"msg", (*b"dst").into()).unwrap()
|
||||||
};
|
};
|
||||||
let client_finalize_result = VerifiableClient::batch_finalize(
|
let client_finalize_result = VerifiableClient::batch_finalize(
|
||||||
&client_states,
|
&client_states,
|
||||||
@@ -1032,7 +1033,7 @@ mod tests {
|
|||||||
|
|
||||||
let dst = GenericArray::from(*STR_HASH_TO_GROUP)
|
let dst = GenericArray::from(*STR_HASH_TO_GROUP)
|
||||||
.concat(get_context_string::<G>(Mode::Base).unwrap());
|
.concat(get_context_string::<G>(Mode::Base).unwrap());
|
||||||
let point = G::hash_to_curve::<H>(&input, &dst).unwrap();
|
let point = G::hash_to_curve::<H, _>(&input, dst).unwrap();
|
||||||
let res2 = finalize_after_unblind::<G, H, _>(
|
let res2 = finalize_after_unblind::<G, H, _>(
|
||||||
Some((input.as_slice(), point)).into_iter(),
|
Some((input.as_slice(), point)).into_iter(),
|
||||||
info,
|
info,
|
||||||
|
|||||||
Reference in New Issue
Block a user