Design

Prove one fact, and nothing else

A party cuts a proof of one fact from its own envelope and hands it over as a link or a small file. The outsider checks it against NEAR with no key and no account.

A lender sometimes has to show an outsider one thing from the books. A buyer wants to know the seller holds what it is selling. A fund’s auditor wants to see one interest payment. A bank that lends against a position wants to see the position. Today that is a PDF from the agent. On a private ledger it usually means giving the outsider a seat on the ledger.

In Pari the party cuts a proof from its own envelope. The agent is not asked, and nothing else in the envelope is shown.

How it works

  1. Inside the enclave, each party’s view is a list of facts: what it holds, its cash, each payment, each trade. For the agent, the borrower and the auditor the list also has the register and the outstanding total.
  2. With every action the enclave draws 32 new random bytes for each party, the seed, and puts them inside that party’s sealed envelope. Each fact gets its own salt, HMAC-SHA256 of the fact’s name under the seed, and is hashed with it (sha256). The sha256 of all those hashes together is the party’s commitment. The contract stores it beside the envelope, where anyone can read it.
  3. A proof is one fact in the clear, its salt, the list of fact hashes and the number of the block it was cut at.
  4. To check it, hash the fact with its salt and find the result at its place in the list. Then hash the list and ask a NEAR archival node what envelope(party) returned at that block. The two commitments must be equal.

The check reads the chain as it was at the proof’s block, so a proof stays checkable after the deal has moved on. The page says whether it is still the party’s latest view.

Try it

On your own deployment, after step 6 of the walk in Check it yourself:

  1. Open /lender/alder. In the payments table, press Prove beside the settled payment. You land on /verify and see It holds: Alder was paid 985,833.33 of the 985,833.33 it was owed for interest to 15 Dec 2026. The page’s address is the proof: anyone you send it to sees the same page, and the server uses no key to draw it.
  2. In the box The proof, change one digit of "paid" and press Check against NEAR. You see It does not hold: The fact, its salt and the list of hashes do not belong together.
  3. Back on /lender/alder, under the sealed envelope, Prove what you hold and Prove your cash do the same for those two facts. /agent, /borrower and /auditor have Prove the register and Prove the outstanding total.
  4. In a terminal, npm run e2e leaves the proof of what Alder holds in near/proofs, and npm run verify:proof checks it with no keys. It then changes one digit and shows the proof rejected, and forges the changed fact’s hash into the list and shows the chain’s commitment reject that too.

Checked from a fresh clone

This is npm run verify:proof with no keys, on the proof the recorded run of northwind-14 left:

$ npm run verify:proof

Proof: …/near/proofs/northwind-14.json

What it says
  Party            alder.paridesk.testnet
  Deal             northwind-14, after action 30
  Fact             position
    accrual_start  2027-06-15
    carried        0.00
    principal      40,000,000.00

Checked, with no keys
  ✓ The fact and its salt hash to number 9 of the 12 hashes in the proof.
  ✓ At block 277320067 (2026-11-12 05:33 UTC) ledger.paridesk.testnet
    held the hash of that list as alder.paridesk.testnet's commitment.
  The other 11 hashes are salted. They show that the party's view holds 11 more facts, and nothing about them.
  This is still the party's latest view.

Control: the same proof with one digit of the fact changed
  ✓ Rejected: the fact, its salt and the list of hashes do not belong together.
  ✓ With its hash put into the list as well, so that the arithmetic agrees:
    rejected: at block 277320067 the chain did not hold this commitment for alder.paridesk.testnet.

PASS: the fact is what the enclave put in this party's view, and the proof shows no other.

What a proof shows besides its fact

The party’s account, the deal, the number of the action the view is from, and how many facts the party’s view holds. The other facts are in the proof as salted hashes only. The salts are new with every action and come from a seed only the party can read, so a hash cannot be matched against a guess (“is Alder’s cash 485,833.33?”) or against an older proof. The proof Alder cuts of what it holds contains no payment, no cash balance, no price and no other party’s name; npm run e2e checks exactly that.

What a proof is not

It is not a signature and it is not zero-knowledge: the fact is shown in the clear to whoever holds the proof, and they can pass it on. Its weight comes from the chain: the rules contract stored that commitment from the answer of the one enclave build it pins. It says what the party’s view held at one block, not what is true today.

Two programs that must agree

The enclave and the checker are written separately, in Rust and in TypeScript. One enclave test, test_the_enclave_and_the_proof_checker_agree_on_a_known_view, holds the enclave to the salt, the hash and the commitment the TypeScript checker computed for a known view. And on every load /visibility recomputes each party’s commitment in TypeScript from its opened envelope and compares it with the chain’s: the eighth claim under Checked live.