Proposal: A Native ZK System for Radix
Zero-Knowledge Properties — without Zero-Knowledge Proofs
Proposal for the Radix community
Status: Concept — Open for discussion
Builds on: Proposal: A Native Privacy System for Radix
TL;DR
Radix already has all the primitives needed to offer Zero-Knowledge properties without Zero-Knowledge proofs: standard asymmetric cryptography, hash functions, Scrypto smart contracts, and a resource-oriented model that allows proofs to be materialised as physical objects.
By adding two new native object types — the Stealth Vault and the Stealth Proof Token (StPT) — to the previously published privacy proposal, Radix can cover 9 of the 12 most important ZK use cases documented in the industry, without the years of R&D that classical ZK systems require.
This is not a replacement for ZK-proofs in all cases — the most complex cases will require future cryptographic advances. But it is a pragmatic solution, buildable today, and progressively extensible.
The architecture is modular and composable: each StPT instance is independent, each application can combine several, and new types can be added without modifying the existing foundation.
The question is not whether Radix can have Zero-Knowledge properties. The question is: when do we start?
1. Background: the privacy system
This proposal builds on the privacy system published previously, which introduces three complementary tools:
Tool 1 — Stealth Addresses Each payment is sent to a unique ephemeral address derived from the recipient’s stealth_meta_address, published in their Persona. The recipient scans the network to recognise their payments. An observer sees a random address with no link to any identity.
Tool 2 — Validator Level 1 A validator’s stakers can obtain superfungible XRD — whose traceability link has been broken — via a deposit/withdrawal mechanism based on an NFT Claim Ticket and a random delay. Reserved for stakers, this level is regulatorily defensible and creates a staking incentive.
Tool 3 — Validator Level 2 The same mechanism, open to all users without any staking requirement. Anyone can deposit pseudofungible (traceable) XRD and withdraw superfungible (history-free) XRD.
These three tools form the foundation on which this proposal builds.
2. Zero-Knowledge Properties: what are we talking about?
The general principle
A Zero-Knowledge Proof (ZK-proof) allows one to prove that a statement is true without revealing the information that makes it true.
Classic example:
"I prove that I know the password"
→ without revealing the password
In a blockchain context:
"I prove that I have at least 1000 XRD of collateral"
→ without revealing that I have 847,000
"I prove that I am a member of an eligible group"
→ without revealing who I am within that group
Why it is difficult to implement
Existing ZK systems (Zcash, Aztec, StarkNet…) require:
-
Arithmetic circuits — representing computations as mathematical constraints
-
A trusted setup — costly initial cryptographic ceremony
-
Special cryptographic opcodes — elliptic curves, ZK-friendly hash functions
-
Costly on-chain verification — even optimised, far heavier than an ordinary transaction
This is why every ZK project has required years of R&D and deep protocol modifications.
Our approach: the same properties, without the machinery
This document proposes obtaining the properties of ZK-proofs — proving without revealing — using exclusively existing cryptographic primitives in Radix: hashing, standard asymmetric cryptography, and smart contract logic.
What we use:
✅ Hash functions (already in Radix)
✅ Standard asymmetric cryptography (already in Radix)
✅ Scrypto smart contracts (already in Radix)
✅ Two new native object types (this proposal)
What we do not use:
❌ ZK arithmetic circuits
❌ Trusted setup
❌ Special cryptographic opcodes
❌ Deep protocol modification
3. Elegant integration into Radix
Why Radix is particularly well positioned
Radix’s resource-oriented model — vaults, badges, NonFungibleResources — offers primitives that make this approach natural:
-
Resources are physical objects: they cannot be duplicated, they actually move between vaults. This conservation property is exactly what is needed to materialise proofs.
-
Authorisation rules allow precise definition of who can do what with an object — including
DenyAllfor transfers, which makes a proof non-transferable. -
Personas and stealth addresses (previous proposal) provide the pseudonymous identity infrastructure on which our proofs rely.
The approach: from specific to general
Rather than starting from a theoretical abstraction, we proceeded case by case:
Step 1 — Concrete case: proof of solvency How to prove that one has enough collateral to borrow, without revealing the exact balance? This question led to the design of the Stealth Vault and the Solvency Proof Token.
Step 2 — Generalisation By examining other ZK use cases documented in the industry (group membership, anonymous voting, credit score, timestamped commitment…), a common pattern emerged: all can be resolved by the same basic mechanism.
Step 3 — Generic primitive This pattern was formalised into a single primitive: the Stealth Proof Token (StPT), of which the specific cases are specialised instances.
4. The Stealth Vault
Problem solved
In classical DeFi, borrowing against collateral reveals everything:
Alice wants to borrow 500 USDC:
→ She deposits 1000 XRD into the lending protocol
→ Everyone sees that account_alice deposited 1000 XRD
→ The protocol sees her full wallet
→ Her wealth is exposed
The Stealth Vault solves this problem by allowing Alice to lock her collateral in a component not attributable to her real identity, while remaining verifiable by the lending protocol.
How it works — solvency proof example (SPT)
Alice creates a Stealth Vault via her stealth_meta_address
→ Deposits superfungible XRD (no traceability)
→ The vault automatically issues a StPT of type SPT
→ Alice presents the SPT to the lending protocol
At loan opening, the protocol:
→ Verifies the SPT: does the vault exist? is it locked? correct amount?
→ Creates a liquidation badge tied to this specific vault
(only this protocol can use it to access the vault)
→ This badge also grants the right to modify lock_status
→ Records: vault_address ↔ loan (without knowing who Alice is)
→ Lends 500 USDC to a fresh stealth address of Alice
If liquidation (collateral/debt ratio insufficient):
→ The protocol uses the liquidation badge created at opening
→ Accesses the vault and liquidates the superfungible tokens
→ Repays the loan from the liquidation proceeds
→ The protocol destroys the liquidation badge
→ The Stealth Vault destroys the SPT
If normal repayment:
→ Any stealth address can repay by referencing the loan
— the protocol does not verify who repays
→ The protocol uses its badge to set lock_status → "free"
→ The protocol destroys the liquidation badge
→ Alice proves control of her stealth_meta_address
by signing with her spend_private_key stealth,
directly with the Stealth Vault (not with the protocol)
→ The Stealth Vault releases the tokens to a fresh stealth address
→ The Stealth Vault destroys the SPT
Classic Vault vs Stealth Vault comparison
| Property | Classic vault | Stealth Vault |
|---|---|---|
| Owner | Named account (visible) | Stealth address (non-attributable) |
| Resource type | Visible | Visible |
| Amount | Visible | Visible |
| Deposit history | Traceable to origin | Broken (superfungible tokens) |
| Link to an identity | ||
| Lifetime | Permanent, tied to account | Ephemeral — created for a specific purpose, destroyed after use or expiration |
| Authorisation rules | Single private key | Differentiated: owner key + optional protocol badge |
| Normal withdrawal | Account private key | spend_private_key stealth |
| Forced access (e.g. liquidation) | N/A | Via badge granted at loan opening |
Stealth Vault metadata
Component "StealthVault":
owner : stealth_component_xyz // non-attributable
resource : XRD_superfungible
withdraw_roles : {
normal : RequireProof(spend_private_key_stealth)
liquidation : RequireProof(badge_lending_protocol)
}
deposit_roles : RequireProof(validator_contract)
metadata_roles : {
lock_status : RequireProof(badge_lending_protocol)
}
recall_roles : DenyAll
freeze_roles : DenyAll
metadata : {
stealth_meta_address : "02abc...03def..."
lending_protocol_address : "component_lending_xyz"
lock_status : "free" | "locked"
lock_expiry_epoch : null | epoch
stpt_issued : null | hash(StPT_current)
auto_return_epoch : null | epoch
}
5. The Stealth Proof Token (StPT)
Principle
The StPT is a generic primitive: a non-transferable NonFungibleResource, linked to a stealth_meta_address, issued by a verifier contract, destroyed after use or expiration. It materialises on-chain any verifiable property without revealing the underlying information.
Property to prove
→ Verified by an appropriate verifier contract
→ Materialised in a non-transferable on-chain object
→ Linked to a non-attributable stealth_meta_address
→ Presented to the recipient without revealing identity
→ Destroyed after use or expiration
Each StPT carries a proof type (proof_type) indicating which property it certifies — solvency, membership, transaction, commitment, reputation… This type corresponds to the instances detailed below (SPT, MPT, TPT, CPT, RTP).
The verifier contract
The verifier contract is a Scrypto smart contract deployed on Radix whose role is to:
1. Receive a proof request from a user
2. Verify that the property to prove is actually true
by consulting on-chain state (vault, history, group...)
3. If verification succeeds → mint a StPT to the stealth address
provided by the user
4. Record the nullifier to prevent abuse
It performs no ZK cryptographic computation — it verifies an on-chain condition and materialises the result in a non-transferable object. The contract does not know who owns the destination stealth address: it verifies a condition, mints an object, and stops there.
Depending on the StPT type, the verifier contract is deployed by a different entity:
SPT → deployed by the lending protocol or the Stealth Vault itself
MPT → deployed by the DAO, the validator, or a KYC authority
TPT → deployed by the validator + Radix Engine
CPT → deployed by the auction or prediction protocol
RTP → deployed by the loan history protocol
The contextual nullifier
A StPT must not be usable twice in the same context — for example voting twice in the same ballot, or borrowing twice with the same SPT. But we also want two legitimate uses in different contexts to be impossible to link to each other.
The solution is the contextual nullifier:
When used in context C:
nullifier_C = hash(StPT_id + context_C + usage_epoch)
→ published on-chain, prevents reuse in this context
→ different for each context (vote, loan, access...)
→ two nullifiers from different contexts are mathematically
unlinkable, even if they come from the same StPT
This is the functional equivalent of the nullifier in classical ZK systems — without arithmetic circuits.
Common structure
NonFungibleResource "StPT":
transfer_roles : DenyAll // non-transferable, always
mint_roles : verifier_contract only
burn_roles : automatic at expiration or use
base_data : {
stealth_meta_address : "02abc...03def..."
proof_type : SPT | MPT | TPT | CPT | RTP | ...
commitment : hash(proved_property + secret)
context_nullifier : null ← filled at use
usage_limit : 1 | N
issued_epoch : N
expiry_epoch : N + duration
verifier_address : "verifier_component"
authorized_verifier : "recipient_component" | null
}
extended_data : { ... } // specific to each instance
Coverage of known ZK use cases
The following table presents all ZK use cases documented in the industry, indicating for each whether our system covers them:
Case Instance Trustless Feasible
────────────────────────────────────────────────────────────────────
1. Solvency SPT ✅ ✅ today
2. On-chain membership MPT ✅ ✅ today
3. Legitimate transaction TPT ✅ ✅ today
4. KYC / compliance MPT ⚠️ semi ✅ today
5. Credit score RTP ✅ ✅ today
6. Anonymous vote MPT ✅ ✅ today
7. Confidential input exec. — ❌ ❌ out of scope
8. Non-inclusion (sanctions) — ❌ ❌ out of scope
9. On-chain anti-Sybil MPT ✅ ✅ today
10. Asset ownership MPT/SPT ✅ ✅ today
11. Timestamped commitment CPT ✅ ✅ today
12. Confidential smart contracts — ❌ ❌ out of scope
────────────────────────────────────────────────────────────────────
9 out of 12 cases covered — 3 require real ZK-proofs
Cases 7, 8 and 12 require homomorphic cryptography or real ZK-proofs. They remain out of scope for this proposal.
Each StPT instance presented below is a conceptual starting point. Each would require detailed specification and implementation work to become a real application — this document aims to open the discussion, not to provide a complete implementation.
The instances
SPT — Solvency Proof Token
Case 1: proof of solvency
proof_type : SPT
duration : ~24h
extended_data : {
threshold : 1000
resource_type : XRD
vault_address : "component_stealth_xyz"
lending_protocol : "component_lending_xyz"
}
Verifier: stealth vault (trustless, automatic) Usage: DeFi borrowing, guarantee, bond, collateral
MPT — Membership Proof Token
Cases 2, 4, 6, 9: group membership, KYC, vote, anti-Sybil
proof_type : MPT
duration : variable by context
extended_data : {
group_id : hash(group_definition)
group_commitment : hash(member_list + group_secret)
subtype : STAKER | KYC | VOTER | HUMAN | MEMBER | ...
}
Verifier: group contract (trustless if on-chain, semi-trust if external authority) Usage: DAO governance, pooled KYC, anonymous vote, restricted access
TPT — Transaction Proof Token
Case 3: proof of legitimate transaction
proof_type : TPT
duration : ~1h
extended_data : {
transaction_commitment : hash(amount + recipient + secret)
legitimacy_proof : hash(radix_engine_validation)
superfungibility_proof : hash(nft_claim_ticket_used)
}
Verifier: validator + Radix Engine (trustless) Usage: confidential payment proof, basic regulatory compliance
CPT — Commitment Proof Token
Case 11: timestamped commitment
proof_type : CPT
duration : long (until reveal)
extended_data : {
commitment : hash(commitment + secret + timestamp)
reveal_condition : epoch | event | manual
revealed : false
revealed_value : null ← filled at reveal
}
Verifier: auction or prediction contract Usage: sealed-bid auctions, predictions, timestamped contracts
RTP — Reputation Proof Token
Case 5: credit score / reputation
proof_type : RTP
duration : ~7 days
extended_data : {
score_threshold : 700
score_category : CREDIT | REPAYMENT | ACTIVITY
history_commitment : hash(history + secret)
sample_size : 5
}
Verifier: stealth loan history contract Usage: preferential rates, increased borrowing limits, seller reputation
6. Possible applications
When an application combines multiple StPT types, this implies creating multiple distinct verifier contracts — and possibly multiple Stealth Vaults — each managing its own proof type. These components interact via the badges and nullifiers described above, but remain independent at the protocol level.
BtoC
Decentralised credit scoring (RTP) A user accumulates an on-chain repayment history. Their wallet generates an RTP “score ≥ X” presentable to any lending protocol for better rates — without revealing their identity or full history.
Confidential subscriptions and access (MPT) A user proves they have paid for a subscription without revealing their identity to the service. The service cannot track their activity. Applicable to media, premium services, on-chain private clubs.
Private DAO governance (MPT) DAO members vote without revealing their individual vote. Only the aggregated result is visible. Eliminates strategic voting and social pressure.
Confidential decentralised insurance (SPT + TPT) A policyholder proves that a claim occurred (TPT, via a verifier contract) and exceeds the deductible threshold (SPT, via a separate Stealth Vault), without revealing the details or their identity to the insurance pool. Automatic and trustless settlement.
Decentralised digital identity (MPT — multiple subtypes) A portfolio of MPTs represents a user’s digital identity: “adult ✓”, “EU citizen ✓”, “not sanctioned ✓”… Selectively presentable by context — a casino receives just “adult”, a bank receives “not sanctioned”, without ever revealing the name.
Confidential marketplace (CPT + TPT) Buyer and seller commit a price off-chain via CPT (auction contract), then prove via TPT (separate verifier contract) that the exact payment occurred. The real price is never visible on-chain — eliminates front-running on NFT or real-asset token markets.
Decentralised payroll and HR (SPT + TPT) An employer proves payroll funds are available (SPT via Stealth Vault) without revealing total treasury. Each salary is provable (TPT via separate verifier contract) without revealing other employees’ salaries. Applicable to DAOs paying anonymous contributors.
Confidential seller reputation (RTP) On a decentralised marketplace, a seller proves their reputation score without revealing their full sales history or volumes. The buyer has confidence, the seller keeps their competitive edge confidential.
BtoB
Confidential invoicing (TPT + CPT) Two companies prove that a payment corresponds to an invoice without revealing amounts or identities. The CPT timestamps the commitment to the invoice before payment, the TPT proves the payment occurred — each proof managed by its own verifier contract. Applicable to NDA contracts and tenders.
Supply chain financing (SPT + RTP) A supplier proves their solvency (SPT via Stealth Vault) and payment history (RTP via history contract) to a factor without revealing their other clients or order book. Two distinct verifier contracts, a single stealth identity.
Selective financial audit (SPT + TPT) A company proves to an auditor that its reserves exceed a regulatory threshold (SPT via Stealth Vault) and that its transactions are legitimate (TPT), without revealing exact balances. Applicable for Basel III, Solvency II, stablecoin reserves.
Sealed-bid B2B auctions (CPT) Multiple companies bid for a contract. Bids are committed on-chain via CPT and revealed simultaneously — nobody can adjust their bid based on competitors’ offers.
Confidential market data sharing (MPT) A consortium of companies shares aggregated data. Each member proves membership via MPT without revealing their identity to others or the group composition to outsiders.
Anonymous interbank lending (SPT + RTP) A bank proves its solvency (SPT via Stealth Vault) and credit score (RTP) to a counterparty for an overnight loan without revealing its full balance sheet. Reduces the risk of bank run contagion.
Pooled KYC compliance (MPT — KYC subtype) A client proves to a new institution that they have already been verified by a member of a KYC consortium, without revealing which one or the details of their verification.
7. What is needed to implement
At the Radix protocol level:
✅ Builds on stealth addresses and validators
(see privacy proposal)
✅ No core protocol modification for the StPT
✅ No core protocol modification for the Stealth Vault
Two new native object types to create (new standards):
✨ NonFungibleResource "StPT" — new resource definition
with its authorisation rules and data schema
✨ Component "StealthVault" — new Scrypto component type
with its differentiated withdraw rules and metadata
These two objects are primitives in the Radix sense:
reusable, standardised building blocks
on which applications can rely.
They do not require modifying the Radix Engine —
they are expressed in the existing Scrypto language.
At the smart contract level:
✅ Verifier contracts per StPT type (Scrypto)
✅ Contextual nullifier contract (Scrypto)
✅ Specialised instances per type (Scrypto)
At the wallet level:
✅ Management of StPTs received on stealth addresses
✅ Presentation interface to the recipient
✅ Automatic rotation after use
Dependencies:
✅ Stealth address system (Tool 1)
✅ Superfungible tokens for SPT and TPT (Tools 2 & 3)
❌ No ZK-proofs
❌ No deep protocol modification
This document is a conceptual proposal open for discussion. Each described mechanism would require detailed technical specification and a security audit before any production implementation. Community contributions are welcome.