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
8 changes: 5 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,14 @@ jobs:
- name: Check workspace
run: cargo check --release --workspace

# zk-core must build in a no_std/WASM context. Guard against a consumer or
# feature change that leaks `std` into the runtime build.
- name: Check zk-core no_std feature matrix
# zk-core and zk-verifier must build in a no_std/WASM context. Guard against
# a consumer or feature change that leaks `std` into the runtime build.
- name: Check zk primitives no_std feature matrix
run: |
cargo check -p orbinum-zk-core --no-default-features
cargo check -p orbinum-zk-core --no-default-features --features poseidon-native
cargo check -p orbinum-zk-verifier --no-default-features
cargo check -p orbinum-zk-verifier --no-default-features --features groth16-native

# Step 3: Build workspace - compiles once for all subsequent jobs to reuse
build:
Expand Down
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions frame/zk-verifier/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ All notable changes to this pallet are documented here.

## [Unreleased]

## [0.18.0] - 2026-10-13

### Added

- Feature `groth16-native`: the pairing runs through the node's
`bn254_groth16_verify` host function instead of in Wasm. Same function, same
results; off by default.

## [0.17.1] - 2026-10-09

### Changed
Expand Down
3 changes: 2 additions & 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.17.1"
version = "0.18.0"
description = "Zero-Knowledge proof verification pallet for Orbinum"
authors = ["Orbinum Team"]
license = "GPL-3.0-or-later"
Expand Down Expand Up @@ -74,6 +74,7 @@ runtime-benchmarks = [
"dep:ark-groth16",
]
skip-proof-verification = []
groth16-native = ["orbinum-zk-verifier/groth16-native"]
try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
Expand Down
16 changes: 13 additions & 3 deletions frame/zk-verifier/src/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,9 @@ fn record_stats<T: Config>(circuit_id: CircuitId, version: u32, result: bool) {
});
}

/// The pairing, under a key in prepared form: [`verify_prepared`], the same
/// function the node's `bn254_groth16_verify` host function runs.
/// The pairing, under a key in prepared form: [`verify_prepared`], natively
/// through the node's `bn254_groth16_verify` host function under
/// `groth16-native`, in Wasm otherwise.
///
/// Always `true` in **test** builds, whose keys deserialize but carry no real
/// proofs. Benchmarks run the full pairing, so weights include it.
Expand All @@ -144,7 +145,16 @@ fn do_verify(prepared: &[u8], proof: &[u8], inputs: &[[u8; 32]]) -> bool {
true
}

#[cfg(not(test))]
#[cfg(all(not(test), feature = "groth16-native"))]
{
orbinum_zk_verifier::host_interface::groth_16_host_interface::bn254_groth16_verify(
prepared,
proof,
&inputs.concat(),
)
}

#[cfg(all(not(test), not(feature = "groth16-native")))]
{
orbinum_zk_verifier::verify_prepared(prepared, proof, &inputs.concat())
}
Expand Down
8 changes: 8 additions & 0 deletions primitives/zk-verifier/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ All notable changes to this crate are documented here.

## [Unreleased]

## [3.3.0] - 2026-10-13

### Changed

- `bn254_groth16_verify` drops `register_only` (`#[version(1)]`): runtimes can
import it. Symbol and behaviour unchanged; nodes from 0.4.0 already register
it.

## [3.2.0] - 2026-10-09

### Added
Expand Down
2 changes: 1 addition & 1 deletion primitives/zk-verifier/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "orbinum-zk-verifier"
version = "3.2.0"
version = "3.3.0"
authors = ["Orbinum Network <contact@orbinum.net>"]
edition = "2021"
publish = false
Expand Down
8 changes: 3 additions & 5 deletions primitives/zk-verifier/src/host_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,8 @@
//!
//! - **Frozen.** Executed blocks call version 1 and syncing nodes re-run them:
//! any observable change is a new `#[version(N)]`, and version 1 stays.
//! - **`register_only`.** A node without the function cannot instantiate a
//! runtime that imports it, so nodes register it first and no runtime calls
//! it yet. A later runtime drops the flag once every node runs a release
//! with it (minimum author version for authors; RPC and archive by hand).
//! - **Imported from spec 19.** Registered `register_only` since node 0.4.0;
//! a node without it cannot instantiate a runtime that imports it.

use alloc::vec::Vec;
use sp_runtime_interface::{pass_by::PassFatPointerAndRead, runtime_interface};
Expand All @@ -16,7 +14,7 @@ use sp_runtime_interface::{pass_by::PassFatPointerAndRead, runtime_interface};
pub trait Groth16HostInterface {
/// [`crate::verify_prepared`], natively. It must never panic: natively a
/// panic takes the node down instead of trapping the runtime.
#[version(1, register_only)]
#[version(1)]
fn bn254_groth16_verify(
prepared_vk: PassFatPointerAndRead<&[u8]>,
proof: PassFatPointerAndRead<&[u8]>,
Expand Down
5 changes: 4 additions & 1 deletion template/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ sp-maybe-compressed-blob = "11.1.0"
grandpa-verifier-primitives = { workspace = true, features = ["std"] }

[features]
default = ["std", "with-rocksdb-weights", "poseidon-native-runtime"]
default = ["std", "with-rocksdb-weights", "poseidon-native-runtime", "groth16-native-runtime"]
with-rocksdb-weights = []
with-paritydb-weights = []

Expand All @@ -116,6 +116,9 @@ hyperbridge-testnet = []
poseidon-native-runtime = [
"pallet-shielded-pool/poseidon-native",
]
groth16-native-runtime = [
"pallet-zk-verifier/groth16-native",
]

std = [
"ethereum/std",
Expand Down
12 changes: 11 additions & 1 deletion template/runtime/RUNTIME_VERSIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ every EVM priority tip goes to the validator that authored the block.
`transaction_version` moves: pallet index 16 and `shielded_pool` call 18 are
gone, and call 19 is renamed. Ships with `orbinum-runtime` / `orbinum-node`
0.5.0, `pallet-shielded-pool` 0.25.0, `pallet-shielded-pool-runtime-api` 0.4.0,
`pallet-evm-precompile-shielded-pool` 0.10.0 and `pallet-validator-set` 0.4.1.
`pallet-evm-precompile-shielded-pool` 0.10.0, `pallet-validator-set` 0.4.1,
`pallet-zk-verifier` 0.18.0 and `orbinum-zk-verifier` 3.3.0.

#### 1 · Block author is the session validator

Expand Down Expand Up @@ -61,6 +62,15 @@ A transaction's priority tip goes to the block author's validator account
(`TipToValidator`); `block.coinbase` is the zero address. It used to be bytes
4..24 of the Aura key, whose mapped account no key controls.

#### 4 · Groth16 host function

The runtime imports `bn254_groth16_verify` (`groth16-native-runtime`): proof
verification runs natively instead of in Wasm (`verify_proof` 2.43 → 0.61 ms).
Same function on both paths, so results do not change. Nodes register it since
0.4.0; an older node cannot instantiate this runtime and stops importing, so
every node (validators, RPC, archive) must run ≥ 0.4.0 before `setCode`.
Weights are unchanged (measured in Wasm, so they overcharge).

#### Migrations

- `RelayerFeesToPool` — drains `Relayer::PendingRelayerFees` into
Expand Down
10 changes: 6 additions & 4 deletions template/runtime/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ fn main() {
.export_heap_base()
.import_memory();

// Poseidon via host functions (~3× faster). Skipped for try-runtime
// builds: the stock try-runtime CLI executor lacks the custom host
// interface, so those builds fall back to the pure-wasm hasher.
// Poseidon (~3×) and Groth16 (~3.5×) via host functions. Skipped for
// try-runtime builds: the stock try-runtime CLI executor lacks the
// custom host interfaces, so those builds fall back to pure Wasm.
if std::env::var("CARGO_FEATURE_TRY_RUNTIME").is_err() {
builder = builder.enable_feature("poseidon-native-runtime");
builder = builder
.enable_feature("poseidon-native-runtime")
.enable_feature("groth16-native-runtime");
}

builder.enable_metadata_hash("ORB", 18).build();
Expand Down
13 changes: 5 additions & 8 deletions template/runtime/src/runtime_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -588,21 +588,18 @@ fn signed_extra_implicit_succeeds_with_check_metadata_hash() {

// ── Host functions ────────────────────────────────────────────────────────────

/// The runtime must not import `bn254_groth16_verify` before every node
/// registers it: a node without it cannot instantiate the runtime and stops
/// importing. Flip when a runtime turns it on.
/// Spec 19 imports `bn254_groth16_verify`, registered since node 0.4.0. A
/// node without it cannot instantiate the runtime and stops importing.
#[test]
fn the_runtime_does_not_import_the_groth16_host_function_yet() {
fn the_runtime_imports_the_groth16_host_function() {
let Some(blob) = crate::WASM_BINARY else {
return; // SKIP_WASM_BUILD
};
// Release builds embed the compressed blob.
let wasm = sp_maybe_compressed_blob::decompress(blob, 64 << 20).expect("runtime blob");
let imports = |symbol: &[u8]| wasm.windows(symbol.len()).any(|w| w == symbol);
// The search works: Poseidon's host function is imported.
assert!(imports(b"ext_poseidon_host_interface_poseidon_hash_2"));
assert!(!imports(
b"ext_groth_16_host_interface_bn254_groth16_verify"
assert!(imports(
b"ext_groth_16_host_interface_bn254_groth16_verify_version_1"
));
}

Expand Down
Loading