Expand description
§IOTA Proof of Inclusion Rust Package
§Introduction
The Proof of Inclusion Rust Package constructs and verifies portable evidence that IOTA ledger data is included in a certified checkpoint. It is the Rust Package for Proof of Inclusion in the IOTA Notarization Toolkit.
Use Proof of Inclusion when a verifier needs cryptographic evidence for a transaction, event, or specific object version without trusting the source that transports the proof. PoiClient provides the main entry point, ProofBuilder constructs the evidence, and ProofVerifier verifies it locally against a committee the caller trusts.
Proof of Inclusion operates on existing IOTA ledger activity. It does not define a separate on-chain object or Move Package. Single Notarization and Audit Trails can create ledger activity that applications later prove, but Proof of Inclusion also supports transactions, events, and object versions created by other IOTA applications.
You can find the full IOTA Notarization Toolkit documentation here.
§Process Flows
Proof construction and verification are separate workflows with different trust responsibilities. Proof construction collects evidence from a ledger source, while verification authenticates that evidence relative to a committee trust decision made by the caller.
§Constructing a Proof
The following sequence shows how PoiClient and ProofBuilder construct one proof for one or more targets. Every target must belong to the same transaction.
sequenceDiagram
actor Application
participant Client as PoiClient
participant Builder as ProofBuilder
participant Source
participant Net as IOTA Network
Application ->>+ Client: fn proof()
Client ->>- Application: ProofBuilder
Application ->> Builder: fn transaction(), object(), or event()
Application ->>+ Builder: fn build()
Builder ->>+ Source: fetch target and transaction evidence
Source ->>+ Net: gRPC ledger requests
Net ->>- Source: transaction, objects, events, and checkpoint
Source ->>- Builder: decoded source evidence
Builder ->> Builder: validate targets and construct proof
Builder ->>- Application: ProofSource is the transport boundary. It fetches decoded transaction, object, checkpoint, chain, and committee evidence.
ProofBuilder owns target resolution, consistency checks, duplicate suppression, and proof construction, so custom sources do not reimplement that workflow.
§Verifying a Proof
The following sequence shows committee-aware verification through PoiClient::verifier(). Committee resolution may fetch evidence, but ProofVerifier performs the final proof checks locally without making network requests.
sequenceDiagram
actor Verifier
participant Client as PoiClient
participant Resolver as CommitteeResolver
participant Source
participant Net as IOTA Network
participant ProofVerifier
Verifier ->>+ Client: fn verifier(resolution)
Client ->>- Verifier: CommitteeResolver
Verifier ->>+ Resolver: fn verify(proof)
Resolver ->>+ Source: resolve committee for checkpoint epoch
Source ->>+ Net: fetch committee or epoch-close evidence
Net ->>- Source: committee evidence
Source ->>- Resolver: decoded evidence
Resolver ->> Resolver: apply trusted-node or anchored resolution
Resolver ->>+ ProofVerifier: fn verify(proof)
Note right of ProofVerifier: Offline verification only
ProofVerifier ->>- Resolver: verification result
Resolver ->>- Verifier: verification resultCommitteeResolution::TrustedNode accepts committee data from a node already inside the caller’s trust boundary.
Anchored resolution starts from a trusted committee or genesis blob and authenticates every committee transition before accepting the committee required by the proof.
§Proof Construction
PoiClient provides explicit constructors for the public IOTA networks. The client does not select a default network, so the calling application always chooses where it fetches proof material.
use iota_sdk_types::TransactionDigest;
use poi_rs::PoiClient;
let transaction_digest: TransactionDigest = todo!();
let client = PoiClient::mainnet()?;
let proof = client
.proof()
.transaction(transaction_digest)
.build()
.await?;Use PoiClient::testnet() or PoiClient::devnet() for the other public networks. Applications can pass a custom Source to PoiClient::new(source) when they use a private node, archive, fixture, or local test cluster. ProofBuilder remains available directly for lower-level use.
A builder can stack multiple object and event targets by calling object() and event() repeatedly or by using the objects() and events() batch methods. Every target must belong to the same transaction. The builder ignores exact
duplicates and reuses one transaction and one checkpoint for the complete target set.
Network selection configures only the proof source. It does not make the returned proof trusted or select an authoritative committee for verification.
The default native-grpc feature implements Source directly for the SDK GrpcClient and provides the public-network constructors. WASM packages can disable default features and supply a JavaScript-backed Source without compiling native gRPC.
§Verification
Create a verifier from the same PoiClient for the common source-backed workflow. The verifier resolves the committee required by the proof and then performs offline proof verification.
use std::fs::File;
use poi_rs::{CommitteeResolution, PoiClient, Proof};
let client = PoiClient::testnet()?;
let resolution = CommitteeResolution::from_genesis(File::open("genesis.blob")?)?;
let verifier = client.verifier(resolution);
let verified = verifier.verify(proof).await?;
println!("verified transaction: {}", verified.transaction_digest());CommitteeResolution::TrustedNode is available when the connected node is explicitly inside the caller’s trust boundary. CommitteeResolution::from_genesis() loads an anchor committee from a trusted BCS-encoded genesis blob, while CommitteeResolution::anchored() accepts an already extracted trusted committee. Use
CommitteeResolution::anchored_with_cache() or CommitteeResolution::from_genesis_with_cache() to supply a cache that
persists authenticated committees. Shared cache entries are keyed by both the trusted genesis checkpoint digest and epoch, so one backend can be shared safely by resolvers for different networks. The genesis-based constructor derives the chain identifier automatically; anchored_with_cache() requires it explicitly.
Retain the verifier when checking multiple proofs so it can reuse its authenticated committee cache. ProofVerifier remains the offline entry point for callers that already possess the authoritative committee.
Successful verification returns a VerifiedProof that borrows from the input proof and exposes authenticated checkpoint metadata, transaction data and digest, execution effects, and the complete event list. effects() returns the execution effects, including execution status and object changes. events() returns all events in transaction order, or None only when the effects commit to no events. targets() preserves the transaction, object, and event targets explicitly selected by the caller; selecting an event does not filter events().
Verification also authenticates the packaged user signatures against the checkpoint contents, although VerifiedProof does not expose them. Read relying-party data through this returned value. The original Proof remains the portable untrusted envelope used for transport and serialization.
Verification checks:
- the proof contains at least one transaction, object, or event target;
- the supplied committee certifies the checkpoint summary and its checkpoint-contents digest;
- the packaged transaction digest matches the transaction effects;
- the transaction effects are included in the authenticated checkpoint contents;
- the packaged user signatures match those committed by the checkpoint;
- the event list is present exactly when the transaction effects commit to events, and its digest matches;
- an explicit transaction target matches the packaged transaction;
- every object target’s exact reference appears in the transaction effects; and
- every event target has packaged event data, belongs to the packaged transaction, and selects an existing event.
§What a Verified Proof Proves
Successful verification authenticates the following targets relative to the supplied committee:
- A transaction target proves that the selected transaction and its effects are included in the certified checkpoint.
- An object target proves that the exact object version was written by the authenticated transaction. For an object ID without a transaction or event target, the builder resolves its latest version at proof construction time; the proof does not claim that it remains latest. Deleted and wrapped objects are unsupported.
- An event target proves that the selected event and its contents appear in the authenticated transaction’s event list.
§Proof Model
A Proof contains three layers of evidence:
ProofTargetsrecords the transaction, objects, and events explicitly selected by the caller.- A
CertifiedCheckpointSummaryand itsCheckpointContentslink the transaction to a committee-certified checkpoint. - A required
TransactionProofcontains the transaction, its effects, and its complete event list when present, regardless of which targets were selected.
Object targets contain their exact values. Event targets contain EventID values, while the transaction proof carries the complete event list needed to verify the effects’ event digest. A transaction target is present only when the caller explicitly requests the transaction itself, although transaction evidence supports every proof.
§JSON Compatibility
Proof JSON is a versioned persistence and exchange format. Releases that support ProofV1 continue to deserialize its existing JSON shape and serialize the same field structure. Frozen V1 fixtures enforce this contract for transaction, object, and event proofs.
Dependency upgrades must not silently change the ProofV1 representation. Preserve the existing shape with custom serialization when necessary, or introduce a new Proof variant for an incompatible format change.
§Trust Boundaries
ProofVerifier is intentionally offline. It does not make RPC calls and does not decide which committee is authoritative. CommitteeResolver::verify() composes committee resolution with offline verification for source-backed
workflows, while CommitteeResolver::resolve() returns the authenticated committee when callers need it directly.
Treat every proof payload as untrusted. After successful verification, trust target data relative to the supplied committee through the returned VerifiedProof; do not read relying-party data from an unrelated Proof value.
The proof’s chain value is informational. The verifier does not authenticate it, so applications must not use it to select a network, committee, genesis blob, or other trust anchor.
§Command-Line Interface
The optional cli feature builds the poi command for creating and verifying JSON proofs. CLI verification uses a trusted genesis blob and does not provide trusted-node verification.
§Building the CLI From Source
The project does not distribute pre-built poi binaries. Build the CLI locally from the repository source with Rust
1.85 or later:
git clone https://github.com/iotaledger/notarization.git
cd notarization
cargo build --release -p poi-rs --features cli --bin poiCargo writes the binary to target/release/poi on Linux and macOS or target\release\poi.exe on Windows. Run the locally built binary from the repository root:
./target/release/poi --helpYou can also build from source and install poi into Cargo’s binary directory:
cargo install --path poi-rs --features cli --bin poi --locked§Using the CLI
cargo run --release -p poi-rs --features cli --bin poi -- create \
--network testnet \
--transaction <transaction-digest> \
--output proof.json
cargo run --release -p poi-rs --features cli --bin poi -- verify \
--network testnet \
proof.jsonFor --network mainnet and --network testnet, the CLI downloads the genesis blob to the IOTA configuration directory under poi/<network>/genesis.blob. It validates the blob against the network’s canonical genesis digest on download and every cache load. Devnet has no stable genesis digest, so verification on devnet requires an explicit trusted blob through --genesis.
Run cargo run --release -p poi-rs --features cli --bin poi -- --help for all targets, network options, and file input formats.
§Glossary
Proof: Versioned Proof of Inclusion envelope.ProofV1: Version 1 checkpoint and transaction evidence carried byProof::ProofV1.TransactionProof: Transaction, effects, and optional event evidence used to prove inclusion.ProofTargets: Transaction, object, and event targets explicitly selected by the caller.PoiClient: Source-backed entry point for proof construction and committee-aware verification.CommitteeResolution: Trusted-node or anchored committee-resolution configuration, including the committee cache.ProofBuilder: Proof-construction workflow for public networks or custom sources.Source: Ledger-read boundary for gRPC nodes, JavaScript clients, archives, fixtures, and other evidence sources.SourceTransactionandSourceCheckpoint: Transport-independent decoded evidence returned by aSource.CommitteeResolver: Committee resolution and source-backed verification configured byCommitteeResolution.ProofVerifier: Offline verifier forProofvalues.SourceError: Transport and response failure from a ledger source.ProofBuilderError,CommitteeResolutionError,ProofVerificationError,VerifyError, andSerializationError: Operation-specific errors.
§Documentation And Resources
- Proof of Inclusion Rust API documentation
- Proof of Inclusion Rust Examples
- Proof of Inclusion Wasm Package
- Proof of Inclusion Wasm Examples
- Repository Root
This README is also the crate-level rustdoc entry point. Source files provide detailed API documentation for all public types and methods.
§Bindings
The Proof of Inclusion Wasm Package provides JavaScript and TypeScript bindings for Node.js applications.
§Contributing
We would love to have you help us develop the IOTA Notarization Toolkit. Every contribution is greatly valued.
Review the contribution sections in the IOTA Docs Portal.
To contribute directly to the repository, fork the project, push your changes to your fork, and create a pull request.
Join the #notarization channel on the IOTA Discord for development discussions and
support. You can also ask questions on IOTA Stack Exchange.
Re-exports§
pub use builder::ProofBuilder;pub use builder::ProofBuilderError;pub use cache::CommitteeCache;pub use cache::CommitteeCacheError;pub use cache::CommitteeCacheKey;pub use cache::MemoryCommitteeCache;pub use client::PoiClient;pub use committee::CommitteeResolution;pub use committee::CommitteeResolutionError;pub use committee::CommitteeResolutionErrorKind;pub use committee::CommitteeResolver;pub use committee::ProofVerificationError;pub use proof::Proof;pub use proof::ProofTargets;pub use proof::ProofV1;pub use proof::ProofVerifier;pub use proof::SerializationError;pub use proof::SerializationErrorKind;pub use proof::TransactionProof;pub use proof::VerifiedProof;pub use proof::VerifyError;pub use proof::VerifyErrorKind;pub use source::Source;pub use source::SourceCheckpoint;pub use source::SourceError;pub use source::SourceTransaction;
Modules§
- builder
- Proof construction builders.
- cache
- Verified committee lineage caches for anchored resolution.
- client
- Convenient source-backed client for proof construction and verification.
- committee
- Committee resolution for checkpoint verification.
- proof
- Proof data types and offline verification. Proof types and verification.
- source
- Ledger evidence source abstraction.