Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 24 additions & 27 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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<Item = Self::Member>,
) -> Result<Self::Commitment, ()>;
Expand Down Expand Up @@ -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,
}
Expand All @@ -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,
}
Expand All @@ -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<Alias, ()> {
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]],
Expand All @@ -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<Self::Proof>],
) -> Result<Vec<Alias>, ()> {
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()
}

Expand Down Expand Up @@ -293,7 +295,7 @@ impl<Gen: GenerateVerifiable> Receipt<Gen> {
/// 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<Item = Gen::Member>,
context: &[u8],
Expand All @@ -302,7 +304,7 @@ impl<Gen: GenerateVerifiable> Receipt<Gen> {
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,
Expand All @@ -328,24 +330,19 @@ impl<Gen: GenerateVerifiable> Receipt<Gen> {
/// 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<u8>), 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,
Expand Down
8 changes: 4 additions & 4 deletions src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}

Expand Down Expand Up @@ -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<Item = Self::Member>,
) -> Result<Self::Commitment, ()> {
Expand Down Expand Up @@ -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]],
Expand Down
33 changes: 7 additions & 26 deletions src/ring/bandersnatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,9 @@ impl VerifierCache<BandersnatchSha512Ell2> for BandersnatchVerifierCache {
fn get(domain_size: RingDomainSize) -> Self::Handle {
use spin::Once;
type P = ark_vrf::ring::RingContext<BandersnatchSha512Ell2>;
static D11: Once<P> = Once::new();
static D12: Once<P> = Once::new();
static D16: Once<P> = 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<P>; RingDomainSize::VARIANTS.len()] =
[const { Once::new() }; RingDomainSize::VARIANTS.len()];
CELLS[domain_size as usize].call_once(|| make_ring_context(domain_size))
}
}

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

Expand Down Expand Up @@ -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!(
Expand Down
41 changes: 19 additions & 22 deletions src/ring/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,22 +38,19 @@ pub enum RingDomainSize {
impl TryFrom<u32> for RingDomainSize {
type Error = ();
fn try_from(value: u32) -> Result<Self, Self::Error> {
const ALL: [RingDomainSize; 3] = [
RingDomainSize::Domain11,
RingDomainSize::Domain12,
RingDomainSize::Domain16,
];
ALL.iter().copied().find(|d| d.value() == value).ok_or(())
}
}

impl From<RingDomainSize> 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 {
Expand Down Expand Up @@ -557,11 +554,11 @@ impl<S: RingSuiteExt> GenerateVerifiable for RingVrfVerifiable<S> {
type Proof = BoundedVec<u8, MaxRingVrfSignatureLen<S>>;
type Signature = S::SignatureBytes;
type StaticChunk = StaticChunk<S>;
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()
}

Expand Down Expand Up @@ -605,13 +602,13 @@ impl<S: RingSuiteExt> GenerateVerifiable for RingVrfVerifiable<S> {
}

fn validate_multi_context(
capacity: Self::Capacity,
config: Self::Config,
proof: &Self::Proof,
members: &Self::Members,
contexts: &[&[u8]],
message: &[u8],
) -> Result<Vec<Alias>, ()> {
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::<S>::deserialize_canonical(proof.as_slice())?;
Expand Down Expand Up @@ -647,11 +644,11 @@ impl<S: RingSuiteExt> GenerateVerifiable for RingVrfVerifiable<S> {
// 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<Self::Proof>],
) -> Result<Vec<Alias>, ()> {
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());
Expand Down Expand Up @@ -686,7 +683,7 @@ impl<S: RingSuiteExt> GenerateVerifiable for RingVrfVerifiable<S> {

#[cfg(feature = "prover")]
fn open(
capacity: Self::Capacity,
config: Self::Config,
member: &Self::Member,
members: impl Iterator<Item = Self::Member>,
) -> Result<Self::Commitment, ()> {
Expand All @@ -695,11 +692,11 @@ impl<S: RingSuiteExt> GenerateVerifiable for RingVrfVerifiable<S> {
.collect::<Result<Vec<_>, _>>()?;
let member = PublicKey::<S>::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,
})
Expand Down
Loading