diff --git a/src/lib.rs b/src/lib.rs index f679eb2..2bec6d0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -93,17 +93,21 @@ pub trait GenerateVerifiable { /// For ring VRF implementations, this is typically a G1 affine point from the SRS. type StaticChunk: Clone + Eq + PartialEq + FullCodec + Debug + TypeInfo + MaxEncodedLen; - /// The capacity type used to parametrize ring operations. - type Capacity: Clone + Copy; - /// A signature attributable to a specific `Member`, verifiable against that member's /// public key. /// /// Created via `sign`, verified via `verify_signature`. type Signature: Clone + Eq + PartialEq + FullCodec + Debug + TypeInfo; + /// Per-call configuration for the operations below. + /// + /// Used by implementations that support multiple parameter sets to select + /// which one applies at each call (for ring VRF: which domain/ring size). + /// Set to `()` when there is nothing to configure. + type Config: Clone + Copy; + /// Begin building a `Members` value. - fn start_members(capacity: Self::Capacity) -> Self::Intermediate; + fn start_members(config: Self::Config) -> Self::Intermediate; /// Introduce a set of new `Member`s into the intermediate value used to build a new `Members` /// value. @@ -144,7 +148,7 @@ pub trait GenerateVerifiable { /// implementing the functionality. #[cfg(feature = "prover")] fn open( - capacity: Self::Capacity, + config: Self::Config, member: &Self::Member, members_iter: impl Iterator, ) -> Result; @@ -193,14 +197,14 @@ pub trait GenerateVerifiable { /// if so, ensure that the member is necessarily associated with `alias` in this `context` and /// that they elected to opine `message`. fn is_valid( - capacity: Self::Capacity, + config: Self::Config, proof: &Self::Proof, members: &Self::Members, context: &[u8], alias: &Alias, message: &[u8], ) -> bool { - match Self::validate(capacity, proof, members, context, message) { + match Self::validate(config, proof, members, context, message) { Ok(a) => &a == alias, Err(()) => false, } @@ -210,14 +214,14 @@ pub trait GenerateVerifiable { /// if so, ensure that the member is necessarily associated with corresponding `alias` from the given `aliases` in this `context` and /// that they elected to opine `message`. fn is_valid_multi_context( - capacity: Self::Capacity, + config: Self::Config, proof: &Self::Proof, members: &Self::Members, contexts: &[&[u8]], aliases: &[Alias], message: &[u8], ) -> bool { - match Self::validate_multi_context(capacity, proof, members, contexts, message) { + match Self::validate_multi_context(config, proof, members, contexts, message) { Ok(a) => a == aliases, Err(()) => false, } @@ -228,19 +232,19 @@ pub trait GenerateVerifiable { /// Like `is_valid`, but `alias` is returned, not provided. fn validate( - capacity: Self::Capacity, + config: Self::Config, proof: &Self::Proof, members: &Self::Members, context: &[u8], message: &[u8], ) -> Result { - let result = Self::validate_multi_context(capacity, proof, members, &[context], message)?; + let result = Self::validate_multi_context(config, proof, members, &[context], message)?; Ok(result[0]) } /// Like `is_valid_multi_context`, but aliases are returned, not provided. fn validate_multi_context( - capacity: Self::Capacity, + config: Self::Config, proof: &Self::Proof, members: &Self::Members, contexts: &[&[u8]], @@ -253,15 +257,13 @@ pub trait GenerateVerifiable { /// Currently only supports single-context proofs. Multi-context proofs should be /// validated individually via [`Self::validate_multi_context`]. fn batch_validate( - capacity: Self::Capacity, + config: Self::Config, members: &Self::Members, proofs: &[BatchProofItem], ) -> Result, ()> { proofs .iter() - .map(|item| { - Self::validate(capacity, &item.proof, members, &item.context, &item.message) - }) + .map(|item| Self::validate(config, &item.proof, members, &item.context, &item.message)) .collect() } @@ -293,7 +295,7 @@ impl Receipt { /// Combines [`GenerateVerifiable::open`] and [`GenerateVerifiable::create`]. #[cfg(feature = "prover")] pub fn create<'a>( - capacity: Gen::Capacity, + config: Gen::Config, secret: &Gen::Secret, members: impl Iterator, context: &[u8], @@ -302,7 +304,7 @@ impl Receipt { where Gen::Member: 'a, { - let commitment = Gen::open(capacity, &Gen::member_from_secret(secret), members)?; + let commitment = Gen::open(config, &Gen::member_from_secret(secret), members)?; let (proof, alias) = Gen::create(commitment, secret, context, &message)?; Ok(Self { proof, @@ -328,24 +330,19 @@ impl Receipt { /// the receipt back so it can be inspected or retried. pub fn verify( self, - capacity: Gen::Capacity, + config: Gen::Config, members: &Gen::Members, context: &[u8], ) -> Result<(Alias, Vec), Self> { - match Gen::validate(capacity, &self.proof, members, context, &self.message) { + match Gen::validate(config, &self.proof, members, context, &self.message) { Ok(alias) => Ok((alias, self.message)), Err(()) => Err(self), } } /// Check whether this receipt contains a valid proof for the given `members` and `context`. - pub fn is_valid( - &self, - capacity: Gen::Capacity, - members: &Gen::Members, - context: &[u8], - ) -> bool { + pub fn is_valid(&self, config: Gen::Config, members: &Gen::Members, context: &[u8]) -> bool { Gen::is_valid( - capacity, + config, &self.proof, members, context, diff --git a/src/mock.rs b/src/mock.rs index 54a8191..90f32dd 100644 --- a/src/mock.rs +++ b/src/mock.rs @@ -85,9 +85,9 @@ impl GenerateVerifiable for Mock { type Proof = MockProof; type Signature = [u8; 32]; type StaticChunk = (); - type Capacity = (); + type Config = (); - fn start_members(_capacity: Self::Capacity) -> Self::Intermediate { + fn start_members(_config: Self::Config) -> Self::Intermediate { BoundedVec::new() } @@ -119,7 +119,7 @@ impl GenerateVerifiable for Mock { #[cfg(feature = "prover")] fn open( - _capacity: Self::Capacity, + _config: Self::Config, member: &Self::Member, members: impl Iterator, ) -> Result { @@ -155,7 +155,7 @@ impl GenerateVerifiable for Mock { } fn validate_multi_context( - _capacity: Self::Capacity, + _config: Self::Config, proof: &Self::Proof, members: &Self::Members, contexts: &[&[u8]], diff --git a/src/ring/bandersnatch.rs b/src/ring/bandersnatch.rs index fd992a7..12654dd 100644 --- a/src/ring/bandersnatch.rs +++ b/src/ring/bandersnatch.rs @@ -30,15 +30,9 @@ impl VerifierCache for BandersnatchVerifierCache { fn get(domain_size: RingDomainSize) -> Self::Handle { use spin::Once; type P = ark_vrf::ring::RingContext; - static D11: Once

= Once::new(); - static D12: Once

= Once::new(); - static D16: Once

= Once::new(); - let init = || make_ring_context(domain_size); - match domain_size { - RingDomainSize::Domain11 => D11.call_once(init), - RingDomainSize::Domain12 => D12.call_once(init), - RingDomainSize::Domain16 => D16.call_once(init), - } + static CELLS: [Once

; RingDomainSize::VARIANTS.len()] = + [const { Once::new() }; RingDomainSize::VARIANTS.len()]; + CELLS[domain_size as usize].call_once(|| make_ring_context(domain_size)) } } @@ -55,15 +49,9 @@ impl ProverCache for BandersnatchProverCache { fn get(domain_size: RingDomainSize) -> Self::Handle { use spin::Once; type P = ark_vrf::ring::RingSetup; - static D11: Once

= Once::new(); - static D12: Once

= Once::new(); - static D16: Once

= Once::new(); - let init = || make_ring_setup(domain_size); - match domain_size { - RingDomainSize::Domain11 => D11.call_once(init), - RingDomainSize::Domain12 => D12.call_once(init), - RingDomainSize::Domain16 => D16.call_once(init), - } + static CELLS: [Once

; RingDomainSize::VARIANTS.len()] = + [const { Once::new() }; RingDomainSize::VARIANTS.len()]; + CELLS[domain_size as usize].call_once(|| make_ring_setup(domain_size)) } } @@ -336,14 +324,7 @@ mod builder_tests { fn generate_empty_ring_builders() { use std::io::Write; - /// All available domain sizes. - const ALL: [RingDomainSize; 3] = [ - RingDomainSize::Domain11, - RingDomainSize::Domain12, - RingDomainSize::Domain16, - ]; - - for domain_size in ALL { + for domain_size in RingDomainSize::VARIANTS { let (builder, builder_params) = start_members_from_params(domain_size); let builder_file = format!( diff --git a/src/ring/mod.rs b/src/ring/mod.rs index 0e5e88a..0e9aeb2 100644 --- a/src/ring/mod.rs +++ b/src/ring/mod.rs @@ -38,22 +38,19 @@ pub enum RingDomainSize { impl TryFrom for RingDomainSize { type Error = (); fn try_from(value: u32) -> Result { - const ALL: [RingDomainSize; 3] = [ - RingDomainSize::Domain11, - RingDomainSize::Domain12, - RingDomainSize::Domain16, - ]; - ALL.iter().copied().find(|d| d.value() == value).ok_or(()) - } -} - -impl From for u32 { - fn from(value: RingDomainSize) -> Self { - value.value() + Self::VARIANTS + .iter() + .copied() + .find(|d| d.value() == value) + .ok_or(()) } } impl RingDomainSize { + /// All variants, in declaration order. Reuse this instead of redefining + /// the array at call sites. + pub(crate) const VARIANTS: [Self; 3] = [Self::Domain11, Self::Domain12, Self::Domain16]; + /// Returns the domain size as a power of 2. pub const fn as_power(self) -> u32 { match self { @@ -557,11 +554,11 @@ impl GenerateVerifiable for RingVrfVerifiable { type Proof = BoundedVec>; type Signature = S::SignatureBytes; type StaticChunk = StaticChunk; - type Capacity = RingDomainSize; + type Config = RingDomainSize; - fn start_members(capacity: Self::Capacity) -> Self::Intermediate { + fn start_members(config: Self::Config) -> Self::Intermediate { // TODO: Optimize by caching the deserialized value; must be compatible with the WASM runtime environment. - let data = S::CurveParams::empty_ring_commitment(capacity); + let data = S::CurveParams::empty_ring_commitment(config); MembersSet::deserialize_uncompressed_unchecked(data).unwrap() } @@ -605,13 +602,13 @@ impl GenerateVerifiable for RingVrfVerifiable { } fn validate_multi_context( - capacity: Self::Capacity, + config: Self::Config, proof: &Self::Proof, members: &Self::Members, contexts: &[&[u8]], message: &[u8], ) -> Result, ()> { - let verifier_params = S::VerifierCache::get(capacity); + let verifier_params = S::VerifierCache::get(config); let ring_verifier = verifier_params.ring_verifier(members.0.clone()); let signature = RingVrfSignature::::deserialize_canonical(proof.as_slice())?; @@ -647,11 +644,11 @@ impl GenerateVerifiable for RingVrfVerifiable { // 2. maintain a list of caches (one for each verifier key) // - the loop below needs to build the `verifier` using the appropriate verifier key fn batch_validate( - capacity: Self::Capacity, + config: Self::Config, members: &Self::Members, proofs: &[BatchProofItem], ) -> Result, ()> { - let verifier_params = S::VerifierCache::get(capacity); + let verifier_params = S::VerifierCache::get(config); let verifier = verifier_params.ring_verifier(members.0.clone()); let mut aliases = Vec::with_capacity(proofs.len()); @@ -686,7 +683,7 @@ impl GenerateVerifiable for RingVrfVerifiable { #[cfg(feature = "prover")] fn open( - capacity: Self::Capacity, + config: Self::Config, member: &Self::Member, members: impl Iterator, ) -> Result { @@ -695,11 +692,11 @@ impl GenerateVerifiable for RingVrfVerifiable { .collect::, _>>()?; let member = PublicKey::::deserialize_canonical(member.as_ref())?; let prover_idx = pks.iter().position(|&m| m == member.0).ok_or(())? as u32; - let prover_key = S::ProverCache::get(capacity) + let prover_key = S::ProverCache::get(config) .prover_key(&pks) .map_err(|_| ())?; Ok(ProverState { - domain_size: capacity.value(), + domain_size: config.value(), prover_idx, prover_key, })