batch_evaluate without alloc (#48)
* `no_alloc` alternative to `VerifiableServer::batch_evaluate()` * Rename `PreparedT` to `PreparedTscalar`
This commit is contained in:
+60
-23
@@ -331,13 +331,10 @@
|
|||||||
//! this case. In the following example, we show how to use the batch API to
|
//! this case. In the following example, we show how to use the batch API to
|
||||||
//! produce a single proof for 10 parallel VOPRF evaluations.
|
//! produce a single proof for 10 parallel VOPRF evaluations.
|
||||||
//!
|
//!
|
||||||
//! This requires the crate feature `alloc`.
|
|
||||||
//!
|
|
||||||
//! First, the client produces 10 blindings, storing their resulting states and
|
//! First, the client produces 10 blindings, storing their resulting states and
|
||||||
//! messages:
|
//! messages:
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! # #[cfg(feature = "alloc")] {
|
|
||||||
//! # #[cfg(feature = "ristretto255")]
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
//! # #[cfg(feature = "ristretto255")]
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
@@ -358,16 +355,14 @@
|
|||||||
//! client_states.push(client_blind_result.state);
|
//! client_states.push(client_blind_result.state);
|
||||||
//! client_messages.push(client_blind_result.message);
|
//! client_messages.push(client_blind_result.message);
|
||||||
//! }
|
//! }
|
||||||
//! # }
|
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! Next, the server calls the [VerifiableServer::batch_evaluate] function on a
|
//! Next, the server calls the [VerifiableServer::batch_evaluate_prepare] and
|
||||||
//! set of client messages, to produce a corresponding set of messages to be
|
//! [VerifiableServer::batch_evaluate_finish] function on a set of client
|
||||||
//! returned to the client (returned in the same order), along with a single
|
//! messages, to produce a corresponding set of messages to be returned to the
|
||||||
//! proof:
|
//! client (returned in the same order), along with a single proof:
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! # #[cfg(feature = "alloc")] {
|
|
||||||
//! # #[cfg(feature = "ristretto255")]
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
//! # #[cfg(feature = "ristretto255")]
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
@@ -376,7 +371,7 @@
|
|||||||
//! # type Group = p256_::ProjectivePoint;
|
//! # type Group = p256_::ProjectivePoint;
|
||||||
//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))]
|
//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))]
|
||||||
//! # type Hash = sha2::Sha256;
|
//! # type Hash = sha2::Sha256;
|
||||||
//! # use voprf::VerifiableClient;
|
//! # use voprf::{VerifiableServerBatchEvaluatePrepareResult, VerifiableServerBatchEvaluateFinishResult, VerifiableClient};
|
||||||
//! # use rand::{rngs::OsRng, RngCore};
|
//! # use rand::{rngs::OsRng, RngCore};
|
||||||
//! #
|
//! #
|
||||||
//! # let mut client_rng = OsRng;
|
//! # let mut client_rng = OsRng;
|
||||||
@@ -394,7 +389,50 @@
|
|||||||
//! let mut server_rng = OsRng;
|
//! let mut server_rng = OsRng;
|
||||||
//! # let server = VerifiableServer::<Group, Hash>::new(&mut server_rng)
|
//! # let server = VerifiableServer::<Group, Hash>::new(&mut server_rng)
|
||||||
//! # .expect("Unable to construct server");
|
//! # .expect("Unable to construct server");
|
||||||
//! let server_batch_evaluate_result = server
|
//! let VerifiableServerBatchEvaluatePrepareResult {
|
||||||
|
//! prepared_evaluation_elements,
|
||||||
|
//! t,
|
||||||
|
//! } = server
|
||||||
|
//! .batch_evaluate_prepare(client_messages.iter(), None)
|
||||||
|
//! .expect("Unable to perform server batch evaluate");
|
||||||
|
//! let prepared_elements: Vec<_> = prepared_evaluation_elements.collect();
|
||||||
|
//! let VerifiableServerBatchEvaluateFinishResult { messages, proof } = VerifiableServer::batch_evaluate_finish(&mut server_rng, client_messages.iter(), &prepared_elements, &t)
|
||||||
|
//! .expect("Unable to perform server batch evaluate");
|
||||||
|
//! let messages: Vec<_> = messages.collect();
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! If [`alloc`] is available, [VerifiableServer::batch_evaluate] can be called
|
||||||
|
//! to avoid having to collect output manually:
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! # #[cfg(feature = "alloc")] {
|
||||||
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
|
//! # type Group = curve25519_dalek::ristretto::RistrettoPoint;
|
||||||
|
//! # #[cfg(feature = "ristretto255")]
|
||||||
|
//! # type Hash = sha2::Sha512;
|
||||||
|
//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))]
|
||||||
|
//! # type Group = p256_::ProjectivePoint;
|
||||||
|
//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))]
|
||||||
|
//! # type Hash = sha2::Sha256;
|
||||||
|
//! # use voprf::{VerifiableServerBatchEvaluateResult, VerifiableClient};
|
||||||
|
//! # use rand::{rngs::OsRng, RngCore};
|
||||||
|
//! #
|
||||||
|
//! # let mut client_rng = OsRng;
|
||||||
|
//! # let mut client_states = vec![];
|
||||||
|
//! # let mut client_messages = vec![];
|
||||||
|
//! # for _ in 0..10 {
|
||||||
|
//! # let client_blind_result = VerifiableClient::<Group, Hash>::blind(
|
||||||
|
//! # b"input",
|
||||||
|
//! # &mut client_rng,
|
||||||
|
//! # ).expect("Unable to construct client");
|
||||||
|
//! # client_states.push(client_blind_result.state);
|
||||||
|
//! # client_messages.push(client_blind_result.message);
|
||||||
|
//! # }
|
||||||
|
//! # use voprf::VerifiableServer;
|
||||||
|
//! let mut server_rng = OsRng;
|
||||||
|
//! # let server = VerifiableServer::<Group, Hash>::new(&mut server_rng)
|
||||||
|
//! # .expect("Unable to construct server");
|
||||||
|
//! let VerifiableServerBatchEvaluateResult { messages, proof } = server
|
||||||
//! .batch_evaluate(&mut server_rng, &client_messages, None)
|
//! .batch_evaluate(&mut server_rng, &client_messages, None)
|
||||||
//! .expect("Unable to perform server batch evaluate");
|
//! .expect("Unable to perform server batch evaluate");
|
||||||
//! # }
|
//! # }
|
||||||
@@ -415,7 +453,7 @@
|
|||||||
//! # type Group = p256_::ProjectivePoint;
|
//! # type Group = p256_::ProjectivePoint;
|
||||||
//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))]
|
//! # #[cfg(all(feature = "p256", not(feature = "ristretto255")))]
|
||||||
//! # type Hash = sha2::Sha256;
|
//! # type Hash = sha2::Sha256;
|
||||||
//! # use voprf::VerifiableClient;
|
//! # use voprf::{VerifiableServerBatchEvaluateResult, VerifiableClient};
|
||||||
//! # use rand::{rngs::OsRng, RngCore};
|
//! # use rand::{rngs::OsRng, RngCore};
|
||||||
//! #
|
//! #
|
||||||
//! # let mut client_rng = OsRng;
|
//! # let mut client_rng = OsRng;
|
||||||
@@ -430,19 +468,17 @@
|
|||||||
//! # client_messages.push(client_blind_result.message);
|
//! # client_messages.push(client_blind_result.message);
|
||||||
//! # }
|
//! # }
|
||||||
//! # use voprf::VerifiableServer;
|
//! # use voprf::VerifiableServer;
|
||||||
//! let mut server_rng = OsRng;
|
//! # let mut server_rng = OsRng;
|
||||||
//! # let server = VerifiableServer::<Group, Hash>::new(&mut server_rng)
|
//! # let server = VerifiableServer::<Group, Hash>::new(&mut server_rng)
|
||||||
//! # .expect("Unable to construct server");
|
//! # .expect("Unable to construct server");
|
||||||
//! # let server_batch_evaluate_result = server.batch_evaluate(
|
//! # let VerifiableServerBatchEvaluateResult { messages, proof } = server
|
||||||
//! # &mut server_rng,
|
//! # .batch_evaluate(&mut server_rng, &client_messages, None)
|
||||||
//! # &client_messages,
|
//! # .expect("Unable to perform server batch evaluate");
|
||||||
//! # None,
|
|
||||||
//! # ).expect("Unable to perform server batch evaluate");
|
|
||||||
//! let client_batch_finalize_result = VerifiableClient::batch_finalize(
|
//! let client_batch_finalize_result = VerifiableClient::batch_finalize(
|
||||||
//! &[b"input"; 10],
|
//! &[b"input"; 10],
|
||||||
//! &client_states,
|
//! &client_states,
|
||||||
//! &server_batch_evaluate_result.messages,
|
//! &messages,
|
||||||
//! &server_batch_evaluate_result.proof,
|
//! &proof,
|
||||||
//! server.get_public_key(),
|
//! server.get_public_key(),
|
||||||
//! None,
|
//! None,
|
||||||
//! )
|
//! )
|
||||||
@@ -527,7 +563,8 @@ pub use crate::group::Group;
|
|||||||
pub use crate::voprf::VerifiableServerBatchEvaluateResult;
|
pub use crate::voprf::VerifiableServerBatchEvaluateResult;
|
||||||
pub use crate::voprf::{
|
pub use crate::voprf::{
|
||||||
BlindedElement, EvaluationElement, NonVerifiableClient, NonVerifiableClientBlindResult,
|
BlindedElement, EvaluationElement, NonVerifiableClient, NonVerifiableClientBlindResult,
|
||||||
NonVerifiableServer, NonVerifiableServerEvaluateResult, Proof, VerifiableClient,
|
NonVerifiableServer, NonVerifiableServerEvaluateResult, PreparedEvaluationElement,
|
||||||
VerifiableClientBatchFinalizeResult, VerifiableClientBlindResult, VerifiableServer,
|
PreparedTscalar, Proof, VerifiableClient, VerifiableClientBatchFinalizeResult,
|
||||||
VerifiableServerEvaluateResult,
|
VerifiableClientBlindResult, VerifiableServer, VerifiableServerBatchEvaluateFinishResult,
|
||||||
|
VerifiableServerBatchEvaluatePrepareResult, VerifiableServerEvaluateResult,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
// License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
// License, Version 2.0 found in the LICENSE-APACHE file in the root directory
|
||||||
// of this source tree.
|
// of this source tree.
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
mod mock_rng;
|
mod mock_rng;
|
||||||
mod parser;
|
mod parser;
|
||||||
mod voprf_test_vectors;
|
mod voprf_test_vectors;
|
||||||
|
|||||||
@@ -8,18 +8,14 @@
|
|||||||
use alloc::string::{String, ToString};
|
use alloc::string::{String, ToString};
|
||||||
use alloc::vec;
|
use alloc::vec;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use core::ops::Add;
|
||||||
|
|
||||||
use digest::core_api::BlockSizeUser;
|
use digest::core_api::BlockSizeUser;
|
||||||
use digest::{Digest, FixedOutputReset};
|
use digest::{Digest, FixedOutputReset};
|
||||||
use generic_array::GenericArray;
|
use generic_array::typenum::Sum;
|
||||||
|
use generic_array::{ArrayLength, GenericArray};
|
||||||
use json::JsonValue;
|
use json::JsonValue;
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
use ::{
|
|
||||||
core::ops::Add,
|
|
||||||
generic_array::{typenum::Sum, ArrayLength},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
use crate::tests::mock_rng::CycleRng;
|
use crate::tests::mock_rng::CycleRng;
|
||||||
use crate::tests::parser::*;
|
use crate::tests::parser::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -38,7 +34,6 @@ struct VOPRFTestVectorParameters {
|
|||||||
blinded_element: Vec<Vec<u8>>,
|
blinded_element: Vec<Vec<u8>>,
|
||||||
evaluation_element: Vec<Vec<u8>>,
|
evaluation_element: Vec<Vec<u8>>,
|
||||||
proof: Vec<u8>,
|
proof: Vec<u8>,
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
proof_random_scalar: Vec<u8>,
|
proof_random_scalar: Vec<u8>,
|
||||||
output: Vec<Vec<u8>>,
|
output: Vec<Vec<u8>>,
|
||||||
}
|
}
|
||||||
@@ -54,7 +49,6 @@ fn populate_test_vectors(values: &JsonValue) -> VOPRFTestVectorParameters {
|
|||||||
blinded_element: decode_vec(values, "BlindedElement"),
|
blinded_element: decode_vec(values, "BlindedElement"),
|
||||||
evaluation_element: decode_vec(values, "EvaluationElement"),
|
evaluation_element: decode_vec(values, "EvaluationElement"),
|
||||||
proof: decode(values, "Proof"),
|
proof: decode(values, "Proof"),
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
proof_random_scalar: decode(values, "ProofRandomScalar"),
|
proof_random_scalar: decode(values, "ProofRandomScalar"),
|
||||||
output: decode_vec(values, "Output"),
|
output: decode_vec(values, "Output"),
|
||||||
}
|
}
|
||||||
@@ -118,7 +112,6 @@ fn test_vectors() -> Result<()> {
|
|||||||
|
|
||||||
test_verifiable_seed_to_key::<RistrettoPoint, Sha512>(&ristretto_verifiable_tvs)?;
|
test_verifiable_seed_to_key::<RistrettoPoint, Sha512>(&ristretto_verifiable_tvs)?;
|
||||||
test_verifiable_blind::<RistrettoPoint, Sha512>(&ristretto_verifiable_tvs)?;
|
test_verifiable_blind::<RistrettoPoint, Sha512>(&ristretto_verifiable_tvs)?;
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
test_verifiable_evaluate::<RistrettoPoint, Sha512>(&ristretto_verifiable_tvs)?;
|
test_verifiable_evaluate::<RistrettoPoint, Sha512>(&ristretto_verifiable_tvs)?;
|
||||||
test_verifiable_finalize::<RistrettoPoint, Sha512>(&ristretto_verifiable_tvs)?;
|
test_verifiable_finalize::<RistrettoPoint, Sha512>(&ristretto_verifiable_tvs)?;
|
||||||
}
|
}
|
||||||
@@ -253,7 +246,6 @@ fn test_base_evaluate<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
fn test_verifiable_evaluate<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>(
|
fn test_verifiable_evaluate<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>(
|
||||||
tvs: &[VOPRFTestVectorParameters],
|
tvs: &[VOPRFTestVectorParameters],
|
||||||
) -> Result<()>
|
) -> Result<()>
|
||||||
@@ -261,6 +253,10 @@ where
|
|||||||
G::ScalarLen: Add<G::ScalarLen>,
|
G::ScalarLen: Add<G::ScalarLen>,
|
||||||
Sum<G::ScalarLen, G::ScalarLen>: ArrayLength<u8>,
|
Sum<G::ScalarLen, G::ScalarLen>: ArrayLength<u8>,
|
||||||
{
|
{
|
||||||
|
use crate::{
|
||||||
|
VerifiableServerBatchEvaluateFinishResult, VerifiableServerBatchEvaluatePrepareResult,
|
||||||
|
};
|
||||||
|
|
||||||
for parameters in tvs {
|
for parameters in tvs {
|
||||||
let mut rng = CycleRng::new(parameters.proof_random_scalar.clone());
|
let mut rng = CycleRng::new(parameters.proof_random_scalar.clone());
|
||||||
let server = VerifiableServer::<G, H>::new_with_key(¶meters.sksm)?;
|
let server = VerifiableServer::<G, H>::new_with_key(¶meters.sksm)?;
|
||||||
@@ -270,20 +266,25 @@ where
|
|||||||
blinded_elements.push(BlindedElement::deserialize(blinded_element_bytes)?);
|
blinded_elements.push(BlindedElement::deserialize(blinded_element_bytes)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
let batch_evaluate_result =
|
let VerifiableServerBatchEvaluatePrepareResult {
|
||||||
server.batch_evaluate(&mut rng, &blinded_elements, Some(¶meters.info))?;
|
prepared_evaluation_elements,
|
||||||
|
t,
|
||||||
|
} = server.batch_evaluate_prepare(blinded_elements.iter(), Some(¶meters.info))?;
|
||||||
|
let prepared_elements: Vec<_> = prepared_evaluation_elements.collect();
|
||||||
|
let VerifiableServerBatchEvaluateFinishResult { messages, proof } =
|
||||||
|
VerifiableServer::batch_evaluate_finish(
|
||||||
|
&mut rng,
|
||||||
|
blinded_elements.iter(),
|
||||||
|
&prepared_elements,
|
||||||
|
&t,
|
||||||
|
)?;
|
||||||
|
let messages: Vec<_> = messages.collect();
|
||||||
|
|
||||||
for i in 0..parameters.evaluation_element.len() {
|
for (parameter, message) in parameters.evaluation_element.iter().zip(messages) {
|
||||||
assert_eq!(
|
assert_eq!(¶meter, &message.serialize().as_slice(),);
|
||||||
¶meters.evaluation_element[i],
|
|
||||||
&batch_evaluate_result.messages[i].serialize().as_slice(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(¶meters.proof, &proof.serialize().as_slice());
|
||||||
¶meters.proof,
|
|
||||||
&batch_evaluate_result.proof.serialize().as_slice()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
+173
-65
@@ -511,23 +511,27 @@ impl<G: Group, H: BlockSizeUser + Digest + FixedOutputReset> VerifiableServer<G,
|
|||||||
blinded_element: &BlindedElement<G, H>,
|
blinded_element: &BlindedElement<G, H>,
|
||||||
metadata: Option<&[u8]>,
|
metadata: Option<&[u8]>,
|
||||||
) -> Result<VerifiableServerEvaluateResult<G, H>> {
|
) -> Result<VerifiableServerEvaluateResult<G, H>> {
|
||||||
let (mut evaluation_elements, t) =
|
let VerifiableServerBatchEvaluatePrepareResult {
|
||||||
self.batch_evaluate_1(Some(blinded_element.copy()).into_iter(), metadata)?;
|
prepared_evaluation_elements: mut evaluation_elements,
|
||||||
|
|
||||||
let evaluation_element = evaluation_elements.next().unwrap();
|
|
||||||
|
|
||||||
let proof = Self::batch_evaluate_2(
|
|
||||||
rng,
|
|
||||||
Some(blinded_element.copy()).into_iter(),
|
|
||||||
Some(evaluation_element.copy()).into_iter(),
|
|
||||||
t,
|
t,
|
||||||
|
} = self.batch_evaluate_prepare(Some(blinded_element).into_iter(), metadata)?;
|
||||||
|
|
||||||
|
let prepared_element = [evaluation_elements.next().unwrap()];
|
||||||
|
|
||||||
|
let VerifiableServerBatchEvaluateFinishResult {
|
||||||
|
mut messages,
|
||||||
|
proof,
|
||||||
|
} = Self::batch_evaluate_finish(
|
||||||
|
rng,
|
||||||
|
Some(blinded_element).into_iter(),
|
||||||
|
&prepared_element,
|
||||||
|
&t,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
|
let message = messages.next().unwrap();
|
||||||
|
|
||||||
//let batch_result = self.batch_evaluate(rng, blinded_elements, metadata)?;
|
//let batch_result = self.batch_evaluate(rng, blinded_elements, metadata)?;
|
||||||
Ok(VerifiableServerEvaluateResult {
|
Ok(VerifiableServerEvaluateResult { message, proof })
|
||||||
message: evaluation_element,
|
|
||||||
proof,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allows for batching of the evaluation of multiple [BlindedElement]
|
/// Allows for batching of the evaluation of multiple [BlindedElement]
|
||||||
@@ -545,37 +549,36 @@ impl<G: Group, H: BlockSizeUser + Digest + FixedOutputReset> VerifiableServer<G,
|
|||||||
&'a I: IntoIterator<Item = &'a BlindedElement<G, H>>,
|
&'a I: IntoIterator<Item = &'a BlindedElement<G, H>>,
|
||||||
<&'a I as IntoIterator>::IntoIter: ExactSizeIterator,
|
<&'a I as IntoIterator>::IntoIter: ExactSizeIterator,
|
||||||
{
|
{
|
||||||
let (evaluation_elements, t) = self.batch_evaluate_1(
|
let VerifiableServerBatchEvaluatePrepareResult {
|
||||||
blinded_elements.into_iter().map(BlindedElement::copy),
|
prepared_evaluation_elements: evaluation_elements,
|
||||||
metadata,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let evaluation_elements: Vec<_> = evaluation_elements.collect();
|
|
||||||
|
|
||||||
let proof = Self::batch_evaluate_2(
|
|
||||||
rng,
|
|
||||||
blinded_elements.into_iter().map(BlindedElement::copy),
|
|
||||||
evaluation_elements.iter().map(EvaluationElement::copy),
|
|
||||||
t,
|
t,
|
||||||
)?;
|
} = self.batch_evaluate_prepare(blinded_elements.into_iter(), metadata)?;
|
||||||
|
|
||||||
|
let prepared_elements = evaluation_elements.collect();
|
||||||
|
|
||||||
|
let VerifiableServerBatchEvaluateFinishResult { messages, proof } =
|
||||||
|
Self::batch_evaluate_finish::<_, _, Vec<_>>(
|
||||||
|
rng,
|
||||||
|
blinded_elements.into_iter(),
|
||||||
|
&prepared_elements,
|
||||||
|
&t,
|
||||||
|
)?;
|
||||||
|
|
||||||
Ok(VerifiableServerBatchEvaluateResult {
|
Ok(VerifiableServerBatchEvaluateResult {
|
||||||
messages: evaluation_elements,
|
messages: messages.collect(),
|
||||||
proof,
|
proof,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn batch_evaluate_1<I>(
|
/// Alternative version of [`batch_evaluate`](Self::batch_evaluate) without
|
||||||
|
/// memory allocation. Returned [`PreparedEvaluationElement`] have to be
|
||||||
|
/// [`collect`](Iterator::collect)ed and passed into
|
||||||
|
/// [`batch_evaluate_finish`](Self::batch_evaluate_finish).
|
||||||
|
pub fn batch_evaluate_prepare<'a, I: Iterator<Item = &'a BlindedElement<G, H>>>(
|
||||||
&self,
|
&self,
|
||||||
blinded_elements: I,
|
blinded_elements: I,
|
||||||
metadata: Option<&[u8]>,
|
metadata: Option<&[u8]>,
|
||||||
) -> Result<(
|
) -> Result<VerifiableServerBatchEvaluatePrepareResult<'a, G, H, I>> {
|
||||||
impl Iterator<Item = EvaluationElement<G, H>> + ExactSizeIterator,
|
|
||||||
G::Scalar,
|
|
||||||
)>
|
|
||||||
where
|
|
||||||
I: Iterator<Item = BlindedElement<G, H>> + ExactSizeIterator,
|
|
||||||
{
|
|
||||||
chain!(context,
|
chain!(context,
|
||||||
STR_CONTEXT => |x| Some(x.as_ref()),
|
STR_CONTEXT => |x| Some(x.as_ref()),
|
||||||
get_context_string::<G>(Mode::Verifiable)? => |x| Some(x.as_slice()),
|
get_context_string::<G>(Mode::Verifiable)? => |x| Some(x.as_slice()),
|
||||||
@@ -585,30 +588,62 @@ impl<G: Group, H: BlockSizeUser + Digest + FixedOutputReset> VerifiableServer<G,
|
|||||||
.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 = blinded_elements.map(move |x| EvaluationElement {
|
let evaluation_elements = blinded_elements
|
||||||
value: x.value * &G::scalar_invert(&t),
|
// To make a return type possible, we have to convert to a `fn` pointer, which isn't
|
||||||
hash: PhantomData,
|
// possible if we `move` from context.
|
||||||
});
|
.zip(iter::repeat(G::scalar_invert(&t)))
|
||||||
|
.map(<fn((&BlindedElement<G, H>, _)) -> _>::from(|(x, t)| {
|
||||||
|
PreparedEvaluationElement(EvaluationElement {
|
||||||
|
value: x.value * &t,
|
||||||
|
hash: PhantomData,
|
||||||
|
})
|
||||||
|
}));
|
||||||
|
|
||||||
Ok((evaluation_elements, t))
|
Ok(VerifiableServerBatchEvaluatePrepareResult {
|
||||||
|
prepared_evaluation_elements: evaluation_elements,
|
||||||
|
t: PreparedTscalar {
|
||||||
|
t,
|
||||||
|
hash: PhantomData,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allows for batching of the evaluation of multiple [BlindedElement]
|
/// See [`batch_evaluate_prepare`](Self::batch_evaluate_prepare) for more
|
||||||
/// messages from a [VerifiableClient]
|
/// details.
|
||||||
fn batch_evaluate_2<R: RngCore + CryptoRng, IE, IB>(
|
pub fn batch_evaluate_finish<'a, 'b, R: RngCore + CryptoRng, IB, IE>(
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
blinded_elements: IB,
|
blinded_elements: IB,
|
||||||
evaluation_elements: IE,
|
evaluation_elements: &'b IE,
|
||||||
t: G::Scalar,
|
PreparedTscalar { t, .. }: &PreparedTscalar<G, H>,
|
||||||
) -> Result<Proof<G, H>>
|
) -> Result<VerifiableServerBatchEvaluateFinishResult<'b, G, H, IE>>
|
||||||
where
|
where
|
||||||
IB: Iterator<Item = BlindedElement<G, H>> + ExactSizeIterator,
|
G: 'a + 'b,
|
||||||
IE: Iterator<Item = EvaluationElement<G, H>> + ExactSizeIterator,
|
H: 'a + 'b,
|
||||||
|
IB: Iterator<Item = &'a BlindedElement<G, H>> + ExactSizeIterator,
|
||||||
|
&'b IE: IntoIterator<Item = &'b PreparedEvaluationElement<G, H>>,
|
||||||
|
<&'b IE as IntoIterator>::IntoIter: ExactSizeIterator,
|
||||||
{
|
{
|
||||||
let g = G::base_point();
|
let g = G::base_point();
|
||||||
let u = g * &t;
|
let u = g * t;
|
||||||
|
|
||||||
generate_proof(rng, t, g, u, evaluation_elements, blinded_elements)
|
let proof = generate_proof(
|
||||||
|
rng,
|
||||||
|
*t,
|
||||||
|
g,
|
||||||
|
u,
|
||||||
|
evaluation_elements
|
||||||
|
.into_iter()
|
||||||
|
.map(|element| element.0.copy()),
|
||||||
|
blinded_elements.map(BlindedElement::copy),
|
||||||
|
)?;
|
||||||
|
let messages =
|
||||||
|
evaluation_elements
|
||||||
|
.into_iter()
|
||||||
|
.map(<fn(&PreparedEvaluationElement<G, H>) -> _>::from(
|
||||||
|
|element| element.0.copy(),
|
||||||
|
));
|
||||||
|
|
||||||
|
Ok(VerifiableServerBatchEvaluateFinishResult { messages, proof })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Retrieves the server's public key
|
/// Retrieves the server's public key
|
||||||
@@ -662,6 +697,59 @@ pub struct VerifiableServerEvaluateResult<G: Group, H: BlockSizeUser + Digest +
|
|||||||
pub proof: Proof<G, H>,
|
pub proof: Proof<G, H>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Contains prepared [`EvaluationElement`]s by a verifiable server batch
|
||||||
|
/// evaluate preparation.
|
||||||
|
pub struct PreparedEvaluationElement<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>(
|
||||||
|
EvaluationElement<G, H>,
|
||||||
|
);
|
||||||
|
|
||||||
|
/// Contains the prepared `t` by a verifiable server batch evaluate preparation.
|
||||||
|
#[derive(DeriveWhere)]
|
||||||
|
#[derive_where(Zeroize(drop))]
|
||||||
|
pub struct PreparedTscalar<G: Group, H: BlockSizeUser + Digest + FixedOutputReset> {
|
||||||
|
t: G::Scalar,
|
||||||
|
#[derive_where(skip)]
|
||||||
|
hash: PhantomData<H>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Contains the fields that are returned by a verifiable server batch evaluate
|
||||||
|
/// preparation.
|
||||||
|
pub struct VerifiableServerBatchEvaluatePrepareResult<
|
||||||
|
'a,
|
||||||
|
G: 'a + Group,
|
||||||
|
H: 'a + BlockSizeUser + Digest + FixedOutputReset,
|
||||||
|
I: Iterator<Item = &'a BlindedElement<G, H>>,
|
||||||
|
> {
|
||||||
|
/// Prepared [`EvaluationElement`]s that will become messages.
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
pub prepared_evaluation_elements: Map<
|
||||||
|
Zip<I, Repeat<G::Scalar>>,
|
||||||
|
fn((&BlindedElement<G, H>, G::Scalar)) -> PreparedEvaluationElement<G, H>,
|
||||||
|
>,
|
||||||
|
/// Prepared `t` needed to finish the verifiable server batch evaluation.
|
||||||
|
pub t: PreparedTscalar<G, H>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Contains the fields that are returned by a verifiable server batch evaluate
|
||||||
|
/// finish.
|
||||||
|
pub struct VerifiableServerBatchEvaluateFinishResult<
|
||||||
|
'a,
|
||||||
|
G: 'a + Group,
|
||||||
|
H: 'a + BlockSizeUser + Digest + FixedOutputReset,
|
||||||
|
I,
|
||||||
|
> where
|
||||||
|
&'a I: IntoIterator<Item = &'a PreparedEvaluationElement<G, H>>,
|
||||||
|
{
|
||||||
|
/// The messages to send to the client
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
pub messages: Map<
|
||||||
|
<&'a I as IntoIterator>::IntoIter,
|
||||||
|
fn(&PreparedEvaluationElement<G, H>) -> EvaluationElement<G, H>,
|
||||||
|
>,
|
||||||
|
/// The proof for the client to verify
|
||||||
|
pub proof: Proof<G, H>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Contains the fields that are returned by a verifiable server batch evaluate
|
/// Contains the fields that are returned by a verifiable server batch evaluate
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
pub struct VerifiableServerBatchEvaluateResult<
|
pub struct VerifiableServerBatchEvaluateResult<
|
||||||
@@ -1008,12 +1096,12 @@ fn get_context_string<G: Group>(mode: Mode) -> Result<GenericArray<u8, U11>> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use core::ops::Add;
|
use core::ops::Add;
|
||||||
|
|
||||||
|
use ::alloc::vec;
|
||||||
|
use ::alloc::vec::Vec;
|
||||||
use generic_array::typenum::Sum;
|
use generic_array::typenum::Sum;
|
||||||
use generic_array::{ArrayLength, GenericArray};
|
use generic_array::{ArrayLength, GenericArray};
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
use zeroize::Zeroize;
|
use zeroize::Zeroize;
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
use ::{alloc::vec, alloc::vec::Vec};
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::Group;
|
use crate::Group;
|
||||||
@@ -1087,7 +1175,6 @@ mod tests {
|
|||||||
assert_eq!(client_finalize_result, res2);
|
assert_eq!(client_finalize_result, res2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
fn verifiable_bad_public_key<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>() {
|
fn verifiable_bad_public_key<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>() {
|
||||||
let input = b"input";
|
let input = b"input";
|
||||||
let info = b"info";
|
let info = b"info";
|
||||||
@@ -1111,7 +1198,6 @@ mod tests {
|
|||||||
assert!(client_finalize_result.is_err());
|
assert!(client_finalize_result.is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
fn verifiable_batch_retrieval<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>() {
|
fn verifiable_batch_retrieval<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>() {
|
||||||
let info = b"info";
|
let info = b"info";
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
@@ -1128,14 +1214,27 @@ mod tests {
|
|||||||
client_messages.push(client_blind_result.message);
|
client_messages.push(client_blind_result.message);
|
||||||
}
|
}
|
||||||
let server = VerifiableServer::<G, H>::new(&mut rng).unwrap();
|
let server = VerifiableServer::<G, H>::new(&mut rng).unwrap();
|
||||||
let server_result = server
|
let VerifiableServerBatchEvaluatePrepareResult {
|
||||||
.batch_evaluate(&mut rng, &client_messages, Some(info))
|
prepared_evaluation_elements,
|
||||||
|
t,
|
||||||
|
} = server
|
||||||
|
.batch_evaluate_prepare(client_messages.iter(), Some(info))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let prepared_elements: Vec<_> = prepared_evaluation_elements.collect();
|
||||||
|
let VerifiableServerBatchEvaluateFinishResult { messages, proof } =
|
||||||
|
VerifiableServer::batch_evaluate_finish(
|
||||||
|
&mut rng,
|
||||||
|
client_messages.iter(),
|
||||||
|
&prepared_elements,
|
||||||
|
&t,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let messages: Vec<_> = messages.collect();
|
||||||
let client_finalize_result = VerifiableClient::batch_finalize(
|
let client_finalize_result = VerifiableClient::batch_finalize(
|
||||||
&inputs,
|
&inputs,
|
||||||
&client_states,
|
&client_states,
|
||||||
&server_result.messages,
|
&messages,
|
||||||
&server_result.proof,
|
&proof,
|
||||||
server.get_public_key(),
|
server.get_public_key(),
|
||||||
Some(info),
|
Some(info),
|
||||||
)
|
)
|
||||||
@@ -1150,7 +1249,6 @@ mod tests {
|
|||||||
assert_eq!(client_finalize_result, res2);
|
assert_eq!(client_finalize_result, res2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
fn verifiable_batch_bad_public_key<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>() {
|
fn verifiable_batch_bad_public_key<G: Group, H: BlockSizeUser + Digest + FixedOutputReset>() {
|
||||||
let info = b"info";
|
let info = b"info";
|
||||||
let mut rng = OsRng;
|
let mut rng = OsRng;
|
||||||
@@ -1167,9 +1265,22 @@ mod tests {
|
|||||||
client_messages.push(client_blind_result.message);
|
client_messages.push(client_blind_result.message);
|
||||||
}
|
}
|
||||||
let server = VerifiableServer::<G, H>::new(&mut rng).unwrap();
|
let server = VerifiableServer::<G, H>::new(&mut rng).unwrap();
|
||||||
let server_result = server
|
let VerifiableServerBatchEvaluatePrepareResult {
|
||||||
.batch_evaluate(&mut rng, &client_messages, Some(info))
|
prepared_evaluation_elements,
|
||||||
|
t,
|
||||||
|
} = server
|
||||||
|
.batch_evaluate_prepare(client_messages.iter(), Some(info))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let prepared_elements: Vec<_> = prepared_evaluation_elements.collect();
|
||||||
|
let VerifiableServerBatchEvaluateFinishResult { messages, proof } =
|
||||||
|
VerifiableServer::batch_evaluate_finish(
|
||||||
|
&mut rng,
|
||||||
|
client_messages.iter(),
|
||||||
|
&prepared_elements,
|
||||||
|
&t,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let messages: Vec<_> = messages.collect();
|
||||||
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").into()).unwrap()
|
G::hash_to_curve::<H, _>(b"msg", (*b"dst").into()).unwrap()
|
||||||
@@ -1177,8 +1288,8 @@ mod tests {
|
|||||||
let client_finalize_result = VerifiableClient::batch_finalize(
|
let client_finalize_result = VerifiableClient::batch_finalize(
|
||||||
&inputs,
|
&inputs,
|
||||||
&client_states,
|
&client_states,
|
||||||
&server_result.messages,
|
&messages,
|
||||||
&server_result.proof,
|
&proof,
|
||||||
wrong_pk,
|
wrong_pk,
|
||||||
Some(info),
|
Some(info),
|
||||||
);
|
);
|
||||||
@@ -1309,11 +1420,8 @@ mod tests {
|
|||||||
base_retrieval::<RistrettoPoint, Sha512>();
|
base_retrieval::<RistrettoPoint, Sha512>();
|
||||||
base_inversion_unsalted::<RistrettoPoint, Sha512>();
|
base_inversion_unsalted::<RistrettoPoint, Sha512>();
|
||||||
verifiable_retrieval::<RistrettoPoint, Sha512>();
|
verifiable_retrieval::<RistrettoPoint, Sha512>();
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
verifiable_batch_retrieval::<RistrettoPoint, Sha512>();
|
verifiable_batch_retrieval::<RistrettoPoint, Sha512>();
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
verifiable_bad_public_key::<RistrettoPoint, Sha512>();
|
verifiable_bad_public_key::<RistrettoPoint, Sha512>();
|
||||||
#[cfg(feature = "alloc")]
|
|
||||||
verifiable_batch_bad_public_key::<RistrettoPoint, Sha512>();
|
verifiable_batch_bad_public_key::<RistrettoPoint, Sha512>();
|
||||||
|
|
||||||
zeroize_base_client::<RistrettoPoint, Sha512>();
|
zeroize_base_client::<RistrettoPoint, Sha512>();
|
||||||
|
|||||||
Reference in New Issue
Block a user