#[cfg(not(feature = "prover"))]
use crate::ring::make_ring_context;
use crate::ring::{
Bls12_381Params, RingContext, RingDomainSize, RingSuiteExt, RingVrfVerifiable, VerifierCache,
make_canonical_pcs_vk, make_empty_members_set,
};
use alloc::borrow::Cow;
pub use ark_vrf::suites::bandersnatch::BandersnatchSha512Ell2;
use spin::Once;
#[cfg(feature = "prover")]
use crate::ring::{ProverCache, make_ring_setup};
pub type BandersnatchVrfVerifiable = RingVrfVerifiable<BandersnatchSha512Ell2>;
pub struct BandersnatchVerifierCache;
impl VerifierCache<BandersnatchSha512Ell2> for BandersnatchVerifierCache {
#[cfg(feature = "prover")]
fn ring_context(
domain_size: RingDomainSize,
) -> Cow<'static, RingContext<BandersnatchSha512Ell2>> {
Cow::Borrowed(BandersnatchProverCache::setup(domain_size).ring_context())
}
#[cfg(not(feature = "prover"))]
fn ring_context(
domain_size: RingDomainSize,
) -> Cow<'static, RingContext<BandersnatchSha512Ell2>> {
type P = RingContext<BandersnatchSha512Ell2>;
static CELLS: [Once<P>; RingDomainSize::VARIANTS.len()] =
[const { Once::new() }; RingDomainSize::VARIANTS.len()];
Cow::Borrowed(CELLS[domain_size as usize].call_once(|| make_ring_context(domain_size)))
}
fn verifier_params() -> ark_vrf::ring::PcsVerifierParams<BandersnatchSha512Ell2> {
static CELL: Once<ark_vrf::ring::PcsVerifierParams<BandersnatchSha512Ell2>> = Once::new();
CELL.call_once(make_canonical_pcs_vk::<BandersnatchSha512Ell2>)
.clone()
}
fn empty_members_set(
domain_size: RingDomainSize,
) -> crate::ring::MembersSet<BandersnatchSha512Ell2> {
type M = crate::ring::MembersSet<BandersnatchSha512Ell2>;
static CELLS: [Once<M>; RingDomainSize::VARIANTS.len()] =
[const { Once::new() }; RingDomainSize::VARIANTS.len()];
CELLS[domain_size as usize]
.call_once(|| make_empty_members_set(domain_size))
.clone()
}
}
#[cfg(feature = "prover")]
pub struct BandersnatchProverCache;
#[cfg(feature = "prover")]
impl BandersnatchProverCache {
fn setup(
domain_size: RingDomainSize,
) -> &'static ark_vrf::ring::RingSetup<BandersnatchSha512Ell2> {
type P = ark_vrf::ring::RingSetup<BandersnatchSha512Ell2>;
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))
}
}
#[cfg(feature = "prover")]
impl ProverCache<BandersnatchSha512Ell2> for BandersnatchProverCache {
fn ring_setup(
domain_size: RingDomainSize,
) -> Cow<'static, ark_vrf::ring::RingSetup<BandersnatchSha512Ell2>> {
Cow::Borrowed(Self::setup(domain_size))
}
}
impl RingSuiteExt for ark_vrf::suites::bandersnatch::BandersnatchSha512Ell2 {
const VRF_INPUT_DOMAIN: &[u8] = b"VerifiableBandersnatchVrfInput";
const PUBLIC_KEY_SIZE: usize = 32;
const MEMBERS_SET_SIZE: usize = 848;
const MEMBERS_COMMITMENT_SIZE: usize = 288;
const STATIC_CHUNK_SIZE: usize = 96;
const SIGNATURE_SIZE: usize = 64;
const RING_PROOF_SIZE: usize = 752;
const VRF_OUTPUT_SIZE: usize = 32;
type CurveParams = Bls12_381Params;
type PublicKeyBytes = [u8; Self::PUBLIC_KEY_SIZE];
type SignatureBytes = [u8; Self::SIGNATURE_SIZE];
type VerifierCache = BandersnatchVerifierCache;
#[cfg(feature = "prover")]
type ProverCache = BandersnatchProverCache;
}
#[cfg(test)]
mod tests {
use ark_scale::MaxEncodedLen;
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_vrf::ring::SrsLookup;
use super::*;
use crate::{GenerateVerifiable, ring::ring_signature_size};
pub type MembersSet = crate::ring::MembersSet<BandersnatchSha512Ell2>;
pub type MembersCommitment = crate::ring::MembersCommitment<BandersnatchSha512Ell2>;
pub type StaticChunk = crate::ring::StaticChunk<BandersnatchSha512Ell2>;
type RingBuilderPcsParams = ark_vrf::ring::RingBuilderPcsParams<BandersnatchSha512Ell2>;
pub fn bandersnatch_ring_setup(
domain_size: RingDomainSize,
) -> &'static ark_vrf::ring::RingSetup<BandersnatchSha512Ell2> {
BandersnatchProverCache::setup(domain_size)
}
pub fn start_members_from_params(
domain_size: RingDomainSize,
) -> (MembersSet, RingBuilderPcsParams) {
let (builder, builder_pcs_params) =
bandersnatch_ring_setup(domain_size).verifier_key_builder();
(crate::ring::MembersSet(builder), builder_pcs_params)
}
#[test]
fn test_plain_signature() {
let msg = b"asd";
let secret = BandersnatchVrfVerifiable::new_secret([0; 32]);
let public = BandersnatchVrfVerifiable::member_from_secret(&secret);
let signature = BandersnatchVrfVerifiable::sign(&secret, msg).unwrap();
let res = BandersnatchVrfVerifiable::verify_signature(&signature, msg, &public);
assert!(res);
}
#[test]
fn test_is_member_valid_invalid() {
let invalid_member = [0u8; 32];
assert!(!BandersnatchVrfVerifiable::is_member_valid(&invalid_member));
}
#[test]
fn test_is_member_valid_valid() {
let secret = BandersnatchVrfVerifiable::new_secret([42u8; 32]);
let valid_member = BandersnatchVrfVerifiable::member_from_secret(&secret);
assert!(BandersnatchVrfVerifiable::is_member_valid(&valid_member));
}
#[test]
fn ring_size_check() {
const DOM_TO_RING_SIZE_MAP: [(RingDomainSize, usize); 3] = [
(RingDomainSize::Domain11, 255),
(RingDomainSize::Domain12, 767),
(RingDomainSize::Domain16, 16127),
];
for (dom_size, exp_ring_size) in DOM_TO_RING_SIZE_MAP {
assert_eq!(
dom_size.max_ring_size::<BandersnatchSha512Ell2>(),
exp_ring_size
);
}
}
#[test]
fn codec_assumptions_check() {
use ark_vrf::suites::bandersnatch::BandersnatchSha512Ell2 as S;
let secret = BandersnatchVrfVerifiable::new_secret([0u8; 32]);
let public = BandersnatchVrfVerifiable::member_from_secret(&secret);
let internal = crate::ring::PublicKey::<BandersnatchSha512Ell2>::deserialize_compressed(
public.as_ref(),
)
.unwrap();
assert_eq!(internal.compressed_size(), S::PUBLIC_KEY_SIZE);
let members_set = BandersnatchVrfVerifiable::start_members(RingDomainSize::Domain11);
assert_eq!(members_set.uncompressed_size(), S::MEMBERS_SET_SIZE);
assert_eq!(MembersSet::max_encoded_len(), S::MEMBERS_SET_SIZE);
let commitment = BandersnatchVrfVerifiable::finish_members(members_set);
assert_eq!(commitment.uncompressed_size(), S::MEMBERS_COMMITMENT_SIZE);
assert_eq!(
MembersCommitment::max_encoded_len(),
S::MEMBERS_COMMITMENT_SIZE
);
let (_, builder_params) = start_members_from_params(RingDomainSize::Domain11);
let chunks: Vec<_> = (&builder_params).lookup(0..1).unwrap();
let chunk: StaticChunk = crate::ring::StaticChunk(chunks[0]);
assert_eq!(chunk.uncompressed_size(), S::STATIC_CHUNK_SIZE);
assert_eq!(StaticChunk::max_encoded_len(), S::STATIC_CHUNK_SIZE);
let signature = BandersnatchVrfVerifiable::sign(&secret, b"test").unwrap();
assert_eq!(signature.len(), S::SIGNATURE_SIZE);
}
#[test]
fn empty_members_set_cache_consistency() {
for &domain in RingDomainSize::VARIANTS.iter() {
assert_eq!(
BandersnatchVerifierCache::empty_members_set(domain),
crate::ring::make_empty_members_set(domain),
);
}
}
#[test]
fn canonical_pcs_vk_is_domain_independent() {
let canonical = crate::ring::make_canonical_pcs_vk::<BandersnatchSha512Ell2>();
for &domain in RingDomainSize::VARIANTS.iter() {
let from_domain = BandersnatchVrfVerifiable::start_members(domain)
.0
.pcs_verifier_params();
assert_eq!(from_domain, canonical);
}
assert_eq!(BandersnatchVerifierCache::verifier_params(), canonical);
}
#[cfg(feature = "prover")]
#[test]
fn canonical_pcs_vk_matches_srs() {
let domain = RingDomainSize::Domain11;
let pcs_params = &bandersnatch_ring_setup(domain).pcs_params;
let canonical = crate::ring::make_canonical_pcs_vk::<BandersnatchSha512Ell2>();
assert_eq!(canonical.g1, pcs_params.powers_in_g1[0]);
assert_eq!(canonical.g2, pcs_params.powers_in_g2[0]);
assert_eq!(canonical.tau_in_g2, pcs_params.powers_in_g2[1]);
}
#[cfg(feature = "prover")]
#[test]
fn proof_size_check() {
use ark_serialize::Compress;
type S = BandersnatchSha512Ell2;
let secrets: Vec<_> = (0..3)
.map(|i| BandersnatchVrfVerifiable::new_secret([i; 32]))
.collect();
let member_keys: Vec<_> = secrets
.iter()
.map(BandersnatchVrfVerifiable::member_from_secret)
.collect();
let commitment = BandersnatchVrfVerifiable::open(
RingDomainSize::Domain11,
&member_keys[0],
member_keys.iter().cloned(),
)
.unwrap();
let (proof, _) =
BandersnatchVrfVerifiable::create(commitment.clone(), &secrets[0], b"ctx", b"msg")
.unwrap();
assert_eq!(proof.len(), ring_signature_size::<S>(1));
let signature =
crate::ring::RingVrfSignature::<S>::deserialize_compressed(proof.as_slice()).unwrap();
assert_eq!(signature.serialized_size(Compress::Yes), proof.len());
let contexts: Vec<&[u8]> = vec![b"a", b"b", b"c"];
let (proof_multi, _) = BandersnatchVrfVerifiable::create_multi_context(
commitment,
&secrets[0],
&contexts,
b"msg",
)
.unwrap();
assert_eq!(proof_multi.len(), ring_signature_size::<S>(3));
}
#[test]
fn ring_proof_blinding_regression() {
let domain_size = RingDomainSize::Domain11;
let secret = BandersnatchVrfVerifiable::new_secret([42; 32]);
let member = BandersnatchVrfVerifiable::member_from_secret(&secret);
let prove = || {
let commitment =
BandersnatchVrfVerifiable::open(domain_size, &member, [member].into_iter())
.unwrap();
BandersnatchVrfVerifiable::create(commitment, &secret, b"ctx", b"msg")
.unwrap()
.0
};
let (first, second) = (prove(), prove());
assert_ne!(first, second);
}
}
#[cfg(test)]
mod builder_tests {
use crate::{GenerateVerifiable, ring::ring_verifier_builder_params};
use super::*;
use ark_scale::MaxEncodedLen;
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_vrf::{ring::SrsLookup, suites::bandersnatch::BandersnatchSha512Ell2};
use parity_scale_codec::{Decode, Encode};
use tests::{
MembersCommitment, MembersSet, bandersnatch_ring_setup, start_members_from_params,
};
macro_rules! test_for_all_domains {
($test_name:ident, |$domain_size:ident| $body:block) => {
paste::paste! {
#[test]
fn [<$test_name _domain11>]() {
let $domain_size = RingDomainSize::Domain11;
$body
}
#[test]
fn [<$test_name _domain12>]() {
let $domain_size = RingDomainSize::Domain12;
$body
}
#[test]
fn [<$test_name _domain16>]() {
let $domain_size = RingDomainSize::Domain16;
$body
}
}
};
}
#[test]
#[ignore = "srs generator"]
fn generate_srs_from_full_zcash_srs() {
use std::fs::File;
use std::io::{Read, Write};
const FULL_ZCASH_SRS_FILE: &str = concat!(
env!("CARGO_MANIFEST_DIR"),
"/src/ring/data/bls12-381/zcash-srs-2-16-uncompressed.bin"
);
const SRS_COMPRESSED_FILE: &str = concat!(
env!("CARGO_MANIFEST_DIR"),
"/src/ring/data/bls12-381/srs-compressed.bin"
);
const SRS_UNCOMPRESSED_FILE: &str = concat!(
env!("CARGO_MANIFEST_DIR"),
"/src/ring/data/bls12-381/srs-uncompressed.bin"
);
let mut buf = vec![];
let mut file = File::open(FULL_ZCASH_SRS_FILE).unwrap();
file.read_to_end(&mut buf).unwrap();
println!("Full size: {}", buf.len());
let full_params = bandersnatch_ring_setup(RingDomainSize::Domain16);
let mut buf = vec![];
full_params.serialize_compressed(&mut buf).unwrap();
println!("Reduced size (compressed): {}", buf.len());
let mut file = File::create(SRS_COMPRESSED_FILE).unwrap();
file.write_all(&buf).unwrap();
let mut buf = vec![];
full_params.serialize_uncompressed(&mut buf).unwrap();
println!("Reduced size (uncompressed): {}", buf.len());
let mut file = File::create(SRS_UNCOMPRESSED_FILE).unwrap();
file.write_all(&buf).unwrap();
}
#[test]
#[ignore = "ring builder generator - generates ring data for all domain sizes"]
fn generate_empty_ring_builders() {
use std::io::Write;
for domain_size in RingDomainSize::VARIANTS {
let (builder, builder_params) = start_members_from_params(domain_size);
let builder_file = format!(
"{}/src/ring/data/bls12-381/ring-builder-domain{}.bin",
env!("CARGO_MANIFEST_DIR"),
domain_size.as_power()
);
let params_file = format!(
"{}/src/ring/data/bls12-381/ring-builder-params-domain{}.bin",
env!("CARGO_MANIFEST_DIR"),
domain_size.as_power()
);
let mut buf = Vec::with_capacity(builder.uncompressed_size());
builder.serialize_uncompressed(&mut buf).unwrap();
println!("Writing empty ring builder to: {}", builder_file);
let mut file = std::fs::File::create(&builder_file).unwrap();
file.write_all(&buf).unwrap();
let mut buf = Vec::with_capacity(builder_params.0.uncompressed_size());
builder_params.0.serialize_uncompressed(&mut buf).unwrap();
println!("G1 len: {}", builder_params.0.len());
println!("Writing ring builder params to: {}", params_file);
let mut file = std::fs::File::create(¶ms_file).unwrap();
file.write_all(&buf).unwrap();
}
}
test_for_all_domains!(check_pre_constructed_ring_builder, |domain_size| {
let builder = BandersnatchVrfVerifiable::start_members(domain_size);
let builder_params = ring_verifier_builder_params::<BandersnatchSha512Ell2>(domain_size);
let (builder2, builder_params2) = start_members_from_params(domain_size);
let mut buf1 = vec![];
builder_params.0.serialize_uncompressed(&mut buf1).unwrap();
let mut buf2 = vec![];
builder_params2.0.serialize_uncompressed(&mut buf2).unwrap();
assert_eq!(buf1, buf2);
let mut buf1 = vec![];
builder.serialize_uncompressed(&mut buf1).unwrap();
let mut buf2 = vec![];
builder2.serialize_uncompressed(&mut buf2).unwrap();
assert_eq!(buf1, buf2);
});
test_for_all_domains!(check_precomputed_size, |domain_size| {
let secret = BandersnatchVrfVerifiable::new_secret([0u8; 32]);
let public = BandersnatchVrfVerifiable::member_from_secret(&secret);
let internal = crate::ring::PublicKey::<BandersnatchSha512Ell2>::deserialize_compressed(
public.as_ref(),
)
.unwrap();
assert_eq!(
internal.compressed_size(),
<BandersnatchSha512Ell2 as RingSuiteExt>::PUBLIC_KEY_SIZE
);
let members = BandersnatchVrfVerifiable::start_members(domain_size);
assert_eq!(members.uncompressed_size(), MembersSet::max_encoded_len());
let commitment = BandersnatchVrfVerifiable::finish_members(members);
assert_eq!(
commitment.uncompressed_size(),
MembersCommitment::max_encoded_len()
);
});
test_for_all_domains!(start_push_finish, |domain_size| {
let alice_sec = BandersnatchVrfVerifiable::new_secret([0u8; 32]);
let bob_sec = BandersnatchVrfVerifiable::new_secret([1u8; 32]);
let charlie_sec = BandersnatchVrfVerifiable::new_secret([2u8; 32]);
let alice = BandersnatchVrfVerifiable::member_from_secret(&alice_sec);
let bob = BandersnatchVrfVerifiable::member_from_secret(&bob_sec);
let charlie = BandersnatchVrfVerifiable::member_from_secret(&charlie_sec);
let mut inter1 = BandersnatchVrfVerifiable::start_members(domain_size);
let mut inter2 = inter1.clone();
let builder_params = ring_verifier_builder_params::<BandersnatchSha512Ell2>(domain_size);
let get_many = chunk_lookup(&builder_params);
BandersnatchVrfVerifiable::push_members(
&mut inter1,
[alice, bob, charlie].into_iter(),
get_many,
)
.unwrap();
BandersnatchVrfVerifiable::push_members(&mut inter2, [alice].into_iter(), get_many)
.unwrap();
BandersnatchVrfVerifiable::push_members(&mut inter2, [bob].into_iter(), get_many).unwrap();
BandersnatchVrfVerifiable::push_members(&mut inter2, [charlie].into_iter(), get_many)
.unwrap();
assert_eq!(inter1, inter2);
let members1 = BandersnatchVrfVerifiable::finish_members(inter1);
let members2 = BandersnatchVrfVerifiable::finish_members(inter2);
assert_eq!(members1, members2);
});
test_for_all_domains!(start_push_finish_multiple_members, |domain_size| {
let alice_sec = BandersnatchVrfVerifiable::new_secret([0u8; 32]);
let bob_sec = BandersnatchVrfVerifiable::new_secret([1u8; 32]);
let charlie_sec = BandersnatchVrfVerifiable::new_secret([2u8; 32]);
let alice = BandersnatchVrfVerifiable::member_from_secret(&alice_sec);
let bob = BandersnatchVrfVerifiable::member_from_secret(&bob_sec);
let charlie = BandersnatchVrfVerifiable::member_from_secret(&charlie_sec);
let mut inter1 = BandersnatchVrfVerifiable::start_members(domain_size);
let (mut inter2, builder_params) = start_members_from_params(domain_size);
let get_many = chunk_lookup(&builder_params);
let mut inter3 = BandersnatchVrfVerifiable::start_members(domain_size);
let mut inter4 = BandersnatchVrfVerifiable::start_members(domain_size);
BandersnatchVrfVerifiable::push_members(
&mut inter1,
[alice, bob, charlie].into_iter(),
get_many,
)
.unwrap();
BandersnatchVrfVerifiable::push_members(
&mut inter2,
[alice, bob, charlie].into_iter(),
get_many,
)
.unwrap();
BandersnatchVrfVerifiable::push_members(&mut inter3, [alice].into_iter(), get_many)
.unwrap();
BandersnatchVrfVerifiable::push_members(&mut inter3, [bob].into_iter(), get_many).unwrap();
BandersnatchVrfVerifiable::push_members(&mut inter3, [charlie].into_iter(), get_many)
.unwrap();
BandersnatchVrfVerifiable::push_members(&mut inter4, [alice].into_iter(), get_many)
.unwrap();
BandersnatchVrfVerifiable::push_members(&mut inter4, [bob, charlie].into_iter(), get_many)
.unwrap();
assert_eq!(inter1, inter2);
assert_eq!(inter2, inter3);
assert_eq!(inter3, inter4);
let members1 = BandersnatchVrfVerifiable::finish_members(inter1);
let members2 = BandersnatchVrfVerifiable::finish_members(inter2);
let members3 = BandersnatchVrfVerifiable::finish_members(inter3);
let members4 = BandersnatchVrfVerifiable::finish_members(inter4);
assert_eq!(members1, members2);
assert_eq!(members2, members3);
assert_eq!(members3, members4);
});
test_for_all_domains!(open_validate_works, |domain_size| {
use std::time::Instant;
let context = b"Context";
let message = b"FooBar";
let start = Instant::now();
let _ = bandersnatch_ring_setup(domain_size);
println!(
"* PCS params decode: {} ms",
(Instant::now() - start).as_millis()
);
let members: Vec<_> = (0..10)
.map(|i| {
let secret = BandersnatchVrfVerifiable::new_secret([i as u8; 32]);
BandersnatchVrfVerifiable::member_from_secret(&secret)
})
.collect();
let member = members[3];
let start = Instant::now();
let commitment =
BandersnatchVrfVerifiable::open(domain_size, &member, members.clone().into_iter())
.unwrap();
println!("* Open: {} ms", (Instant::now() - start).as_millis());
println!(" Commitment size: {} bytes", commitment.encode().len());
let secret = BandersnatchVrfVerifiable::new_secret([commitment.prover_idx as u8; 32]);
let start = Instant::now();
let (proof, alias) =
BandersnatchVrfVerifiable::create(commitment, &secret, context, message).unwrap();
println!("* Create: {} ms", (Instant::now() - start).as_millis());
println!(" Proof size: {} bytes", proof.encode().len());
let (_, builder_params) = start_members_from_params(domain_size);
let get_many = chunk_lookup(&builder_params);
let start = Instant::now();
let mut inter = BandersnatchVrfVerifiable::start_members(domain_size);
println!(
"* Start members: {} ms",
(Instant::now() - start).as_millis()
);
let start = Instant::now();
members.iter().for_each(|member| {
BandersnatchVrfVerifiable::push_members(&mut inter, [*member].into_iter(), get_many)
.unwrap();
});
println!(
"* Push {} members: {} ms",
members.len(),
(Instant::now() - start).as_millis()
);
let start = Instant::now();
let members = BandersnatchVrfVerifiable::finish_members(inter);
println!(
"* Finish members: {} ms",
(Instant::now() - start).as_millis()
);
let start = Instant::now();
let alias2 =
BandersnatchVrfVerifiable::validate(domain_size, &proof, &members, context, message)
.unwrap();
println!("* Validate {} ms", (Instant::now() - start).as_millis());
assert_eq!(alias, alias2);
let start = Instant::now();
let alias3 = BandersnatchVrfVerifiable::alias_in_context(&secret, context).unwrap();
println!("* Alias: {} ms", (Instant::now() - start).as_millis());
assert_eq!(alias, alias3);
});
test_for_all_domains!(batch_validate_multiple_proofs, |domain_size| {
use crate::BatchProofItem;
use std::time::Instant;
let context = b"Context";
let num_members = 10;
let num_proofs = 5;
let _ = bandersnatch_ring_setup(domain_size);
let secrets: Vec<_> = (0..num_members)
.map(|i| BandersnatchVrfVerifiable::new_secret([i as u8; 32]))
.collect();
let member_keys: Vec<_> = secrets
.iter()
.map(BandersnatchVrfVerifiable::member_from_secret)
.collect();
let mut proofs = Vec::new();
let mut expected_aliases = Vec::new();
for i in 0..num_proofs {
let member = member_keys[i];
let message = format!("Message from member {}", i);
let commitment = BandersnatchVrfVerifiable::open(
domain_size,
&member,
member_keys.clone().into_iter(),
)
.unwrap();
let (proof, alias) = BandersnatchVrfVerifiable::create(
commitment,
&secrets[i],
context,
message.as_bytes(),
)
.unwrap();
proofs.push((proof, message, alias));
expected_aliases.push(alias);
}
let (_, builder_params) = start_members_from_params(domain_size);
let get_many = chunk_lookup(&builder_params);
let mut inter = BandersnatchVrfVerifiable::start_members(domain_size);
BandersnatchVrfVerifiable::push_members(&mut inter, member_keys.iter().copied(), get_many)
.unwrap();
let members = BandersnatchVrfVerifiable::finish_members(inter);
let start = Instant::now();
for (proof, message, expected_alias) in &proofs {
let alias_out = BandersnatchVrfVerifiable::validate(
domain_size,
proof,
&members,
context,
message.as_bytes(),
)
.unwrap();
assert_eq!(&alias_out, expected_alias);
}
let individual_ms = (Instant::now() - start).as_millis();
println!(
"* Individual validate {} proofs: {} ms",
num_proofs, individual_ms
);
let batch_items: Vec<_> = proofs
.iter()
.map(|(proof, message, _)| BatchProofItem {
proof: proof.clone(),
config: domain_size,
members: members.clone(),
context: context.to_vec(),
message: message.as_bytes().to_vec(),
})
.collect();
let start = Instant::now();
let aliases = BandersnatchVrfVerifiable::batch_validate(&batch_items).unwrap();
let batch_ms = (Instant::now() - start).as_millis();
println!("* Batch validate {} proofs: {} ms", num_proofs, batch_ms);
assert_eq!(aliases, expected_aliases);
let results = BandersnatchVrfVerifiable::batch_validate_per_item(&batch_items);
assert_eq!(results, aliases.into_iter().map(Ok).collect::<Vec<_>>());
assert_eq!(BandersnatchVrfVerifiable::batch_validate(&[]), Ok(vec![]));
assert!(BandersnatchVrfVerifiable::batch_validate_per_item(&[]).is_empty());
println!(
"* Speedup: {:.2}x",
individual_ms as f64 / batch_ms.max(1) as f64
);
});
test_for_all_domains!(batch_validate_invalid_items, |domain_size| {
use crate::BatchProofItem;
let context = b"Context";
let num_members = 5;
let _ = bandersnatch_ring_setup(domain_size);
let secrets: Vec<_> = (0..num_members)
.map(|i| BandersnatchVrfVerifiable::new_secret([i as u8; 32]))
.collect();
let member_keys: Vec<_> = secrets
.iter()
.map(BandersnatchVrfVerifiable::member_from_secret)
.collect();
let (_, builder_params) = start_members_from_params(domain_size);
let get_many = chunk_lookup(&builder_params);
let mut inter = BandersnatchVrfVerifiable::start_members(domain_size);
BandersnatchVrfVerifiable::push_members(&mut inter, member_keys.iter().copied(), get_many)
.unwrap();
let members = BandersnatchVrfVerifiable::finish_members(inter);
let mut batch_items = Vec::new();
let mut expected = Vec::new();
for i in 0..3 {
let member = member_keys[i];
let message = format!("Message from member {}", i);
let commitment = BandersnatchVrfVerifiable::open(
domain_size,
&member,
member_keys.clone().into_iter(),
)
.unwrap();
let (proof, alias) = BandersnatchVrfVerifiable::create(
commitment,
&secrets[i],
context,
message.as_bytes(),
)
.unwrap();
expected.push(alias);
batch_items.push(BatchProofItem {
proof,
config: domain_size,
members: members.clone(),
context: context.to_vec(),
message: message.into_bytes(),
});
}
let all_valid: Vec<_> = expected.iter().copied().map(Ok).collect();
assert_eq!(
BandersnatchVrfVerifiable::batch_validate(&batch_items),
Ok(expected.clone())
);
let mut corrupted_items = batch_items.clone();
corrupted_items[1].proof[10] ^= 0xFF;
assert!(BandersnatchVrfVerifiable::batch_validate(&corrupted_items).is_err());
let results = BandersnatchVrfVerifiable::batch_validate_per_item(&corrupted_items);
assert!(results[1].is_err());
assert_eq!(results[0], all_valid[0]);
assert_eq!(results[2], all_valid[2]);
let mut wrong_message_items = batch_items.clone();
wrong_message_items[2].message = b"tampered message".to_vec();
assert_eq!(
BandersnatchVrfVerifiable::batch_validate(&wrong_message_items),
Err(crate::Error::VerificationFailed)
);
let results = BandersnatchVrfVerifiable::batch_validate_per_item(&wrong_message_items);
assert_eq!(
results,
vec![
all_valid[0],
all_valid[1],
Err(crate::Error::VerificationFailed)
]
);
let mut two_bad_items = batch_items.clone();
two_bad_items[0].message = b"tampered message".to_vec();
two_bad_items[2].message = b"tampered message".to_vec();
assert!(BandersnatchVrfVerifiable::batch_validate(&two_bad_items).is_err());
let results = BandersnatchVrfVerifiable::batch_validate_per_item(&two_bad_items);
assert_eq!(
results,
vec![
Err(crate::Error::VerificationFailed),
all_valid[1],
Err(crate::Error::VerificationFailed)
]
);
let outsider_secret = BandersnatchVrfVerifiable::new_secret([0xFFu8; 32]);
let outsider_key = BandersnatchVrfVerifiable::member_from_secret(&outsider_secret);
let mut extended_keys = member_keys.clone();
extended_keys.push(outsider_key);
let outsider_commitment =
BandersnatchVrfVerifiable::open(domain_size, &outsider_key, extended_keys.into_iter())
.unwrap();
let (outsider_proof, _) = BandersnatchVrfVerifiable::create(
outsider_commitment,
&outsider_secret,
context,
b"outsider message",
)
.unwrap();
let mut outsider_items = batch_items.clone();
outsider_items.push(BatchProofItem {
proof: outsider_proof,
config: domain_size,
members: members.clone(),
context: context.to_vec(),
message: b"outsider message".to_vec(),
});
assert!(BandersnatchVrfVerifiable::batch_validate(&outsider_items).is_err());
let results = BandersnatchVrfVerifiable::batch_validate_per_item(&outsider_items);
assert_eq!(results[..3], all_valid);
assert_eq!(results[3], Err(crate::Error::VerificationFailed));
let wrong_context = b"WrongContext";
let member = member_keys[0];
let wrong_ctx_commitment =
BandersnatchVrfVerifiable::open(domain_size, &member, member_keys.clone().into_iter())
.unwrap();
let (wrong_ctx_proof, _) = BandersnatchVrfVerifiable::create(
wrong_ctx_commitment,
&secrets[0],
wrong_context,
b"some message",
)
.unwrap();
let mut wrong_ctx_items = batch_items.clone();
wrong_ctx_items.push(BatchProofItem {
proof: wrong_ctx_proof,
config: domain_size,
members: members.clone(),
context: context.to_vec(),
message: b"some message".to_vec(),
});
assert!(BandersnatchVrfVerifiable::batch_validate(&wrong_ctx_items).is_err());
let results = BandersnatchVrfVerifiable::batch_validate_per_item(&wrong_ctx_items);
assert_eq!(results[..3], all_valid);
assert_eq!(results[3], Err(crate::Error::VerificationFailed));
});
test_for_all_domains!(batch_validate_multiple_rings, |domain_size| {
use crate::BatchProofItem;
let context = b"Context";
let _ = bandersnatch_ring_setup(domain_size);
let make_ring = |seed_base: u8| {
let secrets: Vec<_> = (0..4)
.map(|i| BandersnatchVrfVerifiable::new_secret([seed_base + i as u8; 32]))
.collect();
let keys: Vec<_> = secrets
.iter()
.map(BandersnatchVrfVerifiable::member_from_secret)
.collect();
let members = build_members(keys.iter().copied(), domain_size);
(secrets, keys, members)
};
let (secrets_a, keys_a, members_a) = make_ring(0);
let (secrets_b, keys_b, members_b) = make_ring(100);
assert_ne!(members_a.encode(), members_b.encode());
let commitment_a =
BandersnatchVrfVerifiable::open(domain_size, &keys_a[1], keys_a.iter().copied())
.unwrap();
let (proof_a, alias_a) =
BandersnatchVrfVerifiable::create(commitment_a, &secrets_a[1], context, b"from ring A")
.unwrap();
let commitment_b =
BandersnatchVrfVerifiable::open(domain_size, &keys_b[2], keys_b.iter().copied())
.unwrap();
let (proof_b, alias_b) =
BandersnatchVrfVerifiable::create(commitment_b, &secrets_b[2], context, b"from ring B")
.unwrap();
let batch = vec![
BatchProofItem {
proof: proof_a,
config: domain_size,
members: members_a.clone(),
context: context.to_vec(),
message: b"from ring A".to_vec(),
},
BatchProofItem {
proof: proof_b,
config: domain_size,
members: members_b.clone(),
context: context.to_vec(),
message: b"from ring B".to_vec(),
},
];
let aliases = BandersnatchVrfVerifiable::batch_validate(&batch).unwrap();
assert_eq!(aliases, vec![alias_a, alias_b]);
let mut swapped = batch.clone();
swapped[0].members = members_b;
swapped[1].members = members_a;
assert!(BandersnatchVrfVerifiable::batch_validate(&swapped).is_err());
assert_eq!(
BandersnatchVrfVerifiable::batch_validate_per_item(&swapped),
vec![
Err(crate::Error::VerificationFailed),
Err(crate::Error::VerificationFailed)
]
);
});
#[test]
fn batch_validate_mixed_domains() {
use crate::BatchProofItem;
let context = b"Context";
let mut batch = Vec::new();
let mut expected = Vec::new();
for domain_size in RingDomainSize::VARIANTS.iter().copied() {
let _ = bandersnatch_ring_setup(domain_size);
let secrets: Vec<_> = (0..4)
.map(|i| BandersnatchVrfVerifiable::new_secret([i as u8; 32]))
.collect();
let keys: Vec<_> = secrets
.iter()
.map(BandersnatchVrfVerifiable::member_from_secret)
.collect();
let members = build_members(keys.iter().copied(), domain_size);
let commitment =
BandersnatchVrfVerifiable::open(domain_size, &keys[1], keys.iter().copied())
.unwrap();
let msg = format!("proof at {:?}", domain_size);
let (proof, alias) =
BandersnatchVrfVerifiable::create(commitment, &secrets[1], context, msg.as_bytes())
.unwrap();
expected.push(alias);
batch.push(BatchProofItem {
proof,
config: domain_size,
members,
context: context.to_vec(),
message: msg.into_bytes(),
});
}
assert_eq!(batch.len(), 3);
assert_eq!(
BandersnatchVrfVerifiable::batch_validate(&batch),
Ok(expected.clone())
);
let mut wrong = batch.clone();
wrong[0].config = wrong[1].config;
assert!(BandersnatchVrfVerifiable::batch_validate(&wrong).is_err());
let all_valid: Vec<_> = expected.iter().copied().map(Ok).collect();
let results = BandersnatchVrfVerifiable::batch_validate_per_item(&wrong);
assert!(results[0].is_err());
assert_eq!(results[1..], all_valid[1..]);
}
#[test]
fn batch_validate_per_item_reports_errors() {
use crate::BatchProofItem;
use bounded_collections::BoundedVec;
let domain_size = RingDomainSize::Domain11;
let context = b"Context";
let message = b"msg";
let _ = bandersnatch_ring_setup(domain_size);
let secrets: Vec<_> = (0..3)
.map(|i| BandersnatchVrfVerifiable::new_secret([i as u8; 32]))
.collect();
let member_keys: Vec<_> = secrets
.iter()
.map(BandersnatchVrfVerifiable::member_from_secret)
.collect();
let members = build_members(member_keys.iter().copied(), domain_size);
let commitment = BandersnatchVrfVerifiable::open(
domain_size,
&member_keys[0],
member_keys.iter().copied(),
)
.unwrap();
let (valid_proof, alias) =
BandersnatchVrfVerifiable::create(commitment.clone(), &secrets[0], context, message)
.unwrap();
let (multi_ctx_proof, _) = BandersnatchVrfVerifiable::create_multi_context(
commitment,
&secrets[0],
&[context.as_slice(), b"other context".as_slice()],
message,
)
.unwrap();
let garbage_proof = BoundedVec::try_from(vec![0xAA; valid_proof.len()]).unwrap();
let make_item = |proof| BatchProofItem {
proof,
config: domain_size,
members: members.clone(),
context: context.to_vec(),
message: message.to_vec(),
};
let batch = vec![
make_item(garbage_proof),
make_item(valid_proof),
make_item(multi_ctx_proof),
];
assert_eq!(
BandersnatchVrfVerifiable::batch_validate(&batch),
Err(crate::Error::DecodeError),
);
assert_eq!(
BandersnatchVrfVerifiable::batch_validate(&batch[1..]),
Err(crate::Error::Unsupported),
);
assert_eq!(
BandersnatchVrfVerifiable::batch_validate_per_item(&batch),
vec![
Err(crate::Error::DecodeError),
Ok(alias),
Err(crate::Error::Unsupported),
],
);
}
test_for_all_domains!(open_validate_single_vs_multiple_keys, |domain_size| {
use std::time::Instant;
let start = Instant::now();
let _ = bandersnatch_ring_setup(domain_size);
println!("* KZG decode: {} ms", (Instant::now() - start).as_millis());
let max_members = domain_size.max_ring_size::<BandersnatchSha512Ell2>();
println!(
"* Testing with {} members (max for {:?})",
max_members, domain_size
);
let members: Vec<_> = (0..max_members)
.map(|i| {
let mut seed = [0u8; 32];
seed[..8].copy_from_slice(&(i as u64).to_le_bytes());
let secret = BandersnatchVrfVerifiable::new_secret(seed);
BandersnatchVrfVerifiable::member_from_secret(&secret)
})
.collect();
let (_, builder_params) = start_members_from_params(domain_size);
let get_many = chunk_lookup(&builder_params);
let mut inter1 = BandersnatchVrfVerifiable::start_members(domain_size);
let start = Instant::now();
members.iter().for_each(|member| {
BandersnatchVrfVerifiable::push_members(&mut inter1, [*member].into_iter(), get_many)
.unwrap();
});
println!(
"* Push {} members one at a time: {} ms",
members.len(),
(Instant::now() - start).as_millis()
);
let mut inter2 = BandersnatchVrfVerifiable::start_members(domain_size);
let start = Instant::now();
BandersnatchVrfVerifiable::push_members(&mut inter2, members.iter().copied(), get_many)
.unwrap();
println!(
"* Push {} members simultaneously: {} ms",
members.len(),
(Instant::now() - start).as_millis()
);
assert_eq!(inter1, inter2);
});
#[test]
fn open_with_oversized_ring_reports_set_full() {
let domain_size = RingDomainSize::Domain11;
let over_capacity = domain_size.max_ring_size::<BandersnatchSha512Ell2>() + 1;
let members: Vec<_> = (0..over_capacity)
.map(|i| {
let mut seed = [0u8; 32];
seed[..8].copy_from_slice(&(i as u64).to_le_bytes());
let secret = BandersnatchVrfVerifiable::new_secret(seed);
BandersnatchVrfVerifiable::member_from_secret(&secret)
})
.collect();
assert!(matches!(
BandersnatchVrfVerifiable::open(domain_size, &members[0], members.iter().copied()),
Err(crate::Error::SetFull)
));
}
test_for_all_domains!(empty_context_works, |domain_size| {
let _ = bandersnatch_ring_setup(domain_size);
let secrets: Vec<_> = (0..3)
.map(|i| BandersnatchVrfVerifiable::new_secret([i as u8; 32]))
.collect();
let member_keys: Vec<_> = secrets
.iter()
.map(BandersnatchVrfVerifiable::member_from_secret)
.collect();
let commitment = BandersnatchVrfVerifiable::open(
domain_size,
&member_keys[0],
member_keys.iter().cloned(),
)
.unwrap();
let members = build_members(member_keys.iter().copied(), domain_size);
let contexts: [&[u8]; 0] = [];
let message = b"Message";
let (proof, aliases) = BandersnatchVrfVerifiable::create_multi_context(
commitment,
&secrets[0],
&contexts,
message,
)
.unwrap();
assert!(aliases.is_empty());
assert!(BandersnatchVrfVerifiable::is_valid_multi_context(
domain_size,
&proof,
&members,
&contexts,
&aliases,
message,
));
});
test_for_all_domains!(multi_context_works, |domain_size| {
let _ = bandersnatch_ring_setup(domain_size);
let secrets: Vec<_> = (0..10)
.map(|i| BandersnatchVrfVerifiable::new_secret([i as u8; 32]))
.collect();
let member_keys: Vec<_> = secrets
.iter()
.map(BandersnatchVrfVerifiable::member_from_secret)
.collect();
let member_secret = secrets[5].clone();
let member = member_keys[5];
let commitment =
BandersnatchVrfVerifiable::open(domain_size, &member, member_keys.iter().cloned())
.unwrap();
let members = build_members(member_keys.iter().copied(), domain_size);
let contexts = [
b"Context A".as_ref(),
b"Context B".as_ref(),
b"Context C".as_ref(),
];
let message = b"Message";
let (proof, aliases) = BandersnatchVrfVerifiable::create_multi_context(
commitment.clone(),
&member_secret,
&contexts,
message,
)
.unwrap();
assert!(BandersnatchVrfVerifiable::is_valid_multi_context(
domain_size,
&proof,
&members,
&contexts,
&aliases,
message,
));
for (ctx, mutli_ctx_alias) in contexts.iter().zip(aliases.iter()) {
let (_, alias) =
BandersnatchVrfVerifiable::create(commitment.clone(), &member_secret, ctx, message)
.unwrap();
assert_eq!(&alias, mutli_ctx_alias);
}
});
#[test]
fn decode_bogus_commitment_fails() {
let mut bad_bytes = vec![0u8; BandersnatchSha512Ell2::MEMBERS_COMMITMENT_SIZE];
bad_bytes[0] = 1;
assert!(MembersCommitment::decode(&mut &bad_bytes[..]).is_err());
let zero_bytes = vec![0u8; BandersnatchSha512Ell2::MEMBERS_COMMITMENT_SIZE];
let identity_members = MembersCommitment::decode(&mut &zero_bytes[..]).unwrap();
let domain_size = RingDomainSize::Domain11;
let secret = BandersnatchVrfVerifiable::new_secret([0; 32]);
let member = BandersnatchVrfVerifiable::member_from_secret(&secret);
let commitment =
BandersnatchVrfVerifiable::open(domain_size, &member, [member].into_iter()).unwrap();
let (proof, _) =
BandersnatchVrfVerifiable::create(commitment, &secret, b"ctx", b"msg").unwrap();
assert_eq!(
BandersnatchVrfVerifiable::validate(
domain_size,
&proof,
&identity_members,
b"ctx",
b"msg"
),
Err(crate::Error::VerificationFailed),
);
}
#[test]
fn decode_unchecked_reads_same_bytes() {
use crate::ring::DecodeUnchecked;
let domain_size = RingDomainSize::Domain11;
let _ = bandersnatch_ring_setup(domain_size);
let members_set = BandersnatchVrfVerifiable::start_members(domain_size);
let commitment = BandersnatchVrfVerifiable::finish_members(members_set);
let bytes = commitment.encode();
let decoded = MembersCommitment::decode_unchecked(&mut &bytes[..]).expect("decode ok");
assert_eq!(decoded.encode(), bytes);
}
#[test]
fn decode_unchecked_skips_validation() {
use crate::ring::DecodeUnchecked;
let mut bad_bytes = vec![0u8; BandersnatchSha512Ell2::MEMBERS_COMMITMENT_SIZE];
bad_bytes[0] = 1;
assert!(MembersCommitment::decode(&mut &bad_bytes[..]).is_err());
assert!(MembersCommitment::decode_unchecked(&mut &bad_bytes[..]).is_ok());
}
#[test]
fn validate_rejects_trailing_bytes() {
use crate::BatchProofItem;
use bounded_collections::BoundedVec;
let domain_size = RingDomainSize::Domain11;
let _ = bandersnatch_ring_setup(domain_size);
let secrets: Vec<_> = (0..3)
.map(|i| BandersnatchVrfVerifiable::new_secret([i as u8; 32]))
.collect();
let member_keys: Vec<_> = secrets
.iter()
.map(BandersnatchVrfVerifiable::member_from_secret)
.collect();
let members = build_members(member_keys.iter().copied(), domain_size);
let commitment = BandersnatchVrfVerifiable::open(
domain_size,
&member_keys[0],
member_keys.iter().cloned(),
)
.unwrap();
let context = b"ctx";
let message = b"msg";
let (proof, alias) =
BandersnatchVrfVerifiable::create(commitment, &secrets[0], context, message).unwrap();
let alias_out =
BandersnatchVrfVerifiable::validate(domain_size, &proof, &members, context, message)
.unwrap();
assert_eq!(alias_out, alias);
let mut bytes = proof.into_inner();
bytes.extend_from_slice(&[0u8; 16]);
let proof_malleated: <BandersnatchVrfVerifiable as GenerateVerifiable>::Proof =
BoundedVec::try_from(bytes).unwrap();
assert!(
BandersnatchVrfVerifiable::validate(
domain_size,
&proof_malleated,
&members,
context,
message,
)
.is_err()
);
let batch_items = vec![BatchProofItem {
proof: proof_malleated,
config: domain_size,
members: members.clone(),
context: context.to_vec(),
message: message.to_vec(),
}];
assert_eq!(
BandersnatchVrfVerifiable::batch_validate(&batch_items),
Err(crate::Error::DecodeError),
);
}
#[test]
fn push_members_rejects_identity() {
let domain_size = RingDomainSize::Domain11;
let _ = bandersnatch_ring_setup(domain_size);
let mut identity = [0u8; 32];
<BandersnatchSha512Ell2 as ark_vrf::Suite>::Affine::zero()
.serialize_compressed(&mut identity[..])
.unwrap();
assert_eq!(identity[0], 0x01);
assert!(identity[1..].iter().all(|b| *b == 0));
assert!(!BandersnatchVrfVerifiable::is_member_valid(&identity));
let (_, builder_params) = start_members_from_params(domain_size);
let get_many = chunk_lookup(&builder_params);
let mut inter = BandersnatchVrfVerifiable::start_members(domain_size);
let res =
BandersnatchVrfVerifiable::push_members(&mut inter, [identity].into_iter(), get_many);
assert!(matches!(res, Err(crate::Error::InvalidMember)));
}
#[test]
fn validate_rejects_foreign_srs_commitment() {
use ark_vrf::ring::{Prover, RingSetup};
type S = BandersnatchSha512Ell2;
let domain_size = RingDomainSize::Domain11;
let context = b"ctx";
let message = b"msg";
let prover_idx = 0usize;
let _ = bandersnatch_ring_setup(domain_size);
let secrets: Vec<_> = (0..3)
.map(|i| BandersnatchVrfVerifiable::new_secret([i as u8; 32]))
.collect();
let member_keys: Vec<_> = secrets
.iter()
.map(BandersnatchVrfVerifiable::member_from_secret)
.collect();
let canonical_members = build_members(member_keys.iter().copied(), domain_size);
let commitment = BandersnatchVrfVerifiable::open(
domain_size,
&member_keys[prover_idx],
member_keys.iter().cloned(),
)
.unwrap();
let (canonical_proof, _) =
BandersnatchVrfVerifiable::create(commitment, &secrets[prover_idx], context, message)
.unwrap();
assert!(
BandersnatchVrfVerifiable::validate(
domain_size,
&canonical_proof,
&canonical_members,
context,
message,
)
.is_ok()
);
let ring_size = domain_size.max_ring_size::<S>();
let attacker_setup = RingSetup::<S>::from_seed(ring_size, [0xAB; 32]);
let pks: Vec<_> = member_keys
.iter()
.map(|m| crate::ring::decode_member::<S>(m.as_ref()).unwrap().0)
.collect();
let attacker_members =
crate::ring::MembersCommitment(attacker_setup.verifier_key(&pks).unwrap().commitment());
assert_ne!(canonical_members.encode(), attacker_members.encode());
let prover_key = attacker_setup.prover_key(&pks).unwrap();
let ring_prover = ark_vrf::ring::RingContext::<S>::new_without_blinding(ring_size)
.into_ring_prover(prover_key, prover_idx);
let input_msg = [<S as RingSuiteExt>::VRF_INPUT_DOMAIN, context].concat();
let input = ark_vrf::Input::<S>::new(&input_msg).unwrap();
let output = secrets[prover_idx].output(input);
let io = ark_vrf::VrfIo { input, output };
let ring_proof = secrets[prover_idx].prove([io], message, &ring_prover);
let mut outputs = crate::ContextVec::new();
outputs.push(output);
let signature = crate::ring::RingVrfSignature::<S> {
outputs: crate::ring::RingVrfOutputs(outputs),
proof: ring_proof,
};
let mut buf = Vec::new();
signature.serialize_compressed(&mut buf).unwrap();
let attacker_proof: <BandersnatchVrfVerifiable as GenerateVerifiable>::Proof =
bounded_collections::BoundedVec::try_from(buf).unwrap();
assert_eq!(
BandersnatchVrfVerifiable::validate(
domain_size,
&attacker_proof,
&attacker_members,
context,
message,
),
Err(crate::Error::VerificationFailed),
);
let batch = vec![crate::BatchProofItem {
proof: attacker_proof,
config: domain_size,
members: attacker_members,
context: context.to_vec(),
message: message.to_vec(),
}];
assert_eq!(
BandersnatchVrfVerifiable::batch_validate(&batch),
Err(crate::Error::VerificationFailed),
);
assert_eq!(
BandersnatchVrfVerifiable::batch_validate_per_item(&batch),
vec![Err(crate::Error::VerificationFailed)],
);
}
fn chunk_lookup(
builder_params: &ark_vrf::ring::RingBuilderPcsParams<BandersnatchSha512Ell2>,
) -> impl Fn(
core::ops::Range<usize>,
) -> Result<Vec<crate::ring::StaticChunk<BandersnatchSha512Ell2>>, ()>
+ Copy
+ '_ {
move |range| {
builder_params
.lookup(range)
.map(|v| v.into_iter().map(crate::ring::StaticChunk).collect())
.ok_or(())
}
}
fn build_members(
member_keys: impl Iterator<Item = <BandersnatchVrfVerifiable as GenerateVerifiable>::Member>,
domain_size: RingDomainSize,
) -> <BandersnatchVrfVerifiable as GenerateVerifiable>::Members {
let (_, builder_params) = start_members_from_params(domain_size);
let get_many = chunk_lookup(&builder_params);
let mut inter = BandersnatchVrfVerifiable::start_members(domain_size);
BandersnatchVrfVerifiable::push_members(&mut inter, member_keys, get_many).unwrap();
BandersnatchVrfVerifiable::finish_members(inter)
}
}