1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
use ark_crypto_primitives::sponge::{CryptographicSponge, FieldElementSize};
use ark_ff::PrimeField;
/// `ChallengeGenerator` generates opening challenges using multivariate or univariate strategy.
/// For multivariate strategy, each challenge is freshly squeezed from a sponge.
/// For univariate strategy, each challenge is a power of one squeezed element from sponge.
///
/// Note that mutable reference cannot be cloned.
#[derive(Clone)]
pub enum ChallengeGenerator<F: PrimeField, S: CryptographicSponge> {
/// Each challenge is freshly squeezed from a sponge.
Multivariate(S),
/// Each challenge is a power of one squeezed element from sponge.
///
/// `Univariate(generator, next_element)`
Univariate(F, F),
}
impl<F: PrimeField, S: CryptographicSponge> ChallengeGenerator<F, S> {
/// Returns a challenge generator with multivariate strategy. Each challenge is freshly squeezed
/// from a sponge.
pub fn new_multivariate(sponge: S) -> Self {
Self::Multivariate(sponge)
}
/// Returns a challenge generator with univariate strategy. Each challenge is a power of one
/// squeezed element from sponge.
pub fn new_univariate(sponge: &mut S) -> Self {
let gen = sponge.squeeze_field_elements(1)[0];
Self::Univariate(gen, gen)
}
/// Returns a challenge of size `size`.
/// * If `self == Self::Multivariate(...)`, then this squeezes out a challenge of size `size`.
/// * If `self == Self::Univariate(...)`, then this ignores the `size` argument and simply squeezes out
/// the next field element.
pub fn try_next_challenge_of_size(&mut self, size: FieldElementSize) -> F {
match self {
// multivariate (full)
Self::Multivariate(sponge) => sponge.squeeze_field_elements_with_sizes(&[size])[0],
// univariate
Self::Univariate(gen, next) => {
let result = next.clone();
*next *= *gen;
result
}
}
}
/// Returns the next challenge generated.
pub fn next_challenge(&mut self) -> F {
self.try_next_challenge_of_size(FieldElementSize::Full)
}
/// Returns the sponge state if `self` is multivariate. Returns `None` otherwise.
pub fn into_sponge(self) -> Option<S> {
match self {
Self::Multivariate(s) => Some(s),
_ => None,
}
}
}