Semantics
Precise definitions for every term in the protocol. Each definition is self-contained — no circular references.
Primitive Concepts
- Field element
- An integer in the BLS12-381 scalar field:
0 ≤ x < qwhereq = 52435875175126190479447740508185965837690552500527637822603658699938581184513. - Commitment
commit(v, r) = Poseidon(v, r)— a binding, hiding hash of valuevwith randomnessr. Givencommit(v, r), no one can determinevwithoutr. Givenvandr, anyone can verifycommit(v, r).- User secret
- A random field element chosen once by the user's phone. Never leaves the phone. The user's entire identity derives from this value.
- User ID
user_id = Poseidon(user_secret)— the public identity of a user. Appears on-chain. Cannot be reversed to recoveruser_secret.
Certificates
- Cap certificate
-
A signed statement: "user
user_idmay spend up tocappoints from this issuer." Signed by the issuer's shop key (EdDSA on Jubjub). Lives on the user's phone. Never published on-chain.Formally:
(user_id, cap, signature)wheresignature = EdDSA.sign(shop_key, Poseidon(user_id, cap)). - Reification certificate
-
A signed statement: "amount
dwas settled on-chain with nonceN, redeemable at this reificator." Signed by the reificator key. Lives on the user's phone.Formally:
(d, nonce, signature)wheresignature = EdDSA.sign(reificator_key, (d, nonce)).
Actors
- Coalition
- The entity that creates the on-chain state, manufactures reificators, and registers shops. Minimal authority — cannot touch user funds or alter spend state. The only destructive action (removing a shop) requires multi-signature from other shops.
- Shop
- A business in the coalition. Has a key pair (
shop_pk,shop_sk). Issues cap certificates (topup). Holds a master key separately from its devices. Can revert pending entries for its reificators. - Reificator
- A stateless hardware device at a cashing point. Contains two burned-in keys (reificator key from coalition, shop key from shop) and a Cardano payment key. Settles proofs on-chain, signs reification certificates, displays amounts for cashers. All state is on-chain.
- Casher
- The human operator at the cashing point. Sees the reified amount, applies discounts, sets topup amounts. No cryptographic role — interacts only through the reificator's screen.
- User
- A customer with a phone. Holds
user_secret, cap certificates, reification certificates, and spend randomness. Generates ZK proofs. Fully anonymous — no registration, no account, no wallet. - Data provider
- An untrusted service that serves Merkle proofs from the off-chain trie data. Verified against the on-chain trie root. Anyone can run one. Paid per query by reificators.
Operations
- Topup
-
The casher awards loyalty points to a user. The reificator signs a new cap certificate with a higher cap. No on-chain transaction. This is the high-frequency, low-value event.
sequenceDiagram participant C as Casher participant R as Reificator participant P as Phone C->>R: set reward amount R->>R: sign cap certificate (shop_key) R->>P: cap certificate Note over P: stores certificate locally - Settlement
-
The reificator submits a user's ZK proof on-chain. The spend trie counter goes up. A pending entry is created in the pending trie. Happens asynchronously — the user is at home.
sequenceDiagram participant P as Phone participant R as Reificator participant DP as Data Provider participant M as MPFS participant L1 as L1 (Trie Root) P->>R: ZK proof (binds d + shop_pk) R->>DP: request Merkle proof for user_id DP->>R: Merkle proof R->>M: settlement request (proof + Merkle proof) M->>L1: settlement tx (atomic trie update) L1->>L1: spend trie: counter += d L1->>L1: pending trie: insert (reificator, nonce, user_id, d) R->>P: reification certificate (nonce, d, reificator_sig) - Reification
-
The act of exposing a settled spend to the physical world. The reificator's screen lights up and the casher sees the amount. This is not a transaction — it is a physical event triggered by verifying that a pending entry exists on-chain.
sequenceDiagram participant P as Phone participant R as Reificator participant DP as Data Provider P->>R: reification certificate R->>R: verify own signature R->>DP: Merkle proof for nonce in pending trie DP->>R: proof (exists) R->>R: screen lights up: "€X.XX" - Redemption
-
The casher acknowledges the reified amount and applies the discount. The pending entry is removed from the trie. This is the second on-chain transaction per spend.
sequenceDiagram participant C as Casher participant R as Reificator participant M as MPFS participant L1 as L1 (Trie Root) C->>R: acknowledge discount R->>M: redemption request (nonce, reificator_sig) M->>L1: redemption tx L1->>L1: pending trie: remove entry - Revert
-
The shop reverses a committed-but-unredeemed spend. The pending entry is removed and the spend counter is rolled back. Only the shop's master key can authorize this. Used after device loss, theft, or malfunction.
sequenceDiagram participant S as Shop (master key) participant M as MPFS participant L1 as L1 (Trie Root) S->>M: revert request (nonce, shop_sig) M->>L1: revert tx L1->>L1: pending trie: remove entry L1->>L1: spend trie: counter -= d
State Transitions
Every spend goes through a lifecycle:
stateDiagram-v2
[*] --> committed: settlement tx
committed --> redeemed: redemption tx (reificator signs)
committed --> reverted: revert tx (shop signs)
redeemed --> [*]
reverted --> [*]
- committed → redeemed: the happy path. Device confirms physical redemption.
- committed → reverted: recovery path. Shop reverses after device failure.
Both terminal states remove the pending entry from the trie. Only the redeemed path keeps the spend counter elevated. The reverted path rolls it back.