Update to draft 19 (#101)

This commit is contained in:
daxpedda
2023-02-08 00:18:04 -08:00
committed by GitHub
parent 40d81294db
commit 5badeff8d2
15 changed files with 1022 additions and 984 deletions
+1 -1
View File
@@ -43,7 +43,7 @@ jobs:
- --features serde - --features serde
toolchain: toolchain:
- stable - stable
- 1.60.0 - 1.61.0
name: test name: test
steps: steps:
- name: Checkout sources - name: Checkout sources
+6 -3
View File
@@ -8,7 +8,7 @@ license = "MIT"
name = "voprf" name = "voprf"
readme = "README.md" readme = "README.md"
repository = "https://github.com/novifinancial/voprf/" repository = "https://github.com/novifinancial/voprf/"
rust-version = "1.60" rust-version = "1.61"
version = "0.5.0-pre.2" version = "0.5.0-pre.2"
[features] [features]
@@ -28,7 +28,7 @@ curve25519-dalek = { version = "=4.0.0-rc.1", default-features = false, features
derive-where = { version = "1", features = ["zeroize-on-drop"] } derive-where = { version = "1", features = ["zeroize-on-drop"] }
digest = "0.10" digest = "0.10"
displaydoc = { version = "0.2", default-features = false } displaydoc = { version = "0.2", default-features = false }
elliptic-curve = { version = "0.12", features = [ elliptic-curve = { version = "=0.13.0-pre.5", features = [
"hash2curve", "hash2curve",
"sec1", "sec1",
"voprf", "voprf",
@@ -45,7 +45,7 @@ zeroize = { version = "1.5", default-features = false }
[dev-dependencies] [dev-dependencies]
generic-array = { version = "0.14", features = ["more_lengths"] } generic-array = { version = "0.14", features = ["more_lengths"] }
hex = "0.4" hex = "0.4"
p256 = { version = "0.12", default-features = false, features = [ p256 = { version = "=0.13.0-pre", default-features = false, features = [
"hash2curve", "hash2curve",
"voprf", "voprf",
] } ] }
@@ -59,3 +59,6 @@ sha2 = "0.10"
all-features = true all-features = true
rustdoc-args = ["--cfg", "docsrs"] rustdoc-args = ["--cfg", "docsrs"]
targets = [] targets = []
[patch.crates-io]
p256 = { git = "https://github.com/RustCrypto/elliptic-curves", rev = "136fed7944d53c0508b1a93cd97bdab46891bcf7" }
+1 -1
View File
@@ -21,7 +21,7 @@ voprf = "0.5.0-pre.2"
### Minimum Supported Rust Version ### Minimum Supported Rust Version
Rust **1.60** or higher. Rust **1.61** or higher.
Contributors Contributors
------------ ------------
+5 -5
View File
@@ -8,7 +8,7 @@
//! Defines the CipherSuite trait to specify the underlying primitives for VOPRF //! Defines the CipherSuite trait to specify the underlying primitives for VOPRF
use digest::core_api::BlockSizeUser; use digest::core_api::BlockSizeUser;
use digest::{Digest, OutputSizeUser}; use digest::{FixedOutput, HashMarker, OutputSizeUser};
use elliptic_curve::VoprfParameters; use elliptic_curve::VoprfParameters;
use generic_array::typenum::{IsLess, IsLessOrEqual, U256}; use generic_array::typenum::{IsLess, IsLessOrEqual, U256};
@@ -22,7 +22,7 @@ where
{ {
/// The ciphersuite identifier as dictated by /// The ciphersuite identifier as dictated by
/// <https://datatracker.ietf.org/doc/draft-irtf-cfrg-voprf/> /// <https://datatracker.ietf.org/doc/draft-irtf-cfrg-voprf/>
const ID: u16; const ID: &'static str;
/// A finite cyclic group along with a point representation that allows some /// A finite cyclic group along with a point representation that allows some
/// customization on how to hash an input to a curve point. See [`Group`]. /// customization on how to hash an input to a curve point. See [`Group`].
@@ -30,17 +30,17 @@ where
/// The main hash function to use (for HKDF computations and hashing /// The main hash function to use (for HKDF computations and hashing
/// transcripts). /// transcripts).
type Hash: BlockSizeUser + Digest; type Hash: BlockSizeUser + Default + FixedOutput + HashMarker;
} }
impl<T: VoprfParameters> CipherSuite for T impl<T: VoprfParameters> CipherSuite for T
where where
T: Group, T: Group,
T::Hash: BlockSizeUser + Digest, T::Hash: BlockSizeUser + Default + FixedOutput + HashMarker,
<T::Hash as OutputSizeUser>::OutputSize: <T::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<T::Hash as BlockSizeUser>::BlockSize>, IsLess<U256> + IsLessOrEqual<<T::Hash as BlockSizeUser>::BlockSize>,
{ {
const ID: u16 = T::ID; const ID: &'static str = T::ID;
type Group = T; type Group = T;
+72 -24
View File
@@ -8,12 +8,13 @@
//! Common functionality between multiple OPRF modes. //! Common functionality between multiple OPRF modes.
use core::convert::TryFrom; use core::convert::TryFrom;
use core::ops::Add;
use derive_where::derive_where; use derive_where::derive_where;
use digest::core_api::BlockSizeUser; use digest::core_api::BlockSizeUser;
use digest::{Digest, Output, OutputSizeUser}; use digest::{Digest, Output, OutputSizeUser};
use generic_array::sequence::Concat; use generic_array::sequence::Concat;
use generic_array::typenum::{IsLess, IsLessOrEqual, Unsigned, U11, U2, U256}; use generic_array::typenum::{IsLess, IsLessOrEqual, Unsigned, U2, U256, U9};
use generic_array::{ArrayLength, GenericArray}; use generic_array::{ArrayLength, GenericArray};
use rand_core::{CryptoRng, RngCore}; use rand_core::{CryptoRng, RngCore};
use subtle::ConstantTimeEq; use subtle::ConstantTimeEq;
@@ -33,7 +34,7 @@ pub(crate) const STR_DERIVE_KEYPAIR: [u8; 13] = *b"DeriveKeyPair";
pub(crate) const STR_COMPOSITE: [u8; 9] = *b"Composite"; pub(crate) const STR_COMPOSITE: [u8; 9] = *b"Composite";
pub(crate) const STR_CHALLENGE: [u8; 9] = *b"Challenge"; pub(crate) const STR_CHALLENGE: [u8; 9] = *b"Challenge";
pub(crate) const STR_INFO: [u8; 4] = *b"Info"; pub(crate) const STR_INFO: [u8; 4] = *b"Info";
pub(crate) const STR_VOPRF: [u8; 8] = *b"VOPRF10-"; pub(crate) const STR_OPRF: [u8; 7] = *b"OPRFV1-";
pub(crate) const STR_HASH_TO_SCALAR: [u8; 13] = *b"HashToScalar-"; pub(crate) const STR_HASH_TO_SCALAR: [u8; 13] = *b"HashToScalar-";
pub(crate) const STR_HASH_TO_GROUP: [u8; 12] = *b"HashToGroup-"; pub(crate) const STR_HASH_TO_GROUP: [u8; 12] = *b"HashToGroup-";
@@ -194,9 +195,9 @@ where
&STR_CHALLENGE, &STR_CHALLENGE,
]; ];
let dst = GenericArray::from(STR_HASH_TO_SCALAR).concat(create_context_string::<CS>(mode)); let dst = Dst::new::<CS, _, _>(STR_HASH_TO_SCALAR, mode);
// This can't fail, the size of the `input` is known. // This can't fail, the size of the `input` is known.
let c_scalar = CS::Group::hash_to_scalar::<CS::Hash>(&h2_input, &dst).unwrap(); let c_scalar = CS::Group::hash_to_scalar::<CS::Hash>(&h2_input, &dst.as_dst()).unwrap();
let s_scalar = r - &(c_scalar * &k); let s_scalar = r - &(c_scalar * &k);
Ok(Proof { c_scalar, s_scalar }) Ok(Proof { c_scalar, s_scalar })
@@ -254,9 +255,9 @@ where
&STR_CHALLENGE, &STR_CHALLENGE,
]; ];
let dst = GenericArray::from(STR_HASH_TO_SCALAR).concat(create_context_string::<CS>(mode)); let dst = Dst::new::<CS, _, _>(STR_HASH_TO_SCALAR, mode);
// This can't fail, the size of the `input` is known. // This can't fail, the size of the `input` is known.
let c = CS::Group::hash_to_scalar::<CS::Hash>(&h2_input, &dst).unwrap(); let c = CS::Group::hash_to_scalar::<CS::Hash>(&h2_input, &dst.as_dst()).unwrap();
match c.ct_eq(&proof.c_scalar).into() { match c.ct_eq(&proof.c_scalar).into() {
true => Ok(()), true => Ok(()),
@@ -296,7 +297,7 @@ where
let len = u16::try_from(c_slice.len()).map_err(|_| Error::Batch)?; let len = u16::try_from(c_slice.len()).map_err(|_| Error::Batch)?;
// seedDST = "Seed-" || contextString // seedDST = "Seed-" || contextString
let seed_dst = GenericArray::from(STR_SEED).concat(create_context_string::<CS>(mode)); let seed_dst = Dst::new::<CS, _, _>(STR_SEED, mode);
// h1Input = I2OSP(len(Bm), 2) || Bm || // h1Input = I2OSP(len(Bm), 2) || Bm ||
// I2OSP(len(seedDST), 2) || seedDST // I2OSP(len(seedDST), 2) || seedDST
@@ -304,8 +305,8 @@ where
let seed = CS::Hash::new() let seed = CS::Hash::new()
.chain_update(elem_len) .chain_update(elem_len)
.chain_update(CS::Group::serialize_elem(b)) .chain_update(CS::Group::serialize_elem(b))
.chain_update(i2osp_2_array(&seed_dst)) .chain_update(seed_dst.i2osp_2())
.chain_update(seed_dst) .chain_update_multi(&seed_dst.as_dst())
.finalize(); .finalize();
let seed_len = i2osp_2_array(&seed); let seed_len = i2osp_2_array(&seed);
@@ -332,9 +333,9 @@ where
&STR_COMPOSITE, &STR_COMPOSITE,
]; ];
let dst = GenericArray::from(STR_HASH_TO_SCALAR).concat(create_context_string::<CS>(mode)); let dst = Dst::new::<CS, _, _>(STR_HASH_TO_SCALAR, mode);
// This can't fail, the size of the `input` is known. // This can't fail, the size of the `input` is known.
let di = CS::Group::hash_to_scalar::<CS::Hash>(&h2_input, &dst).unwrap(); let di = CS::Group::hash_to_scalar::<CS::Hash>(&h2_input, &dst.as_dst()).unwrap();
m = c * &di + &m; m = c * &di + &m;
z = match k_option { z = match k_option {
Some(_) => z, Some(_) => z,
@@ -365,8 +366,7 @@ where
<CS::Hash as OutputSizeUser>::OutputSize: <CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>, IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{ {
let context_string = create_context_string::<CS>(mode); let dst = Dst::new::<CS, _, _>(STR_DERIVE_KEYPAIR, mode);
let dst = GenericArray::from(STR_DERIVE_KEYPAIR).concat(context_string);
let info_len = i2osp_2(info.len()).map_err(|_| Error::DeriveKeyPair)?; let info_len = i2osp_2(info.len()).map_err(|_| Error::DeriveKeyPair)?;
@@ -376,7 +376,7 @@ where
// || contextString) // || contextString)
let sk_s = CS::Group::hash_to_scalar::<CS::Hash>( let sk_s = CS::Group::hash_to_scalar::<CS::Hash>(
&[seed, &info_len, info, &counter.to_be_bytes()], &[seed, &info_len, info, &counter.to_be_bytes()],
&dst, &dst.as_dst(),
) )
.map_err(|_| Error::DeriveKeyPair)?; .map_err(|_| Error::DeriveKeyPair)?;
@@ -455,8 +455,8 @@ where
<CS::Hash as OutputSizeUser>::OutputSize: <CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>, IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{ {
let dst = GenericArray::from(STR_HASH_TO_GROUP).concat(create_context_string::<CS>(mode)); let dst = Dst::new::<CS, _, _>(STR_HASH_TO_GROUP, mode);
CS::Group::hash_to_curve::<CS::Hash>(&[input], &dst).map_err(|_| Error::Input) CS::Group::hash_to_curve::<CS::Hash>(&[input], &dst.as_dst()).map_err(|_| Error::Input)
} }
/// Internal function that finalizes the hash input for OPRF, VOPRF & POPRF. /// Internal function that finalizes the hash input for OPRF, VOPRF & POPRF.
@@ -497,16 +497,64 @@ where
.finalize()) .finalize())
} }
/// Generates the contextString parameter as defined in pub(crate) struct Dst<L: ArrayLength<u8>> {
/// <https://datatracker.ietf.org/doc/draft-irtf-cfrg-voprf/> dst_1: GenericArray<u8, L>,
pub(crate) fn create_context_string<CS: CipherSuite>(mode: Mode) -> GenericArray<u8, U11> dst_2: &'static str,
}
impl<L: ArrayLength<u8>> Dst<L> {
pub(crate) fn new<CS: CipherSuite, T, TL: ArrayLength<u8>>(par_1: T, mode: Mode) -> Self
where
T: Into<GenericArray<u8, TL>>,
TL: Add<U9, Output = L>,
<CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{
let par_1 = par_1.into();
// Generates the contextString parameter as defined in
// <https://datatracker.ietf.org/doc/draft-irtf-cfrg-voprf/>
let par_2 = GenericArray::from(STR_OPRF)
.concat([mode.to_u8()].into())
.concat([b'-'].into());
let dst_1 = par_1.concat(par_2);
let dst_2 = CS::ID;
assert!(
L::USIZE + dst_2.len() <= u16::MAX.into(),
"constructed DST longer then {}",
u16::MAX
);
Self { dst_1, dst_2 }
}
pub(crate) fn as_dst(&self) -> [&[u8]; 2] {
[&self.dst_1, self.dst_2.as_bytes()]
}
pub(crate) fn i2osp_2(&self) -> [u8; 2] {
u16::try_from(L::USIZE + self.dst_2.len())
.unwrap()
.to_be_bytes()
}
}
trait DigestExt {
fn chain_update_multi(self, data: &[&[u8]]) -> Self;
}
impl<T> DigestExt for T
where where
<CS::Hash as OutputSizeUser>::OutputSize: T: Digest,
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{ {
GenericArray::from(STR_VOPRF) fn chain_update_multi(mut self, datas: &[&[u8]]) -> Self {
.concat([mode.to_u8()].into()) for data in datas {
.concat(CS::ID.to_be_bytes().into()) self.update(data)
}
self
}
} }
/////////////////////// ///////////////////////
+11 -11
View File
@@ -6,12 +6,12 @@
// of this source tree. // of this source tree.
use digest::core_api::BlockSizeUser; use digest::core_api::BlockSizeUser;
use digest::Digest; use digest::{FixedOutput, HashMarker};
use elliptic_curve::group::cofactor::CofactorGroup; use elliptic_curve::group::cofactor::CofactorGroup;
use elliptic_curve::hash2curve::{ExpandMsgXmd, FromOkm, GroupDigest}; use elliptic_curve::hash2curve::{ExpandMsgXmd, FromOkm, GroupDigest};
use elliptic_curve::sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint}; use elliptic_curve::sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint};
use elliptic_curve::{ use elliptic_curve::{
AffinePoint, Field, FieldSize, Group as _, ProjectivePoint, PublicKey, Scalar, SecretKey, AffinePoint, Field, FieldBytesSize, Group as _, ProjectivePoint, PublicKey, Scalar, SecretKey,
}; };
use generic_array::typenum::{IsLess, IsLessOrEqual, U256}; use generic_array::typenum::{IsLess, IsLessOrEqual, U256};
use generic_array::GenericArray; use generic_array::GenericArray;
@@ -24,32 +24,32 @@ impl<C> Group for C
where where
C: GroupDigest, C: GroupDigest,
ProjectivePoint<Self>: CofactorGroup + ToEncodedPoint<Self>, ProjectivePoint<Self>: CofactorGroup + ToEncodedPoint<Self>,
FieldSize<Self>: ModulusSize, FieldBytesSize<Self>: ModulusSize,
AffinePoint<Self>: FromEncodedPoint<Self> + ToEncodedPoint<Self>, AffinePoint<Self>: FromEncodedPoint<Self> + ToEncodedPoint<Self>,
Scalar<Self>: FromOkm, Scalar<Self>: FromOkm,
{ {
type Elem = ProjectivePoint<Self>; type Elem = ProjectivePoint<Self>;
type ElemLen = <FieldSize<Self> as ModulusSize>::CompressedPointSize; type ElemLen = <FieldBytesSize<Self> as ModulusSize>::CompressedPointSize;
type Scalar = Scalar<Self>; type Scalar = Scalar<Self>;
type ScalarLen = FieldSize<Self>; type ScalarLen = FieldBytesSize<Self>;
// 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>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Elem, InternalError> fn hash_to_curve<H>(input: &[&[u8]], dst: &[&[u8]]) -> Result<Self::Elem, InternalError>
where where
H: Digest + BlockSizeUser, H: BlockSizeUser + Default + FixedOutput + HashMarker,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>, H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>,
{ {
Self::hash_from_bytes::<ExpandMsgXmd<H>>(input, dst).map_err(|_| InternalError::Input) Self::hash_from_bytes::<ExpandMsgXmd<H>>(input, dst).map_err(|_| InternalError::Input)
} }
// Implements the `HashToScalar()` function // Implements the `HashToScalar()` function
fn hash_to_scalar<H>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Scalar, InternalError> fn hash_to_scalar<H>(input: &[&[u8]], dst: &[&[u8]]) -> Result<Self::Scalar, InternalError>
where where
H: Digest + BlockSizeUser, H: BlockSizeUser + Default + FixedOutput + HashMarker,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>, H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>,
{ {
<Self as GroupDigest>::hash_to_scalar::<ExpandMsgXmd<H>>(input, dst) <Self as GroupDigest>::hash_to_scalar::<ExpandMsgXmd<H>>(input, dst)
@@ -92,7 +92,7 @@ where
#[cfg(test)] #[cfg(test)]
fn zero_scalar() -> Self::Scalar { fn zero_scalar() -> Self::Scalar {
Scalar::<Self>::zero() Scalar::<Self>::ZERO
} }
fn serialize_scalar(scalar: Self::Scalar) -> GenericArray<u8, Self::ScalarLen> { fn serialize_scalar(scalar: Self::Scalar) -> GenericArray<u8, Self::ScalarLen> {
@@ -100,7 +100,7 @@ where
} }
fn deserialize_scalar(scalar_bits: &[u8]) -> Result<Self::Scalar> { fn deserialize_scalar(scalar_bits: &[u8]) -> Result<Self::Scalar> {
SecretKey::<Self>::from_be_bytes(scalar_bits) SecretKey::<Self>::from_slice(scalar_bits)
.map(|secret_key| *secret_key.to_nonzero_scalar()) .map(|secret_key| *secret_key.to_nonzero_scalar())
.map_err(|_| Error::Deserialization) .map_err(|_| Error::Deserialization)
} }
+5 -5
View File
@@ -14,7 +14,7 @@ mod ristretto;
use core::ops::{Add, Mul, Sub}; use core::ops::{Add, Mul, Sub};
use digest::core_api::BlockSizeUser; use digest::core_api::BlockSizeUser;
use digest::Digest; use digest::{FixedOutput, HashMarker};
use generic_array::typenum::{IsLess, IsLessOrEqual, U256}; use generic_array::typenum::{IsLess, IsLessOrEqual, U256};
use generic_array::{ArrayLength, GenericArray}; use generic_array::{ArrayLength, GenericArray};
use rand_core::{CryptoRng, RngCore}; use rand_core::{CryptoRng, RngCore};
@@ -54,9 +54,9 @@ pub trait Group {
/// # Errors /// # Errors
/// [`Error::Input`](crate::Error::Input) if the `input` is empty or longer /// [`Error::Input`](crate::Error::Input) if the `input` is empty or longer
/// then [`u16::MAX`]. /// then [`u16::MAX`].
fn hash_to_curve<H>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Elem, InternalError> fn hash_to_curve<H>(input: &[&[u8]], dst: &[&[u8]]) -> Result<Self::Elem, InternalError>
where where
H: Digest + BlockSizeUser, H: BlockSizeUser + Default + FixedOutput + HashMarker,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>; H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>;
/// Hashes a slice of pseudo-random bytes to a scalar /// Hashes a slice of pseudo-random bytes to a scalar
@@ -64,9 +64,9 @@ pub trait Group {
/// # Errors /// # Errors
/// [`Error::Input`](crate::Error::Input) if the `input` is empty or longer /// [`Error::Input`](crate::Error::Input) if the `input` is empty or longer
/// then [`u16::MAX`]. /// then [`u16::MAX`].
fn hash_to_scalar<H>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Scalar, InternalError> fn hash_to_scalar<H>(input: &[&[u8]], dst: &[&[u8]]) -> Result<Self::Scalar, InternalError>
where where
H: Digest + BlockSizeUser, H: BlockSizeUser + Default + FixedOutput + HashMarker,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>; H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>;
/// Get the base point for the group /// Get the base point for the group
+6 -6
View File
@@ -10,7 +10,7 @@ use curve25519_dalek::ristretto::{CompressedRistretto, RistrettoPoint};
use curve25519_dalek::scalar::Scalar; use curve25519_dalek::scalar::Scalar;
use curve25519_dalek::traits::Identity; use curve25519_dalek::traits::Identity;
use digest::core_api::BlockSizeUser; use digest::core_api::BlockSizeUser;
use digest::Digest; use digest::{FixedOutput, HashMarker};
use elliptic_curve::hash2curve::{ExpandMsg, ExpandMsgXmd, Expander}; use elliptic_curve::hash2curve::{ExpandMsg, ExpandMsgXmd, Expander};
use generic_array::typenum::{IsLess, IsLessOrEqual, U256, U32, U64}; use generic_array::typenum::{IsLess, IsLessOrEqual, U256, U32, U64};
use generic_array::GenericArray; use generic_array::GenericArray;
@@ -26,7 +26,7 @@ pub struct Ristretto255;
#[cfg(feature = "ristretto255-ciphersuite")] #[cfg(feature = "ristretto255-ciphersuite")]
impl crate::CipherSuite for Ristretto255 { impl crate::CipherSuite for Ristretto255 {
const ID: u16 = 0x0001; const ID: &'static str = "ristretto255-SHA512";
type Group = Ristretto255; type Group = Ristretto255;
@@ -44,9 +44,9 @@ impl Group for Ristretto255 {
// 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>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Elem, InternalError> fn hash_to_curve<H>(input: &[&[u8]], dst: &[&[u8]]) -> Result<Self::Elem, InternalError>
where where
H: Digest + BlockSizeUser, H: BlockSizeUser + Default + FixedOutput + HashMarker,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>, H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>,
{ {
let mut uniform_bytes = GenericArray::<_, U64>::default(); let mut uniform_bytes = GenericArray::<_, U64>::default();
@@ -59,9 +59,9 @@ impl Group for Ristretto255 {
// 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>(input: &[&[u8]], dst: &[u8]) -> Result<Self::Scalar, InternalError> fn hash_to_scalar<H>(input: &[&[u8]], dst: &[&[u8]]) -> Result<Self::Scalar, InternalError>
where where
H: Digest + BlockSizeUser, H: BlockSizeUser + Default + FixedOutput + HashMarker,
H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>, H::OutputSize: IsLess<U256> + IsLessOrEqual<H::BlockSize>,
{ {
let mut uniform_bytes = GenericArray::<_, U64>::default(); let mut uniform_bytes = GenericArray::<_, U64>::default();
+1 -1
View File
@@ -8,7 +8,7 @@
//! An implementation of a verifiable oblivious pseudorandom function (VOPRF) //! An implementation of a verifiable oblivious pseudorandom function (VOPRF)
//! //!
//! Note: This implementation is in sync with //! Note: This implementation is in sync with
//! [draft-irtf-cfrg-voprf-11](https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-11.html), //! [draft-irtf-cfrg-voprf-19](https://www.ietf.org/archive/id/draft-irtf-cfrg-voprf-19.html),
//! but this specification is subject to change, until the final version //! but this specification is subject to change, until the final version
//! published by the IETF. //! published by the IETF.
//! //!
+5 -7
View File
@@ -291,11 +291,10 @@ where
mod tests { mod tests {
use core::ptr; use core::ptr;
use generic_array::sequence::Concat;
use rand::rngs::OsRng; use rand::rngs::OsRng;
use super::*; use super::*;
use crate::common::{create_context_string, STR_HASH_TO_GROUP}; use crate::common::{Dst, STR_HASH_TO_GROUP};
use crate::Group; use crate::Group;
fn prf<CS: CipherSuite>( fn prf<CS: CipherSuite>(
@@ -308,8 +307,8 @@ mod tests {
<CS::Hash as OutputSizeUser>::OutputSize: <CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>, IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{ {
let dst = GenericArray::from(STR_HASH_TO_GROUP).concat(create_context_string::<CS>(mode)); let dst = Dst::new::<CS, _, _>(STR_HASH_TO_GROUP, mode);
let point = CS::Group::hash_to_curve::<CS::Hash>(&[input], &dst).unwrap(); let point = CS::Group::hash_to_curve::<CS::Hash>(&[input], &dst.as_dst()).unwrap();
let res = point * &key; let res = point * &key;
@@ -348,9 +347,8 @@ mod tests {
.finalize(&input, &EvaluationElement(client_blind_result.message.0)) .finalize(&input, &EvaluationElement(client_blind_result.message.0))
.unwrap(); .unwrap();
let dst = let dst = Dst::new::<CS, _, _>(STR_HASH_TO_GROUP, Mode::Oprf);
GenericArray::from(STR_HASH_TO_GROUP).concat(create_context_string::<CS>(Mode::Oprf)); let point = CS::Group::hash_to_curve::<CS::Hash>(&[&input], &dst.as_dst()).unwrap();
let point = CS::Group::hash_to_curve::<CS::Hash>(&[&input], &dst).unwrap();
let res2 = finalize_after_unblind::<CS, _, _>(iter::once((input.as_ref(), point)), &[]) let res2 = finalize_after_unblind::<CS, _, _>(iter::once((input.as_ref(), point)), &[])
.next() .next()
.unwrap() .unwrap()
+11 -16
View File
@@ -14,16 +14,14 @@ use core::iter::{self, Map, Repeat, Zip};
use derive_where::derive_where; use derive_where::derive_where;
use digest::core_api::BlockSizeUser; use digest::core_api::BlockSizeUser;
use digest::{Digest, Output, OutputSizeUser}; use digest::{Digest, Output, OutputSizeUser};
use generic_array::sequence::Concat;
use generic_array::typenum::{IsLess, IsLessOrEqual, Unsigned, U256}; use generic_array::typenum::{IsLess, IsLessOrEqual, Unsigned, U256};
use generic_array::GenericArray; use generic_array::GenericArray;
use rand_core::{CryptoRng, RngCore}; use rand_core::{CryptoRng, RngCore};
use crate::common::{ use crate::common::{
create_context_string, derive_keypair, deterministic_blind_unchecked, generate_proof, derive_keypair, deterministic_blind_unchecked, generate_proof, hash_to_group, i2osp_2,
hash_to_group, i2osp_2, server_evaluate_hash_input, verify_proof, BlindedElement, server_evaluate_hash_input, verify_proof, BlindedElement, Dst, EvaluationElement, Mode,
EvaluationElement, Mode, PreparedEvaluationElement, Proof, STR_FINALIZE, STR_HASH_TO_SCALAR, PreparedEvaluationElement, Proof, STR_FINALIZE, STR_HASH_TO_SCALAR, STR_INFO,
STR_INFO,
}; };
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use crate::serialization::serde::{Element, Scalar}; use crate::serialization::serde::{Element, Scalar};
@@ -616,10 +614,9 @@ where
let info_len = i2osp_2(info.len()).map_err(|_| Error::Info)?; let info_len = i2osp_2(info.len()).map_err(|_| Error::Info)?;
let framed_info = [STR_INFO.as_slice(), &info_len, info]; let framed_info = [STR_INFO.as_slice(), &info_len, info];
let dst = let dst = Dst::new::<CS, _, _>(STR_HASH_TO_SCALAR, Mode::Poprf);
GenericArray::from(STR_HASH_TO_SCALAR).concat(create_context_string::<CS>(Mode::Poprf));
// This can't fail, the size of the `input` is known. // This can't fail, the size of the `input` is known.
let m = CS::Group::hash_to_scalar::<CS::Hash>(&framed_info, &dst).unwrap(); let m = CS::Group::hash_to_scalar::<CS::Hash>(&framed_info, &dst.as_dst()).unwrap();
let t = CS::Group::base_elem() * &m; let t = CS::Group::base_elem() * &m;
let tweaked_key = t + &pk; let tweaked_key = t + &pk;
@@ -654,10 +651,9 @@ where
let info_len = i2osp_2(info.len()).map_err(|_| Error::Info)?; let info_len = i2osp_2(info.len()).map_err(|_| Error::Info)?;
let framed_info = [STR_INFO.as_slice(), &info_len, info]; let framed_info = [STR_INFO.as_slice(), &info_len, info];
let dst = let dst = Dst::new::<CS, _, _>(STR_HASH_TO_SCALAR, Mode::Poprf);
GenericArray::from(STR_HASH_TO_SCALAR).concat(create_context_string::<CS>(Mode::Poprf));
// This can't fail, the size of the `input` is known. // This can't fail, the size of the `input` is known.
let m = CS::Group::hash_to_scalar::<CS::Hash>(&framed_info, &dst).unwrap(); let m = CS::Group::hash_to_scalar::<CS::Hash>(&framed_info, &dst.as_dst()).unwrap();
let t = sk + &m; let t = sk + &m;
@@ -810,8 +806,8 @@ mod tests {
{ {
let t = compute_tweak::<CS>(key, Some(info)).unwrap(); let t = compute_tweak::<CS>(key, Some(info)).unwrap();
let dst = GenericArray::from(STR_HASH_TO_GROUP).concat(create_context_string::<CS>(mode)); let dst = Dst::new::<CS, _, _>(STR_HASH_TO_GROUP, mode);
let point = CS::Group::hash_to_curve::<CS::Hash>(&[input], &dst).unwrap(); let point = CS::Group::hash_to_curve::<CS::Hash>(&[input], &dst.as_dst()).unwrap();
// evaluatedElement = G.ScalarInverse(t) * blindedElement // evaluatedElement = G.ScalarInverse(t) * blindedElement
let res = point * &CS::Group::invert_scalar(t); let res = point * &CS::Group::invert_scalar(t);
@@ -864,10 +860,9 @@ mod tests {
.blind_evaluate(&mut rng, &client_blind_result.message, Some(info)) .blind_evaluate(&mut rng, &client_blind_result.message, Some(info))
.unwrap(); .unwrap();
let wrong_pk = { let wrong_pk = {
let dst = GenericArray::from(STR_HASH_TO_GROUP) let dst = Dst::new::<CS, _, _>(STR_HASH_TO_GROUP, Mode::Oprf);
.concat(create_context_string::<CS>(Mode::Oprf));
// 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
CS::Group::hash_to_curve::<CS::Hash>(&[b"msg"], &dst).unwrap() CS::Group::hash_to_curve::<CS::Hash>(&[b"msg"], &dst.as_dst()).unwrap()
}; };
let client_finalize_result = client_blind_result.state.finalize( let client_finalize_result = client_blind_result.state.finalize(
input, input,
+884 -887
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -14,7 +14,7 @@ pub(crate) fn rfc_to_json(input: &str) -> String {
} }
fn parse_ciphersuites(input: &str) -> String { fn parse_ciphersuites(input: &str) -> String {
let re = regex::Regex::new(r"## OPRF\((?P<ciphersuite>.+?)\)").unwrap(); let re = regex::Regex::new(r"\n## (?P<ciphersuite>.+?)\n").unwrap();
let mut ciphersuites = vec![]; let mut ciphersuites = vec![];
let chunks: Vec<&str> = re.split(input).collect(); let chunks: Vec<&str> = re.split(input).collect();
+6 -6
View File
@@ -97,7 +97,7 @@ fn test_vectors() -> Result<()> {
let ristretto_oprf_tvs = json_to_test_vectors!( let ristretto_oprf_tvs = json_to_test_vectors!(
rfc, rfc,
String::from("ristretto255, SHA-512"), String::from("ristretto255-SHA512"),
String::from("OPRF") String::from("OPRF")
); );
assert_ne!(ristretto_oprf_tvs.len(), 0); assert_ne!(ristretto_oprf_tvs.len(), 0);
@@ -109,7 +109,7 @@ fn test_vectors() -> Result<()> {
let ristretto_voprf_tvs = json_to_test_vectors!( let ristretto_voprf_tvs = json_to_test_vectors!(
rfc, rfc,
String::from("ristretto255, SHA-512"), String::from("ristretto255-SHA512"),
String::from("VOPRF") String::from("VOPRF")
); );
assert_ne!(ristretto_voprf_tvs.len(), 0); assert_ne!(ristretto_voprf_tvs.len(), 0);
@@ -121,7 +121,7 @@ fn test_vectors() -> Result<()> {
let ristretto_poprf_tvs = json_to_test_vectors!( let ristretto_poprf_tvs = json_to_test_vectors!(
rfc, rfc,
String::from("ristretto255, SHA-512"), String::from("ristretto255-SHA512"),
String::from("POPRF") String::from("POPRF")
); );
assert_ne!(ristretto_poprf_tvs.len(), 0); assert_ne!(ristretto_poprf_tvs.len(), 0);
@@ -133,7 +133,7 @@ fn test_vectors() -> Result<()> {
} }
let p256_oprf_tvs = let p256_oprf_tvs =
json_to_test_vectors!(rfc, String::from("P-256, SHA-256"), String::from("OPRF")); json_to_test_vectors!(rfc, String::from("P256-SHA256"), String::from("OPRF"));
assert_ne!(p256_oprf_tvs.len(), 0); assert_ne!(p256_oprf_tvs.len(), 0);
test_oprf_seed_to_key::<NistP256>(&p256_oprf_tvs)?; test_oprf_seed_to_key::<NistP256>(&p256_oprf_tvs)?;
test_oprf_blind::<NistP256>(&p256_oprf_tvs)?; test_oprf_blind::<NistP256>(&p256_oprf_tvs)?;
@@ -142,7 +142,7 @@ fn test_vectors() -> Result<()> {
test_oprf_evaluate::<NistP256>(&p256_oprf_tvs)?; test_oprf_evaluate::<NistP256>(&p256_oprf_tvs)?;
let p256_voprf_tvs = let p256_voprf_tvs =
json_to_test_vectors!(rfc, String::from("P-256, SHA-256"), String::from("VOPRF")); json_to_test_vectors!(rfc, String::from("P256-SHA256"), String::from("VOPRF"));
assert_ne!(p256_voprf_tvs.len(), 0); assert_ne!(p256_voprf_tvs.len(), 0);
test_voprf_seed_to_key::<NistP256>(&p256_voprf_tvs)?; test_voprf_seed_to_key::<NistP256>(&p256_voprf_tvs)?;
test_voprf_blind::<NistP256>(&p256_voprf_tvs)?; test_voprf_blind::<NistP256>(&p256_voprf_tvs)?;
@@ -151,7 +151,7 @@ fn test_vectors() -> Result<()> {
test_voprf_evaluate::<NistP256>(&p256_voprf_tvs)?; test_voprf_evaluate::<NistP256>(&p256_voprf_tvs)?;
let p256_poprf_tvs = let p256_poprf_tvs =
json_to_test_vectors!(rfc, String::from("P-256, SHA-256"), String::from("POPRF")); json_to_test_vectors!(rfc, String::from("P256-SHA256"), String::from("POPRF"));
assert_ne!(p256_poprf_tvs.len(), 0); assert_ne!(p256_poprf_tvs.len(), 0);
test_poprf_seed_to_key::<NistP256>(&p256_poprf_tvs)?; test_poprf_seed_to_key::<NistP256>(&p256_poprf_tvs)?;
test_poprf_blind::<NistP256>(&p256_poprf_tvs)?; test_poprf_blind::<NistP256>(&p256_poprf_tvs)?;
+7 -10
View File
@@ -587,13 +587,12 @@ mod tests {
use ::alloc::vec; use ::alloc::vec;
use ::alloc::vec::Vec; use ::alloc::vec::Vec;
use generic_array::sequence::Concat;
use generic_array::typenum::Sum; use generic_array::typenum::Sum;
use generic_array::ArrayLength; use generic_array::ArrayLength;
use rand::rngs::OsRng; use rand::rngs::OsRng;
use super::*; use super::*;
use crate::common::{create_context_string, STR_HASH_TO_GROUP}; use crate::common::{Dst, STR_HASH_TO_GROUP};
use crate::Group; use crate::Group;
fn prf<CS: CipherSuite>( fn prf<CS: CipherSuite>(
@@ -605,8 +604,8 @@ mod tests {
<CS::Hash as OutputSizeUser>::OutputSize: <CS::Hash as OutputSizeUser>::OutputSize:
IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>, IsLess<U256> + IsLessOrEqual<<CS::Hash as BlockSizeUser>::BlockSize>,
{ {
let dst = GenericArray::from(STR_HASH_TO_GROUP).concat(create_context_string::<CS>(mode)); let dst = Dst::new::<CS, _, _>(STR_HASH_TO_GROUP, mode);
let point = CS::Group::hash_to_curve::<CS::Hash>(&[input], &dst).unwrap(); let point = CS::Group::hash_to_curve::<CS::Hash>(&[input], &dst.as_dst()).unwrap();
let res = point * &key; let res = point * &key;
@@ -718,10 +717,9 @@ mod tests {
.unwrap(); .unwrap();
let messages: Vec<_> = messages.collect(); let messages: Vec<_> = messages.collect();
let wrong_pk = { let wrong_pk = {
let dst = GenericArray::from(STR_HASH_TO_GROUP) let dst = Dst::new::<CS, _, _>(STR_HASH_TO_GROUP, Mode::Oprf);
.concat(create_context_string::<CS>(Mode::Oprf));
// 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
CS::Group::hash_to_curve::<CS::Hash>(&[b"msg"], &dst).unwrap() CS::Group::hash_to_curve::<CS::Hash>(&[b"msg"], &dst.as_dst()).unwrap()
}; };
let client_finalize_result = let client_finalize_result =
VoprfClient::batch_finalize(&inputs, &client_states, &messages, &proof, wrong_pk); VoprfClient::batch_finalize(&inputs, &client_states, &messages, &proof, wrong_pk);
@@ -739,10 +737,9 @@ mod tests {
let server = VoprfServer::<CS>::new(&mut rng).unwrap(); let server = VoprfServer::<CS>::new(&mut rng).unwrap();
let server_result = server.blind_evaluate(&mut rng, &client_blind_result.message); let server_result = server.blind_evaluate(&mut rng, &client_blind_result.message);
let wrong_pk = { let wrong_pk = {
let dst = GenericArray::from(STR_HASH_TO_GROUP) let dst = Dst::new::<CS, _, _>(STR_HASH_TO_GROUP, Mode::Oprf);
.concat(create_context_string::<CS>(Mode::Oprf));
// 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
CS::Group::hash_to_curve::<CS::Hash>(&[b"msg"], &dst).unwrap() CS::Group::hash_to_curve::<CS::Hash>(&[b"msg"], &dst.as_dst()).unwrap()
}; };
let client_finalize_result = client_blind_result.state.finalize( let client_finalize_result = client_blind_result.state.finalize(
input, input,