Zipwire.ProofPack
0.2.1
dotnet add package Zipwire.ProofPack --version 0.2.1
NuGet\Install-Package Zipwire.ProofPack -Version 0.2.1
<PackageReference Include="Zipwire.ProofPack" Version="0.2.1" />
<PackageVersion Include="Zipwire.ProofPack" Version="0.2.1" />
<PackageReference Include="Zipwire.ProofPack" />
paket add Zipwire.ProofPack --version 0.2.1
#r "nuget: Zipwire.ProofPack, 0.2.1"
#:package Zipwire.ProofPack@0.2.1
#addin nuget:?package=Zipwire.ProofPack&version=0.2.1
#tool nuget:?package=Zipwire.ProofPack&version=0.2.1
ProofPack
ProofPack is a layered approach to secure, privacy-preserving data exchange. Each layer serves a specific purpose:
Merkle Exchange Document - The innermost layer containing the actual data:
- Uses Merkle tree proofs to ensure data integrity
- Enables selective disclosure of data fields
- Each leaf can be revealed or hidden independently
- The root hash provides a cryptographic commitment to the entire dataset
Attested Merkle Exchange Document - Adds blockchain attestation:
- Contains the Merkle Exchange Document
- Adds metadata about the on-chain attestation
- Includes timestamp and nonce for replay protection
- Links to the blockchain attestation to the root hash
JWS Envelope - The outermost layer providing cryptographic signatures:
- Wraps the Attested Merkle Exchange Document
- Provides one or more cryptographic signatures
- Ensures the document hasn't been tampered with
- Can be verified without accessing the blockchain
This layered approach enables:
- Privacy-preserving data sharing
- Cryptographic proof of data integrity
- Blockchain-based attestation
- Flexible signature schemes
How It Works
- An app with the original dataset (e.g., a passport record) creates a Merkle tree and attests its root hash on-chain
- The user can then create a ProofPack document that reveals only the data they want to share
- This ProofPack can be shared via website upload, email, or a share link
- The recipient can verify both the data integrity and the on-chain attestation
This repository contains:
- The JSON specification
- Libraries to create ProofPacks
- Tools to verify ProofPacks
- Documentation and examples
For the complete technical specification, see the Merkle Exchange Specification.
Vision
ProofPack is designed to bridge traditional data sharing with emerging blockchain-based trust ecosystems. While initially developed by Zipwire, the goal is to establish a new standard for sharing data that:
- Ensures data integrity through cryptographic proofs
- Enables selective disclosure of sensitive information
- Connects data sources to blockchain-based trust networks
- Supports attestations - where one blockchain account holder can make verifiable statements about another
Building Trust Chains
The power of ProofPack lies in its ability to tie back to verifiable trust chains, made possible by cryptography and blockchains. Let's use a concrete example of verifying someone's date of birth:
At its core, ProofPack is just a standard around a JSON schema. But it allows, for example, a passport checking app to make a verifiable statement about a person's date of birth. But this isn't just a standalone claim - it's connected to a chain of trust that extends all the way back to trusted institutions:
Date of Birth ← Passport ← Zipwire ← Yoti ← iBeta ← NIST
Today, this chain of trust exists only in words. For example:
- Zipwire uses Yoti's MyFace technology for identity verification
- Yoti's MyFace has achieved iBeta ISO PAD Level 2 certification
- iBeta is a NIST-accredited testing laboratory
But these relationships are currently just claims on websites. ProofPack envisions a future where each link in this chain is verifiable through blockchain attestations:
- NIST attesting to iBeta's testing capabilities
- iBeta attesting to Yoti's MyFace technology
- Yoti attesting to Zipwire's implementation
- Zipwire attesting to passport verification
- The passport authority attesting to date of birth
This creates a verifiable chain of trust that can be cryptographically proven, rather than just claimed.
Platform Security & Compliance
- Zipwire's reputation depends on maintaining high security standards
- Using best-in-class ID checking and AML reporting systems
- Keeping cryptographic keys secure
- Following industry best practices
Trust Attestations
- Organizations can attest to Zipwire's wallet address (the one making attestations)
- For example, Yoti (our ID checking provider) could attest to our security practices
- ISO standards bodies could attest to our compliance
- These attestations create a trust chain
Extended Trust Network
- Yoti itself could be attested to by:
- iBeta (for software testing)
- NIST (National Institute of Standards and Technology)
- This creates a web of trust that's verifiable on-chain
- Replaces the current system of "trust us, we have a nice website"
- Yoti itself could be attested to by:
This trust chain enables a new paradigm where:
- Trust is built through verifiable attestations
- Organizations can prove their security and compliance
- Users can verify the entire chain of trust
- Reputation is built through on-chain proof, not just marketing
Understanding ProofPack's Role
To understand how ProofPack fits into real-world applications and user journeys, we've created two diagrams:
Sequence Diagram - Shows how ProofPack integrates with other systems in a typical user flow
User Journey Diagram - Illustrates how users interact with ProofPack in the context of a complete application
Real-World Examples
Energy Performance Certificate
Imagine you're selling your house. You need to provide an energy performance certificate to the legal portal to reassure your buyer. Currently, this is just a PDF file that only needs to look legitimate.
With ProofPack, this could be transformed into a verifiable document containing the complete dataset, attested to by the software they used to make the calculations. The chain of attestations might look like this:
EPC Root Hash ← EPC Calculation Software ← Software Provider Attestation ← Software Certification Body Attestation ← NCM (National Calculation Methodology) Attestation ← DLUHC / Government Approval (Policy & Standards Attestation)
The surveyor's software would create the ProofPack which your surveyor would furnish you with, and you could then upload to the legal portal. The document could include embedded visual charts as JPGs to make the data more accessible, as well as the key-values.
EU Medical Services
You need to access EU medical services, which requires proof of your nationality. You connect your web3 wallet to the medical services website, but you don't have any attestations about your nationality as that would compromise your privacy.
Instead, you log into an ID checking service you've used before that supports ProofPack. You create a new proof that reveals only your nationality from your passport, then generate a Share Link. When you paste this URL into the medical services website, it verifies the JSON and confirms that the attestation:
- Matches your wallet address
- Comes from a reputable attester
- Is part of a trusted chain of attestations (see chains of trust, above)
AI and LLM Integration
ProofPack's structured JSON format enables interesting possibilities with AI and Large Language Models (LLMs). For example:
- Automated Verification: An LLM can:
- Parse the ProofPack JSON structure
- Extract and decode the leaf data
- Write code to verify the Merkle root hash
- Use MCP (Model Context Protocol) to call out to blockchain services and verify the attestation
- Use MCP to also look for the attester's attestations, and so on, building confidence
This opens up possibilities for automated, AI-driven verification systems that can process ProofPacks without human intervention, while maintaining the security and privacy guarantees of the format. The structured nature of ProofPack makes it particularly well-suited for LLM tool use, as the AI can reliably parse the format and make appropriate service calls to verify the attestations.
Google Gemini Python Verifier
The screenshot below was taken from Google Gemini in June, 2025. The Attested Merkle Exchange JSON was pasted into the chat window and asked to decode the leaves. Once it did this, using its native ability to speak hex-encoded UTF-8, it was then asked to write a script to check the leaf hashes roll up to the root hash, which it did.
It isn't hard to imagine an MCP service calling out to the EAS contract on the right chain and checking the hash matches.
Responsible Timber Supply Chain
ProofPack enables a verifiable, privacy-preserving supply chain for responsibly sourced timber:
Provenance Attestation:
- Loggers attest timber batches (e.g., batch #T1234 from Canada)
- Structured location data (country, region, coordinates)
- Certification details
- Merkle root stored on-chain via EAS
Handover Tracking:
- Each transfer (logger → trucker → port) attested using ProofPack
- QR codes contain location, batch number, and wallet IDs
- Links to consignment attestation
Selective Disclosure:
- Customers view coarse data (e.g., "Sourced from Canada, May 2025")
- Auditors access detailed locations and IDs
- Auditors issue their own EAS attestations
API Integration:
- Supply chain APIs serve redacted ProofPacks
- Each party (trucker, port) can hide sensitive leaves
- Verified by JWS and EAS
Trust Chain:
- Logger → Certification Body → Auditor
- All cryptographically attested
- Ensures sustainable sourcing without compromising privacy
OAuth API Integration
ProofPack can be integrated with OAuth 2.0 to enable secure, scope-based access to attested data. This integration allows applications to request ProofPacks via API calls, with the disclosed data controlled by the OAuth scope granted by the user.
An application in possession of a proof, but not the original issuer, could share it onward via its API. The API could choose to redact leaf data from the proof according to the scope agreed with its owner. In this situation, the original JWS envelope would have its signature invalidated by the change to the payload, so it would use the naked Attested Merkle Exchange JSON.
The consuming application can still trust the API and its SSL certificate, and the exchanged data is still reliable since its root hash can be computed and the attestation checked, so long as that application has proven its end user is the attested wallet holder.
API Flow
Authorization Request:
- The application initiates an OAuth flow with specific scopes
- Scopes can be granular, requesting access to specific fields (e.g.,
passport:read:dob
,passport:read:address
) - The user authorizes the application with the requested scopes
API Request:
- The application makes an authenticated API call with its OAuth token
- The request specifies which ProofPack fields it needs
- The API validates the token and scopes
ProofPack Generation:
- The server generates a ProofPack containing the authorized data*
- Fields not covered by the granted scopes remain hidden
- The ProofPack can be returned in either:
- JWS format (signed by the service)
- The naked Attested Merkle Exchange format
*redacting leaf data is simply a case of removing the data
and salt
fields.
- Verification:
- The application can verify the ProofPack's integrity
- The attestation chain can be validated
- Only the authorized fields are accessible
Example API Request
GET /api/v1/proofpack/passport
Authorization: Bearer <oauth_token>
Accept: application/attested-merkle-exchange-3.0+json
Example Response
Content-Type: application/attested-merkle-exchange-3.0+json
{
"merkleTree": {
"header": {
"typ": "application/merkle-exchange-3.0+json"
},
"leaves": [...],
"root": "0x1316f..."
},
"attestation": {
"eas": {
"network": "base-sepolia",
"attestationUid": "...",
"from": "...",
"to": "...",
"schema": { "schemaUid": "...", "name": "PrivateData" }
}
}
}
In this example, the OAuth scope passport:read:dob
was granted, so the date of birth field is disclosed while other fields remain hidden.
AML Report Example
Consider a scenario where you need to prove your compliance status to multiple trading applications:
Initial Verification:
- You complete a full AML check with a compliance provider
- The provider creates and stores an Attested Merkle Exchange blob containing sanctions list check, PEP status, etc.
Sharing with Trading Apps:
- Trading apps can request specific compliance data via OAuth*
- The compliance provider's API creates new ProofPacks from the original data
- No new checks are needed - just new JSON with selected fields
*or ask for the user to submit proofs via a form.
For example, a trading app might request just the PEP status with scope aml:read:pep_status
. The trading app can verify the attestation is valid, the root hash matches the disclosed data, and the user's wallet address matches the attested address.
This enables efficient compliance sharing while maintaining privacy and security.
ProofPack vs Zero-Knowledge Proofs
ProofPack and Zero-Knowledge Proofs (ZKPs) serve different privacy goals and use cases:
ProofPack: Selective Disclosure of Actual Data
ProofPack is designed for situations where you want to reveal actual data but control which specific fields are disclosed. It's like a digital ID card where you can choose which information to show:
- Static, downloadable files: Once issued, ProofPacks can be stored and reused
- Selective disclosure: Reveal only the fields needed for a specific use case
- Data authenticity: Prove the data comes from a trusted source and hasn't been tampered with
- Privacy through control: You decide what to reveal, but the revealed data is the actual data
- Self-sovereign: Users can download and keep their JSON, even editing it themselves to redact leaf data
- Verifiable despite edits: While edited data is no longer signed within its envelope, the remaining structure remains highly secure and verifiable
Example: A passport ProofPack where you reveal only your nationality for EU medical services, but the nationality field contains your actual nationality.
Self-Sovereign Example: A user downloads their ProofPack containing passport data. They can edit the JSON to redact sensitive fields like their full name or address, leaving only the fields they want to share. While the redacted data loses its cryptographic signature, the remaining structure and any undisclosed leaves maintain their integrity and can still be verified against the original Merkle root and blockchain attestation.
Zero-Knowledge Proofs: Proving Statements Without Revealing Data
ZKPs are designed for situations where you want to prove a statement is true without revealing the underlying data:
- Dynamic generation: Proofs are typically generated on-demand for specific questions
- Boolean outcomes: The result is always true/false for a specific statement
- No data revelation: The underlying data (witness) is never disclosed
- Privacy through cryptography: Mathematical proofs that don't reveal the source data
Example: Proving you're over 18 without revealing your exact date of birth.
Dynamic Questions Example: Consider age verification where the threshold date changes daily. Today (June 19, 2025), proving you're over 18 means proving your date of birth is before June 20, 2007. Tomorrow, it becomes June 21, 2007. A ZKP generated today for "born before June 20, 2007" cannot be reused tomorrow - a new proof must be generated for the new threshold date. This requires the verifier to communicate the current threshold to the prover's system so a fresh, relevant ZKP can be created.
Key Differences
Aspect | ProofPack | Zero-Knowledge Proofs |
---|---|---|
Data Revelation | Reveals actual data (selectively) | Never reveals underlying data |
Storage | Static, downloadable files | Often generated on-demand |
Reusability | Can be reused across different scenarios | May need regeneration for different questions |
Privacy Model | Control over what to reveal | Complete data hiding |
Use Case | When you want to share authentic data | When you want to prove properties without sharing data |
When to Use Each
Use ProofPack when:
- You need to share actual data fields
- You want to control which specific fields are revealed
- You need a reusable, static credential
- Data authenticity and source verification are important
Use ZKPs when:
- You want to prove a statement without revealing any underlying data
- The question/statement is dynamic and changes over time
- You need maximum privacy protection
- You're proving properties about data rather than sharing the data itself
Integration with Attestation Services
ProofPack is designed to work with various blockchain attestation services:
- Ethereum Attestation Service (EAS) - A public good for making onchain or offchain attestations about anything
- Solana Attestation Service (coming soon) - Similar functionality on the Solana blockchain
These services enable a new paradigm of trust where attestations can be:
- Chained together to build trust graphs
- Composed to create complex trust relationships
- Verified on-chain for maximum transparency
- Used off-chain for privacy-preserving verification
Current Packages
The library is currently available as two .NET packages:
Zipwire.ProofPack
: The core library providing the base functionalityZipwire.ProofPack.Ethereum
: Adds support for Ethereum curve (ES256K) signing and verification of JWS envelopes
Specialized libraries for verifying attestations on specific blockchains (e.g., Ethereum EAS integration) are coming soon.
JWS Envelope API
The JwsEnvelopeDoc
class represents a JWS envelope in the .NET API. Unlike some other classes in the library, JwsEnvelopeDoc
is a DTO (Data Transfer Object) that uses standard JSON serialization.
Creating JWS Envelopes
using Zipwire.ProofPack;
using Zipwire.ProofPack.Ethereum;
using Evoq.Blockchain.Merkle;
// Create a Merkle tree (the payload)
var merkleTree = new MerkleTree(MerkleTreeVersionStrings.V2_0);
merkleTree.AddJsonLeaves(new Dictionary<string, object?>
{
{ "name", "John Doe" },
{ "age", 30 }
});
merkleTree.RecomputeSha256Root();
// Create a JWS envelope with the Merkle tree as payload
var signer = new ES256KJwsSigner(privateKey);
var builder = new JwsEnvelopeBuilder(
signer,
type: "JWT",
contentType: "application/merkle-exchange+json"
);
var jwsEnvelope = await builder.BuildAsync(merkleTree);
Serializing JWS Envelopes
To convert a JwsEnvelopeDoc
to JSON, use the standard JsonSerializer
:
using System.Text.Json;
var json = JsonSerializer.Serialize(jwsEnvelope, new JsonSerializerOptions
{
WriteIndented = true,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});
Payload Serialization
When using MerkleTree
objects as payloads, the library automatically uses the correct serialization format:
- MerkleTree objects are serialized using the
MerkleTreeJsonConverter
to produce the proper Merkle Exchange Document format - Other objects use standard JSON serialization
- The payload is automatically base64url-encoded for the JWS envelope
Reading JWS Envelopes
using Zipwire.ProofPack;
var reader = new JwsEnvelopeReader<MerkleTree>(verifier);
var result = await reader.ReadAsync(jwsJson);
if (result.VerifiedSignatureCount > 0)
{
var merkleTree = result.Payload;
// Use the MerkleTree...
}
Naked Proofs (Unattested)
You can create "naked" proofs without blockchain attestation by putting a MerkleTree
directly into a JWS envelope:
// This creates a JWS envelope with just the MerkleTree as payload
// No blockchain attestation is required
var jwsEnvelope = await builder.BuildAsync(merkleTree);
This produces a JWS envelope where the payload is a properly serialized Merkle Exchange Document, enabling cryptographic signatures without blockchain attestation.
Merkle-inspired Hash Set with Root Hash
ProofPack's innermost object is a Merkle proof-inspired hash set, designed for privacy-preserving, verifiable data exchange. This structure is optimized for small sets (typically <20 items) and selective disclosure, rather than large-scale Merkle proofs.
Structure Overview
- Header: Contains metadata about the format and algorithm
- Leaves: An array of data nodes, each containing:
data
: The actual content (hex-encoded)salt
: Random bytes to prevent preimage attackshash
: Hash of the data + saltcontentType
: MIME type of the data
- Root: The final hash combining all leaf hashes
Security Properties
- Each leaf's data is salted to prevent preimage attacks
- The first leaf must contain metadata about the structure
- At least two leaves are required, with one being valid metadata
- The root hash provides integrity verification
- Private leaves can omit their data while maintaining verifiability
Processing & Verification
Verify the JWS envelope signatures:
- Check that at least one signature is present and valid
- Verify the signature using the appropriate algorithm (e.g., RS256, ES256K)
- Ensure the signature covers both the header and payload
Verify the Merkle tree structure:
- Verify at least two leaves exist
- Decode and validate the first leaf's metadata
- Verify the first leaf's contentType is
application/merkle-exchange-header-3.0+json; charset=utf-8; encoding=hex
- Check each leaf's hash can be recomputed from its data and salt
- Verify the root hash matches the computed combination of all leaf hashes
Document Structure
ProofPack uses a layered approach to security and verification:
- Merkle Exchange Document - The innermost layer containing the actual data:
{
"header": {
"typ": "application/merkle-exchange-3.0+json"
},
"leaves": [
{
"data": "0x7b22616c67223a22534841323536222c226c6561766573223a352c2265786368616e6765223a2270617373706f7274227d",
"salt": "0x3d29e942cc77a7e77dad43bfbcbd5be3",
"hash": "0xe77007d7627eb3eb334a556343a8ef0b5c9582061195441b2d9e18b32501897f",
"contentType": "application/merkle-exchange-header-3.0+json; charset=utf-8; encoding=hex"
},
{
"hash": "0xf4d2c8036badd107e396d4f05c7c6fc174957e4d2107cc3f4aa805f92deeeb63"
}
],
"root": "0x1316fc0f3d76988cb4f660bdf97fff70df7bf90a5ff342ffc3baa09ed3c280e5"
}
- Attested Merkle Exchange Document - Adds blockchain attestation to the root hash:
{
"merkleTree": {
"header": { ... },
"leaves": [ ... ],
"root": "..."
},
"attestation": {
"eas": {
"network": "base-sepolia",
"attestationUid": "...",
"from": "...",
"to": "...",
"schema": { "schemaUid": "...", "name": "PrivateData" }
}
},
"timestamp": "2025-05-23T12:00:00Z",
"nonce": "..."
}
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
.NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.1 is compatible. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- Base64UrlEncoder (>= 1.0.1 && < 2.0.0)
- Evoq.Blockchain (>= 1.5.0 && < 2.0.0)
- System.Text.Json (>= 6.0.10)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Zipwire.ProofPack:
Package | Downloads |
---|---|
Zipwire.ProofPack.Ethereum
Ethereum specializations for ProofPack. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version 0.2.1 of Zipwire.ProofPack.
- Add IAttestationVerifier interface for blockchain attestation verification
- Add StatusOption<T> result type for robust error handling
- Add AttestationVerifierFactory for managing multiple attestation services
- Enhanced AttestedMerkleExchangeReader with factory pattern support
- Improved error handling and validation throughout
- Foundation for EAS (Ethereum Attestation Service) integration