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
17 changes: 17 additions & 0 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,23 @@ ignore = [
"RUSTSEC-2025-0141", # bincode 1.3.3 unmaintained (from wasmtime-jit)
"RUSTSEC-2026-0020", # wasmtime 8.0.1 - guest-controlled resource exhaustion (from Polkadot SDK sc-executor)
"RUSTSEC-2026-0021", # wasmtime 8.0.1 - panic on excessive headers (from Polkadot SDK sc-executor)
"RUSTSEC-2026-0085", # wasmtime 8.0.1 - panic lifting flags component value (from Polkadot SDK sc-executor)
"RUSTSEC-2026-0086", # wasmtime 8.0.1 - host data leakage with 64-bit tables and Winch (from Polkadot SDK)
"RUSTSEC-2026-0087", # wasmtime 8.0.1 - segfault f64x2.splat on x86-64 Cranelift (from Polkadot SDK)
"RUSTSEC-2026-0088", # wasmtime 8.0.1 - data leakage between pooling allocator instances (from Polkadot SDK)
"RUSTSEC-2026-0089", # wasmtime 8.0.1 - host panic on table.fill with Winch (from Polkadot SDK)
"RUSTSEC-2026-0091", # wasmtime 8.0.1 - OOB write transcoding component model strings (from Polkadot SDK)
"RUSTSEC-2026-0092", # wasmtime 8.0.1 - panic transcoding misaligned UTF-16 strings (from Polkadot SDK)
"RUSTSEC-2026-0093", # wasmtime 8.0.1 - heap OOB read UTF-16 to latin1+utf16 transcoding (from Polkadot SDK)
"RUSTSEC-2026-0094", # wasmtime 8.0.1 - improperly masked return from table.grow with Winch (from Polkadot SDK)
"RUSTSEC-2026-0095", # wasmtime 8.0.1 - sandbox-escaping memory access with Winch (from Polkadot SDK)
"RUSTSEC-2026-0096", # wasmtime 8.0.1 - miscompiled heap access enables sandbox escape on aarch64 (from Polkadot SDK)

# Unsound (transitive, no upgrade path within current SDK pinning)
"RUSTSEC-2026-0097", # rand 0.8.5 / 0.9.2 - unsound with custom logger (from ark-std, fc-rpc, litep2p)

# Unmaintained (transitive)
"RUSTSEC-2025-0161", # libsecp256k1 0.7.2 unmaintained (from fc-rpc, fp-account/pallet-evm)

# Allowed warnings (8 total)
"RUSTSEC-2024-0388", # derivative 2.2.0 unmaintained (from ark-r1cs-std)
Expand Down
2 changes: 1 addition & 1 deletion frame/zk-verifier/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "pallet-zk-verifier"
version = "0.4.0"
version = "0.4.1"
description = "Zero-Knowledge proof verification pallet for Orbinum"
authors = ["Orbinum Team"]
license = "GPL-3.0-or-later"
Expand Down
39 changes: 39 additions & 0 deletions frame/zk-verifier/src/benchmarking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,5 +194,44 @@ mod benchmarks {
));
}

#[benchmark]
fn batch_register_verification_keys(n: Linear<1, 10>) {
let vk_bytes = sample_verification_key();

let entries: Vec<crate::types::VkEntry> = (0..n)
.map(|i| crate::types::VkEntry {
circuit_id: CircuitId(100 + i),
version: 1,
verification_key: vk_bytes
.clone()
.try_into()
.expect("benchmark vk bytes must fit BoundedVec"),
set_active: true,
})
.collect();

let bounded_entries: frame_support::BoundedVec<
crate::types::VkEntry,
frame_support::traits::ConstU32<10>,
> = entries
.try_into()
.expect("n <= 10, bounded vec debe admitir la entrada");

#[extrinsic_call]
_(RawOrigin::Root, bounded_entries);

for i in 0..n {
assert!(
VerificationKeys::<T>::contains_key(CircuitId(100 + i), 1u32),
"entrada {i} debe estar en VerificationKeys"
);
assert_eq!(
crate::pallet::ActiveCircuitVersion::<T>::get(CircuitId(100 + i)),
Some(1u32),
"entrada {i} debe tener versión activa = 1"
);
}
}

impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test);
}
67 changes: 66 additions & 1 deletion frame/zk-verifier/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ mod benchmarking;
/// Domain port for ZK verification (the ONLY public contract)
pub use domain::services::ZkVerifierPort;

pub use types::{CircuitId, ProofSystem, VerificationKeyInfo, VerificationStatistics};
pub use types::{CircuitId, ProofSystem, VerificationKeyInfo, VerificationStatistics, VkEntry};
pub use weights::WeightInfo;

#[derive(
Expand Down Expand Up @@ -206,6 +206,8 @@ pub mod pallet {
ProofVerified { circuit_id: CircuitId, version: u32 },
/// Proof verification failed
ProofVerificationFailed { circuit_id: CircuitId, version: u32 },
/// All VKs in a batch were registered (and optionally activated) atomically
BatchVerificationKeysRegistered { count: u32 },
}

// ========================================================================
Expand Down Expand Up @@ -377,6 +379,69 @@ pub mod pallet {
) -> DispatchResult {
Self::execute_verify_proof(origin, circuit_id.0, None, proof, public_inputs)
}

/// Atomically register (and optionally activate) up to 10 verification keys.
///
/// All entries are validated and written in the same block. If any entry is
/// invalid the whole call reverts — no partial state is committed.
///
/// `set_active: true` in an entry forces that version to become the active one
/// for its circuit. If no active version exists yet the entry is activated
/// regardless of the flag.
///
/// Origin must be Root (sudo/governance).
#[pallet::call_index(4)]
#[pallet::weight(T::WeightInfo::batch_register_verification_keys(entries.len() as u32))]
pub fn batch_register_verification_keys(
origin: OriginFor<T>,
entries: BoundedVec<VkEntry, ConstU32<10>>,
) -> DispatchResult {
ensure_root(origin)?;
ensure!(!entries.is_empty(), Error::<T>::InvalidBatchSize);

for entry in entries.iter() {
let domain_vk = crate::domain::entities::VerificationKey::new(
entry.verification_key.to_vec(),
crate::domain::value_objects::ProofSystem::Groth16,
)
.map_err(|err| {
Self::map_application_error(
crate::application::errors::ApplicationError::Domain(err),
)
})?;

let vk_info = VerificationKeyInfo {
key_data: domain_vk
.data()
.to_vec()
.try_into()
.map_err(|_| Error::<T>::VerificationKeyTooLarge)?,
system: ProofSystem::Groth16,
registered_at: frame_system::Pallet::<T>::block_number(),
};

VerificationKeys::<T>::insert(entry.circuit_id, entry.version, vk_info);

let auto_activate = ActiveCircuitVersion::<T>::get(entry.circuit_id).is_none();
if entry.set_active || auto_activate {
ActiveCircuitVersion::<T>::insert(entry.circuit_id, entry.version);
Self::deposit_event(Event::ActiveVersionSet {
circuit_id: entry.circuit_id,
version: entry.version,
});
}

Self::deposit_event(Event::VerificationKeyRegistered {
circuit_id: entry.circuit_id,
version: entry.version,
});
}

Self::deposit_event(Event::BatchVerificationKeysRegistered {
count: entries.len() as u32,
});
Ok(())
}
}
}

Expand Down
Loading
Loading