@clearproof/content 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/content/explainers/pilot-proof-public-signals.md +80 -0
- package/content/explainers/portable-evidence-review.md +103 -0
- package/content/explainers/usd-cents-without-a-price-feed.md +106 -0
- package/content/explainers/verify-independently.md +106 -0
- package/content/explainers/what-clearproof-does.md +92 -0
- package/content/explainers/who-verifies-what.md +86 -0
- package/content/recipes/deploy-contracts.md +45 -0
- package/content/recipes/full-walkthrough.md +84 -0
- package/content/recipes/generate-proof.md +43 -0
- package/content/recipes/update-sanctions.md +35 -0
- package/content/recipes/verify-onchain.md +41 -0
- package/content/recipes/verify-proof.md +36 -0
- package/content/signals.yaml +128 -0
- package/content/topics/api.md +61 -0
- package/content/topics/architecture.md +50 -0
- package/content/topics/circuits.md +66 -0
- package/content/topics/contracts.md +60 -0
- package/content/topics/gdpr.md +36 -0
- package/content/topics/quickstart.md +77 -0
- package/content/topics/sdk.md +56 -0
- package/content/topics/security.md +33 -0
- package/content/topics/troubleshooting.md +109 -0
- package/content/updates/2026-09-09-adoption-roadmap.md +27 -0
- package/content/updates/2026-09-12-full-walkthrough.md +31 -0
- package/content/updates/2026-09-12-npm-status.md +27 -0
- package/content/updates/2026-09-12-proof-boundaries.md +40 -0
- package/content/updates/2026-09-21-sanctions-schedule.md +43 -0
- package/content/updates/2026-09-25-pilot-transfer-v3.md +60 -0
- package/dist/explainers.d.ts +29 -0
- package/dist/explainers.d.ts.map +1 -0
- package/dist/explainers.js +71 -0
- package/dist/explainers.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/parser.d.ts +25 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +97 -0
- package/dist/parser.js.map +1 -0
- package/dist/recipes.d.ts +28 -0
- package/dist/recipes.d.ts.map +1 -0
- package/dist/recipes.js +103 -0
- package/dist/recipes.js.map +1 -0
- package/dist/signals.d.ts +18 -0
- package/dist/signals.d.ts.map +1 -0
- package/dist/signals.js +34 -0
- package/dist/signals.js.map +1 -0
- package/dist/topics.d.ts +18 -0
- package/dist/topics.d.ts.map +1 -0
- package/dist/topics.js +41 -0
- package/dist/topics.js.map +1 -0
- package/dist/updates.d.ts +27 -0
- package/dist/updates.d.ts.map +1 -0
- package/dist/updates.js +69 -0
- package/dist/updates.js.map +1 -0
- package/package.json +42 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: UP-EX-002
|
|
3
|
+
title: The pilot proof's eight public signals — what they show and what they hide
|
|
4
|
+
date: 2026-09-16
|
|
5
|
+
publishAfter: 2026-09-16T00:00:00Z
|
|
6
|
+
sourceCommit: caa15cb49a3d9da8f0978dcfaebf5bf958161b67
|
|
7
|
+
claimRefs:
|
|
8
|
+
- README.md
|
|
9
|
+
- specs/pilot-transfer-v3.md
|
|
10
|
+
- packages/content/content/topics/security.md
|
|
11
|
+
- packages/content/content/topics/circuits.md
|
|
12
|
+
status: approved
|
|
13
|
+
summary: A Clearproof pilot proof publishes exactly eight public signals. Reading them is the fastest way to understand what a verifier learns without the encrypted envelope — and what it still cannot conclude.
|
|
14
|
+
canonical: /explainers/pilot-proof-public-signals
|
|
15
|
+
templateVersion: explainer-v1
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
Every Groth16 proof publishes a fixed array of public signals. In a Travel Rule
|
|
19
|
+
system those signals are metadata that any verifier — and anyone who sees the
|
|
20
|
+
proof — can read. So before evaluating any privacy claim, it is worth reading
|
|
21
|
+
the actual array. Clearproof's current pilot profile, `pilot-transfer-v3`, has
|
|
22
|
+
exactly eight. The
|
|
23
|
+
[public statement](https://github.com/repfigit/clearproof/blob/main/specs/pilot-transfer-v3.md)
|
|
24
|
+
in the repository lists them in mandatory order:
|
|
25
|
+
|
|
26
|
+
| Index | Signal |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| 0 | `projection_commitment` |
|
|
29
|
+
| 1 | `authorized_issuer_root` |
|
|
30
|
+
| 2 | `sanctions_root` |
|
|
31
|
+
| 3 | `authorization_nullifier` |
|
|
32
|
+
| 4 | `evaluated_at` |
|
|
33
|
+
| 5 | `proof_expires_at` |
|
|
34
|
+
| 6 | `domain_chain_id` |
|
|
35
|
+
| 7 | `domain_registry` |
|
|
36
|
+
|
|
37
|
+
## What a verifier learns from these alone
|
|
38
|
+
|
|
39
|
+
The three root signals (`authorized_issuer_root`, `sanctions_root`) and the
|
|
40
|
+
timestamp pair (`evaluated_at`, `proof_expires_at`) say which sanctions tree,
|
|
41
|
+
issuer set and validity window the proof was built against. The domain pair
|
|
42
|
+
(`domain_chain_id`, `domain_registry`) pins the exact chain and registry
|
|
43
|
+
deployment the proof is bound to, which is what stops a proof made for one
|
|
44
|
+
deployment being replayed against another.
|
|
45
|
+
|
|
46
|
+
Two signals deserve closer reading. `projection_commitment` is a Poseidon hash
|
|
47
|
+
over the 48-field canonical transfer projection, the exact credential
|
|
48
|
+
commitment and the issuance root — it reveals nothing about the fields, but it
|
|
49
|
+
does mean the verifier must independently reconstruct the expected commitment
|
|
50
|
+
from its own authenticated records before the proof means anything.
|
|
51
|
+
`authorization_nullifier` is deliberately unlinkable-by-design across
|
|
52
|
+
contexts: it prevents the same holder authorization being consumed twice
|
|
53
|
+
without identifying the holder.
|
|
54
|
+
|
|
55
|
+
## What is deliberately not public
|
|
56
|
+
|
|
57
|
+
The v3 profile carries **no public amount tier and no SAR advisory flag**. The
|
|
58
|
+
[README](https://github.com/repfigit/clearproof/blob/main/README.md) is
|
|
59
|
+
explicit about this, and about the contrast: the older 16-signal
|
|
60
|
+
`compliance.circom` demo profile publishes amount-tier and SAR metadata among
|
|
61
|
+
its sixteen values. The README warns never to select artifacts by signal count
|
|
62
|
+
alone and never to reinterpret legacy proofs as current pilot authorization —
|
|
63
|
+
a real risk, because both profiles have passing tests and committed manifests.
|
|
64
|
+
|
|
65
|
+
## The boundary that matters more than the signal list
|
|
66
|
+
|
|
67
|
+
The security documentation states the boundary directly: public signals expose
|
|
68
|
+
metadata, and omitting a named field from a bridge payload does not conceal
|
|
69
|
+
information that remains in the public-signal array. A valid proof establishes
|
|
70
|
+
its encoded statement — nothing more. Proof verification alone neither
|
|
71
|
+
authenticates the verifier's reconstructed records nor establishes current
|
|
72
|
+
roots, revocation, policy compliance or legal compliance. Current circuits and
|
|
73
|
+
contracts have not completed an independent audit, and generated proving keys
|
|
74
|
+
are explicitly unapproved development artifacts.
|
|
75
|
+
|
|
76
|
+
If you are evaluating the system, the signal array is where to start: it tells
|
|
77
|
+
you exactly what every observer learns, before any encrypted envelope is even
|
|
78
|
+
opened. The full statement, including the private 48-field projection and the
|
|
79
|
+
subcircuit binding, is in
|
|
80
|
+
[specs/pilot-transfer-v3.md](https://github.com/repfigit/clearproof/blob/main/specs/pilot-transfer-v3.md).
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: UP-EX-006
|
|
3
|
+
title: Portable evidence review — taking the receipt out of the operator's hands
|
|
4
|
+
date: 2026-09-28
|
|
5
|
+
publishAfter: 2026-09-28T00:00:00Z
|
|
6
|
+
sourceCommit: 61d6b1f2d133ce32796efa015cdac34c06b266b0
|
|
7
|
+
claimRefs:
|
|
8
|
+
- README.md
|
|
9
|
+
- docs/operations/local-pilot-acceptance.md
|
|
10
|
+
- src/services/evidence_export.py
|
|
11
|
+
- src/prover/history_cli.py
|
|
12
|
+
- src/prover/history.py
|
|
13
|
+
- src/chain/audit_mirror.py
|
|
14
|
+
status: approved
|
|
15
|
+
summary: Clearproof's retained evidence is exported as a recipient-encrypted HPKE bundle and reviewed offline by a process that disables its own networking, with every pin supplied by the reviewer rather than the exported bundle. This explainer walks through that path and the three outcomes it can report.
|
|
16
|
+
canonical: /explainers/portable-evidence-review
|
|
17
|
+
templateVersion: explainer-v1
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
An export feature can be cosmetic: a button that hands you a file the
|
|
21
|
+
operator's servers must interpret. The question worth asking of any compliance
|
|
22
|
+
system is whether retained evidence can be carried to a reviewer and checked
|
|
23
|
+
without the operator in the loop. In Clearproof's current source, that path
|
|
24
|
+
exists end to end, and its trust placement is the interesting part: the
|
|
25
|
+
reviewer, not the export, decides what counts as evidence.
|
|
26
|
+
|
|
27
|
+
## The export is encrypted to a recipient, not to the operator
|
|
28
|
+
|
|
29
|
+
The local pilot's acceptance run retains a `history.encrypted.json` file —
|
|
30
|
+
described in [the acceptance guide](https://github.com/repfigit/clearproof/blob/main/docs/operations/local-pilot-acceptance.md)
|
|
31
|
+
as the "recipient-encrypted historical evidence export." In source, the export
|
|
32
|
+
service (`src/services/evidence_export.py`) builds the bundle only for a
|
|
33
|
+
principal holding both `evidence:export` and `evidence:decrypt` roles, only
|
|
34
|
+
while the configured recipient's approval window is open, and only against a
|
|
35
|
+
pinned authorization receipt whose identity digests, transfer and context
|
|
36
|
+
digests must match across the receipt, the proof and the evidence manifest.
|
|
37
|
+
Every referenced record is re-read and compared byte-for-byte against its
|
|
38
|
+
pinned SHA-256, up to a hard limit of 80 records.
|
|
39
|
+
|
|
40
|
+
The bundle is then sealed with [HPKE (RFC
|
|
41
|
+
9180)](https://github.com/repfigit/clearproof/blob/main/src/sar/hpke_envelope.py)
|
|
42
|
+
to the recipient's X25519 public key, with the export binding — tenant,
|
|
43
|
+
receipt, reviewer, key id, export time — bound as associated data. The
|
|
44
|
+
operator cannot later open this file; only the holder of the reviewer key can.
|
|
45
|
+
And the private half of that key is never captured in reports: the acceptance
|
|
46
|
+
guide states plainly that it stays in `pilot/private/` and must not be
|
|
47
|
+
published.
|
|
48
|
+
|
|
49
|
+
## The reviewer supplies the pins; the bundle never does
|
|
50
|
+
|
|
51
|
+
`src/prover/history.py` says it in one line: "Pins and verifier come from the
|
|
52
|
+
reviewer, never from the exported bundle." The offline CLI (`src/prover/history_cli.py`)
|
|
53
|
+
takes the encrypted bundle, a separately configured reviewer trust file, and an
|
|
54
|
+
explicit list of trusted inputs — the artifact directory, the pinned snarkjs
|
|
55
|
+
runtime bundle, the Node executable, and the review clock. `open_evidence_bundle`
|
|
56
|
+
decrypts with the recipient's private key and immediately qualifies itself: the
|
|
57
|
+
docstring notes decryption "does not validate historical compliance or sender
|
|
58
|
+
identity." Decryption is a door, not a verdict.
|
|
59
|
+
|
|
60
|
+
The integrity pass that follows binds everything together: the receipt, proof
|
|
61
|
+
and manifest digests must agree, the retained proof must hash to its pinned
|
|
62
|
+
digest, the nullifier and expiry signals must match the receipt, and the
|
|
63
|
+
captured configuration — artifact manifest, verification key, asset registry,
|
|
64
|
+
valuation approval, root pins — must match both its recorded digests and the
|
|
65
|
+
artifacts the reviewer chose to trust. If a pinned record is missing entirely,
|
|
66
|
+
the result is `indeterminate` with `missing_evidence`, not a best-effort pass.
|
|
67
|
+
|
|
68
|
+
## What the offline review can conclude
|
|
69
|
+
|
|
70
|
+
`inspect_history_bundle` reports one of three outcomes, each with named
|
|
71
|
+
reasons: `supported`, `indeterminate`, or `contradicted`. Six independent
|
|
72
|
+
authorities stand between decryption and a `supported` verdict — statement
|
|
73
|
+
reconstruction at the claimed authorization time, policy replay from pinned
|
|
74
|
+
fact records, the signed decision attestation, historical non-revocation
|
|
75
|
+
status, independent timing evidence, and the information authority's signed
|
|
76
|
+
approval. Any authority the reviewer has not configured leaves the outcome
|
|
77
|
+
`indeterminate` with the specific gap named (`decision_authority_unverified`,
|
|
78
|
+
`historical_revocation_evidence_missing`, and so on). A mismatch — wrong
|
|
79
|
+
signals, invalid pairing, bad decision or information signature — is
|
|
80
|
+
`contradicted`.
|
|
81
|
+
|
|
82
|
+
That vocabulary is the design's honesty made mechanical: the reviewer cannot
|
|
83
|
+
get a clean bill of health by skipping checks, because each skipped check is
|
|
84
|
+
visible in the output as a named gap.
|
|
85
|
+
|
|
86
|
+
## The mirror, and what none of this establishes
|
|
87
|
+
|
|
88
|
+
Alongside on-chain events, `src/chain/audit_mirror.py` writes an append-only
|
|
89
|
+
JSON Lines audit mirror — for regulatory examination, offline access during
|
|
90
|
+
chain downtime, and context not stored on-chain — where every record carries
|
|
91
|
+
the SHA-256 of the previous record, forming a tamper-evident hash chain that
|
|
92
|
+
`verify_integrity` can re-check. Each writer derives the predecessor from the
|
|
93
|
+
file while holding the lock through fsync; no cached tail is trusted.
|
|
94
|
+
|
|
95
|
+
The boundaries stay explicit. This is a local source-checkout workflow with
|
|
96
|
+
synthetic fixtures — the acceptance guide warns that a copied trust file is
|
|
97
|
+
not an independently approved production trust configuration, that changing
|
|
98
|
+
the review clock "asks a different historical trust question," and that the
|
|
99
|
+
M0–M5 acceptance is complete only for the local scope. Live provider access,
|
|
100
|
+
customer validation and production assurance remain follow-on gates. What the
|
|
101
|
+
source does establish is the shape: evidence that travels encrypted to a named
|
|
102
|
+
reviewer, with trust placed in the reviewer's pins rather than the operator's
|
|
103
|
+
say-so.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: UP-EX-005
|
|
3
|
+
title: USD cents without a price feed — how the pilot proof handles valuation
|
|
4
|
+
date: 2026-09-22
|
|
5
|
+
publishAfter: 2026-09-22T00:00:00Z
|
|
6
|
+
sourceCommit: dfda3eab85b9ab2e664826e05ee455e4c0cdad1c
|
|
7
|
+
claimRefs:
|
|
8
|
+
- docs/adr/0007-scoped-valuation-approvals.md
|
|
9
|
+
- src/protocol/valuation_approval.py
|
|
10
|
+
- src/prover/pilot_valuation.py
|
|
11
|
+
- src/protocol/transfer.py
|
|
12
|
+
status: approved
|
|
13
|
+
summary: The pilot circuit proves exact USD-cent arithmetic over a quoted price, but no oracle tells it what the price is. Reading the scoped valuation approval design shows where pricing trust actually lives — and why a proof of arithmetic is not a proof of price.
|
|
14
|
+
canonical: /explainers/usd-cents-without-a-price-feed
|
|
15
|
+
templateVersion: explainer-v1
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
Travel Rule compliance turns a transfer of tokens into a question about money:
|
|
19
|
+
how much is this worth in USD, and does it cross a reporting threshold? That
|
|
20
|
+
question hides a hard dependency. Somewhere, something must assert a price. In
|
|
21
|
+
Clearproof's current source, that "something" is not an oracle inside the
|
|
22
|
+
circuit — it is a signed approval checked outside it, and the source is explicit
|
|
23
|
+
that its truthfulness remains an assumption. This explainer walks through how a
|
|
24
|
+
USD valuation enters the pilot proof, what the circuit proves about it, and what
|
|
25
|
+
it deliberately does not.
|
|
26
|
+
|
|
27
|
+
## The quote is a rational number, not a feed
|
|
28
|
+
|
|
29
|
+
The pilot transfer record carries a `Valuation` (`clearproof-valuation-v1`,
|
|
30
|
+
defined in
|
|
31
|
+
[src/protocol/transfer.py](https://github.com/repfigit/clearproof/blob/main/src/protocol/transfer.py)):
|
|
32
|
+
a rational USD-cents-per-base-unit price as an exact 128-bit numerator over
|
|
33
|
+
denominator, an asset ID, observation and expiry times, a source ID and a
|
|
34
|
+
SHA-256 digest of the source evidence. The comment in the source says the ratio
|
|
35
|
+
must be reduced and that no stablecoin peg is assumed. Nothing in the record
|
|
36
|
+
claims the price is current, best, or even true — it claims only what was
|
|
37
|
+
observed, from which source, with which evidence digest, over which interval.
|
|
38
|
+
|
|
39
|
+
## The circuit proves arithmetic, not price
|
|
40
|
+
|
|
41
|
+
Inside the composed pilot circuit, the valuation sub-problem is pure integer
|
|
42
|
+
arithmetic (`src/prover/pilot_valuation.py`): multiply the transfer amount by
|
|
43
|
+
the numerator, divide by the denominator, and constrain both the USD-cent
|
|
44
|
+
quotient and the remainder. The remainder is constrained so the quotient is the
|
|
45
|
+
exact floor of the division — not an approximation the prover can nudge. The
|
|
46
|
+
reduced ratio itself participates in the private projection, so a proof made
|
|
47
|
+
with one price cannot be re-verified against a different one.
|
|
48
|
+
|
|
49
|
+
But no Circom constraint makes the numerator or denominator equal to a market
|
|
50
|
+
price. The circuit proves: "given these inputs, the USD cents figure follows."
|
|
51
|
+
It cannot prove: "these inputs are what the market said."
|
|
52
|
+
|
|
53
|
+
## The approval layer: signatures, not oracles
|
|
54
|
+
|
|
55
|
+
Commit 2a3dbc7 introduced the
|
|
56
|
+
[`ValuationApproval`](https://github.com/repfigit/clearproof/blob/main/src/protocol/valuation_approval.py)
|
|
57
|
+
layer. An authority signs the complete valuation — the quote, tenant, asset
|
|
58
|
+
catalog digest, signing time and key ID — under a dedicated Ed25519 domain
|
|
59
|
+
(`clearproof/valuation-approval/v1`, with a separate key domain for
|
|
60
|
+
`clearproof/valuation-key/v1`). The approval binds the quote's full validity
|
|
61
|
+
interval: an approval must be signed while the quote is live, and freshly
|
|
62
|
+
signing an old observation cannot reset its age.
|
|
63
|
+
|
|
64
|
+
Operator configuration pins each public key to a tenant, a catalog digest,
|
|
65
|
+
exact chain-qualified assets, exact source IDs and a key validity interval.
|
|
66
|
+
Verification checks the quote against the trusted catalog, tenant, signing
|
|
67
|
+
time, expiry, key interval, source and asset scope, and the signature itself.
|
|
68
|
+
|
|
69
|
+
[ADR 0007](https://github.com/repfigit/clearproof/blob/main/docs/adr/0007-scoped-valuation-approvals.md)
|
|
70
|
+
is explicit about the boundary: "The signing authority must validate the source
|
|
71
|
+
evidence and correct asset/base unit interpretation before signing... The
|
|
72
|
+
authority's pricing truthfulness is an explicit trust assumption. No stablecoin
|
|
73
|
+
peg is inferred. This approves a scoped quote within configured bounds, not
|
|
74
|
+
necessarily the latest quote, a business policy, legal compliance or
|
|
75
|
+
settlement."
|
|
76
|
+
|
|
77
|
+
## Why the signature is checked outside the circuit
|
|
78
|
+
|
|
79
|
+
The Ed25519 signature verification happens in the application layer, not
|
|
80
|
+
inside the Circom circuit. ADR 0007 says this directly: "Ed25519 signatures are
|
|
81
|
+
verified outside the circuit; they are not claimed to be ZK-verified." Inside
|
|
82
|
+
the circuit, the signed quote's operands feed the projection; the application
|
|
83
|
+
verifier independently re-validates the quote using its authenticated tenant
|
|
84
|
+
and actual clock before accepting the projection.
|
|
85
|
+
|
|
86
|
+
This split matters for evaluation. A proof says the arithmetic is right for the
|
|
87
|
+
bound quote. The approval says an operator-chosen authority endorsed the quote.
|
|
88
|
+
Neither says the quote reflects any market. That three-way split — arithmetic,
|
|
89
|
+
endorsement, truth — is the honest description of the pilot's pricing boundary.
|
|
90
|
+
|
|
91
|
+
## What this means for an evaluator
|
|
92
|
+
|
|
93
|
+
If you evaluate a system that claims ZK Travel Rule compliance, ask where the
|
|
94
|
+
price comes from. A useful checklist, grounded in this source:
|
|
95
|
+
|
|
96
|
+
- Is the quote an exact rational with evidence digest and validity interval, or
|
|
97
|
+
a floating-point number that could silently lose precision?
|
|
98
|
+
- Who signs the approval, and what are they trusted to know?
|
|
99
|
+
- Is the signature verified in-circuit, or is that verification honestly
|
|
100
|
+
described as application-layer?
|
|
101
|
+
- Does the documentation claim the circuit proves price truth, or does it
|
|
102
|
+
state, as ADR 0007 does, that pricing truthfulness is a trust assumption?
|
|
103
|
+
|
|
104
|
+
Clearproof's current source takes the fourth position, and states it. That
|
|
105
|
+
statement is not a weakness in the design — it is the design making its trust
|
|
106
|
+
boundary visible instead of hiding it inside a proof that cannot carry it.
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: UP-EX-004
|
|
3
|
+
title: Verifying a Clearproof proof without trusting Clearproof
|
|
4
|
+
date: 2026-09-21
|
|
5
|
+
publishAfter: 2026-09-21T00:00:00Z
|
|
6
|
+
sourceCommit: cd63c3a06b978b5401ff9641260882c96fa31037
|
|
7
|
+
claimRefs:
|
|
8
|
+
- packages/proof/src/verifier.ts
|
|
9
|
+
- packages/proof/src/thresholds.ts
|
|
10
|
+
- packages/contracts/contracts/ComplianceRegistry.sol
|
|
11
|
+
- README.md
|
|
12
|
+
status: approved
|
|
13
|
+
summary: Clearproof's TypeScript SDK ships no baked-in proving or verification keys, and the CLI's verify command takes a proof file plus any verification key you point it at. This explainer walks through what an independent verifier can check — and the one signal block that a pairing check alone would let a prover abuse.
|
|
14
|
+
canonical: /explainers/verify-independently
|
|
15
|
+
templateVersion: explainer-v1
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
*Scope: this explainer walks through the SDK's `verifyProof` path for the
|
|
19
|
+
legacy 16-signal demo profile. Current `pilot-transfer-v3` proofs publish eight
|
|
20
|
+
values with no tier thresholds or review flag, and are checked by the pilot's
|
|
21
|
+
authorization service; see [the eight public signals](/explainers/pilot-proof-public-signals).*
|
|
22
|
+
|
|
23
|
+
A fair question for any compliance tool: do you have to trust the vendor to
|
|
24
|
+
check its own proofs? In Clearproof's current source, the answer is no —
|
|
25
|
+
verification is caller-supplied and separately runnable. This explainer walks
|
|
26
|
+
through what an independent verifier can check with only the public source, the
|
|
27
|
+
proof, and a verification key, and where the checks are stricter than a bare
|
|
28
|
+
pairing check.
|
|
29
|
+
|
|
30
|
+
## No baked-in keys
|
|
31
|
+
|
|
32
|
+
The [`@clearproof/proof`](https://github.com/repfigit/clearproof/blob/main/packages/proof/AGENTS.md)
|
|
33
|
+
SDK has **no baked-in artifacts**. `verifyProof` reads the verification key
|
|
34
|
+
from a caller-supplied `vkeyPath` and hands the proof, the public signals and
|
|
35
|
+
that key straight to `snarkjs.groth16.verify`. Nothing about the result depends
|
|
36
|
+
on a Clearproof-operated service. The CLI's `verify` command follows the same
|
|
37
|
+
shape: `--proof <file>` plus an `--artifacts <dir>` the caller controls, and it
|
|
38
|
+
exits non-zero when verification fails.
|
|
39
|
+
|
|
40
|
+
That design has a consequence worth stating: the security of a verification
|
|
41
|
+
inherits the provenance of the verification key. An independent verifier
|
|
42
|
+
should obtain `verification_key.json` from a source it controls or has
|
|
43
|
+
audited — the project's own documentation notes that production proving keys
|
|
44
|
+
are expected to come from a documented multi-party ceremony, and that
|
|
45
|
+
development artifacts are local-only and not safe for production. The tool
|
|
46
|
+
does not make that choice for you; it refuses to hide it.
|
|
47
|
+
|
|
48
|
+
## What a pairing check alone would miss
|
|
49
|
+
|
|
50
|
+
The circuit takes the tier thresholds (`tier2_threshold`, `tier3_threshold`,
|
|
51
|
+
`tier4_threshold` — public signals 8 through 10) as **unconstrained public
|
|
52
|
+
inputs**. The prover chooses them. A proof could therefore be cryptographically
|
|
53
|
+
valid while embedding an arbitrarily high `tier2_threshold`, landing any
|
|
54
|
+
transfer amount in tier 1 and defeating both the tier attestation and the SAR
|
|
55
|
+
review flag.
|
|
56
|
+
|
|
57
|
+
Clearproof's verifier handles this explicitly rather than leaving it to the
|
|
58
|
+
caller: `verifyProof` returns `valid = proofValid && thresholdsBound`, where
|
|
59
|
+
`thresholdsBound` checks the submitted thresholds against the jurisdiction
|
|
60
|
+
table in [`packages/proof/src/thresholds.ts`](https://github.com/repfigit/clearproof/blob/main/packages/proof/src/thresholds.ts).
|
|
61
|
+
That module's own comment is the design rationale: these thresholds are a
|
|
62
|
+
*consensus parameter*, not a local preference — if the table disagrees with the
|
|
63
|
+
Python SDK or the on-chain `ComplianceRegistry`, proofs will verify in one
|
|
64
|
+
place and fail in another.
|
|
65
|
+
|
|
66
|
+
The on-chain registry enforces the same discipline. `ComplianceRegistry`'s
|
|
67
|
+
`verifyAndRecord` deliberately rejects any proof whose thresholds disagree
|
|
68
|
+
with the table stored on-chain, and its threshold-setting function reverts if
|
|
69
|
+
the table is not strictly ordered (`tier2 < tier3 < tier4`), because an
|
|
70
|
+
out-of-order table would silently make some tiers unreachable.
|
|
71
|
+
|
|
72
|
+
## The other signals an independent verifier can read
|
|
73
|
+
|
|
74
|
+
Beyond the two interpreted outputs — `publicSignals[0]` is `is_compliant`,
|
|
75
|
+
`publicSignals[1]` is `sar_review_flag` — the full signal array is returned
|
|
76
|
+
with the verification result, so a reviewer can check:
|
|
77
|
+
|
|
78
|
+
- **Jurisdiction** (signal 6), decodable from its big-endian ASCII value
|
|
79
|
+
("US" → `0x5553`); a value that is not two uppercase ASCII letters decodes
|
|
80
|
+
to `null` rather than a plausible-looking code.
|
|
81
|
+
- **Jurisdiction–VASP consistency**, via the optional
|
|
82
|
+
`expectedJurisdiction` argument. The result distinguishes a real mismatch
|
|
83
|
+
from *unverified*: with no expected jurisdiction supplied,
|
|
84
|
+
`jurisdictionMatchesVASP` is `null`, never silently `true`.
|
|
85
|
+
- **Rejection reasons**: the result carries explicit `rejectionReasons`
|
|
86
|
+
(`groth16_invalid`, `threshold_mismatch`) instead of a bare boolean, so a
|
|
87
|
+
failed verification says *why*.
|
|
88
|
+
|
|
89
|
+
## What independent verification does not establish
|
|
90
|
+
|
|
91
|
+
A valid verification is a statement about one proof against one key. It does
|
|
92
|
+
not establish that the input commitments behind the proof came from trusted
|
|
93
|
+
records, that the sanctions root is current (the root is relayed across
|
|
94
|
+
deployed chains and staleness is a live deployment question), or that any
|
|
95
|
+
counterparty's policy obligations are met. Those remain the registry and
|
|
96
|
+
application checks described in the [previous
|
|
97
|
+
explainer](/explainers/who-verifies-what).
|
|
98
|
+
|
|
99
|
+
## The practical takeaway
|
|
100
|
+
|
|
101
|
+
For an evaluator, the check is concrete and runnable today: take a proof file,
|
|
102
|
+
a verification key from a source you control, and run the CLI's `verify`
|
|
103
|
+
command — the same pairing check the project itself relies on, with the
|
|
104
|
+
threshold-binding check that a bare snarkjs call would skip. The source makes
|
|
105
|
+
that path deliberately short, and deliberately honest about what a valid proof
|
|
106
|
+
still leaves open.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: UP-EX-001
|
|
3
|
+
title: What Clearproof does — and what a valid proof does not establish
|
|
4
|
+
date: 2026-09-13
|
|
5
|
+
publishAfter: 2026-09-13T20:30:00Z
|
|
6
|
+
sourceCommit: 4ed9a6ac19bbb9b479dc271b148731d1ecb04cb0
|
|
7
|
+
claimRefs:
|
|
8
|
+
- README.md
|
|
9
|
+
- docs/ADOPTION_ROADMAP.md
|
|
10
|
+
- packages/content/content/topics/security.md
|
|
11
|
+
- packages/content/content/topics/quickstart.md
|
|
12
|
+
status: approved
|
|
13
|
+
summary: Clearproof combines scoped zero-knowledge statements, encrypted transfer information, policy decisions and retained evidence for controlled evaluation. This explainer walks through what that means in the current source, and where the proof's guarantee stops.
|
|
14
|
+
canonical: /explainers/what-clearproof-does
|
|
15
|
+
templateVersion: explainer-v1
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
Clearproof is an open-source project for privacy-preserving crypto transfer
|
|
19
|
+
evidence. Its [README](https://github.com/repfigit/clearproof/blob/main/README.md)
|
|
20
|
+
states the scope plainly: scoped zero-knowledge statements, encrypted transfer
|
|
21
|
+
information, policy decisions and retained evidence for controlled evaluation by
|
|
22
|
+
stablecoin processors and custodians. In the FATF Travel Rule context, the
|
|
23
|
+
recurring problem is sending required transfer information to a counterparty
|
|
24
|
+
without exposing more than required — and retaining evidence you can review
|
|
25
|
+
later. Clearproof's answer is a Groth16 proof plus the required personal
|
|
26
|
+
information encrypted to the receiving institution's key (HPKE), bound to the
|
|
27
|
+
same transfer.
|
|
28
|
+
|
|
29
|
+
## What the source checkout implements today
|
|
30
|
+
|
|
31
|
+
The unreleased 0.4.0 development checkout implements a local adoption pilot:
|
|
32
|
+
|
|
33
|
+
- Authenticated credential enrollment with holder-bound issuance membership and
|
|
34
|
+
a canonical transfer/context projection using exact asset and valuation
|
|
35
|
+
arithmetic.
|
|
36
|
+
- Encrypted tenant-scoped storage with retained policy, root and revocation
|
|
37
|
+
history, actor-bound retries and atomic authorization consumption.
|
|
38
|
+
- Explained policy evaluation, comparison, review and activation history.
|
|
39
|
+
- Signed synthetic custody-event ingestion, simulated bilateral outcomes and
|
|
40
|
+
read-only transfer investigations with independent lifecycle states.
|
|
41
|
+
- Non-authorizing observation reports with scoped coverage, disagreement and
|
|
42
|
+
timing.
|
|
43
|
+
- Recipient-encrypted historical exports and offline review under independently
|
|
44
|
+
configured proof, policy, source, decision, status and timing authorities.
|
|
45
|
+
|
|
46
|
+
The current pilot proof profile, `pilot-transfer-v3`, has eight public signals
|
|
47
|
+
with no public amount tier or SAR advisory flag. The older 16-signal
|
|
48
|
+
`compliance.circom` profile remains a separate legacy demo path — the README
|
|
49
|
+
warns never to select artifacts by signal count alone.
|
|
50
|
+
|
|
51
|
+
## What a valid proof establishes — and what it does not
|
|
52
|
+
|
|
53
|
+
This is the boundary worth internalizing before any evaluation: a valid proof
|
|
54
|
+
establishes its encoded statement. It does not establish legal compliance,
|
|
55
|
+
source truth, counterparty acceptance or settlement by itself. Concretely, from
|
|
56
|
+
the [security boundaries](https://github.com/repfigit/clearproof/blob/main/packages/content/content/topics/security.md)
|
|
57
|
+
documentation:
|
|
58
|
+
|
|
59
|
+
- Credential authenticity, holder authority, jurisdiction and actual transfer
|
|
60
|
+
binding require coordinated improvements across the proof statement and the
|
|
61
|
+
application.
|
|
62
|
+
- Replay, expiry and root checks depend on the verifier and its configuration.
|
|
63
|
+
- A cryptographically valid proof is not an accepted transfer.
|
|
64
|
+
|
|
65
|
+
## What is available to install
|
|
66
|
+
|
|
67
|
+
Public npm packages are at **0.3.0** while the development checkout is **0.4.0**;
|
|
68
|
+
they are not the same. `@clearproof/proof` 0.3.0 installs as an SDK, but proof
|
|
69
|
+
generation requires compatible circuit WASM and proving-key files supplied by
|
|
70
|
+
the caller. The public CLI install is currently blocked by an unavailable
|
|
71
|
+
registry dependency. The practical evaluation path is a
|
|
72
|
+
[source checkout](https://github.com/repfigit/clearproof/blob/main/packages/content/content/topics/quickstart.md):
|
|
73
|
+
clone, build from the committed lockfiles, and run the documented local pilot,
|
|
74
|
+
which owns a disposable PostgreSQL cluster and loopback EVM and exercises real
|
|
75
|
+
proofs. A documented clean-checkout checkpoint (September 7, 2026) reproduced
|
|
76
|
+
this workflow end to end, including an offline historical review with network
|
|
77
|
+
connections disabled.
|
|
78
|
+
|
|
79
|
+
## Assurance status, stated once
|
|
80
|
+
|
|
81
|
+
Current circuits and contracts have not completed an independent audit, and
|
|
82
|
+
generated proving keys are explicitly unapproved development artifacts. Use
|
|
83
|
+
synthetic data and testnet funds. Development proofs and passing local tests do
|
|
84
|
+
not establish production readiness — see the
|
|
85
|
+
[adoption roadmap](https://github.com/repfigit/clearproof/blob/main/docs/ADOPTION_ROADMAP.md)
|
|
86
|
+
for what the project treats as its public priorities and follow-on gates.
|
|
87
|
+
|
|
88
|
+
If that scoped problem — verifiable transfer statements with minimized data
|
|
89
|
+
exposure and independently reviewable retained evidence — matches a workflow you
|
|
90
|
+
own, the fastest next step is the [full walkthrough](https://github.com/repfigit/clearproof/blob/main/packages/content/content/recipes/full-walkthrough.md):
|
|
91
|
+
build the sanctions tree, issue a credential, generate a proof, verify it, and
|
|
92
|
+
record the verified result on a testnet registry.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: UP-EX-003
|
|
3
|
+
title: Who verifies what — circuit, registry and application responsibilities in Clearproof
|
|
4
|
+
date: 2026-09-17
|
|
5
|
+
publishAfter: 2026-09-17T00:00:00Z
|
|
6
|
+
sourceCommit: eaab3d020c6d3f2943cb20d56633e919d6c1579e
|
|
7
|
+
claimRefs:
|
|
8
|
+
- packages/content/content/topics/architecture.md
|
|
9
|
+
- specs/pilot-transfer-v3.md
|
|
10
|
+
- packages/content/content/topics/security.md
|
|
11
|
+
- README.md
|
|
12
|
+
status: approved
|
|
13
|
+
summary: A zero-knowledge proof is one verifier among several. Reading where Clearproof's circuit stops and the registry and application take over is the difference between evaluating the system and over-crediting the math.
|
|
14
|
+
canonical: /explainers/who-verifies-what
|
|
15
|
+
templateVersion: explainer-v1
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
A recurring evaluation mistake with zero-knowledge compliance systems is
|
|
19
|
+
treating the proof as the security model. In Clearproof's source, the proof is
|
|
20
|
+
one verifier among at least three, and the [architecture
|
|
21
|
+
documentation](https://github.com/repfigit/clearproof/blob/main/packages/content/content/topics/architecture.md)
|
|
22
|
+
draws the line explicitly: "The circuit constrains particular mathematical
|
|
23
|
+
relationships. The application establishes trusted input sources and the policy
|
|
24
|
+
context. The registry additionally checks on-chain state, domain, expiry,
|
|
25
|
+
revocation and replay. Do not collapse these into a single claim that every
|
|
26
|
+
security property is proved by the circuit."
|
|
27
|
+
|
|
28
|
+
## What the circuit constrains
|
|
29
|
+
|
|
30
|
+
The pilot profile `pilot-transfer-v3` (Circom `pilot_compliance.circom`) proves
|
|
31
|
+
statements over the 48-field canonical transfer projection. Its public signals
|
|
32
|
+
include the projection commitment, issuer and sanctions tree roots, an
|
|
33
|
+
authorization nullifier, and domain binding (`domain_chain_id`,
|
|
34
|
+
`domain_registry`) that stops a proof built for one deployment being replayed
|
|
35
|
+
against another. The commitment binds the exact credential and issuance root
|
|
36
|
+
used by the credential subcircuit — the spec is explicit that it "is not a
|
|
37
|
+
caller-selected opaque assertion."
|
|
38
|
+
|
|
39
|
+
But the [public
|
|
40
|
+
statement](https://github.com/repfigit/clearproof/blob/main/specs/pilot-transfer-v3.md)
|
|
41
|
+
also states the boundary plainly: "Proof verification alone neither
|
|
42
|
+
authenticates those records nor establishes current roots, revocation, policy
|
|
43
|
+
compliance or legal compliance. The profile cannot authorize replay through
|
|
44
|
+
historical inspection."
|
|
45
|
+
|
|
46
|
+
## What the registry checks that the circuit does not
|
|
47
|
+
|
|
48
|
+
The registry is a second verifier. Per the architecture documentation, it
|
|
49
|
+
checks on-chain state, domain, expiry, revocation and replay. The development
|
|
50
|
+
registry includes a versioned verifier router, so a deployed registry and its
|
|
51
|
+
selector/artifacts must be checked against the intended proof version — v1 and
|
|
52
|
+
v2 profiles have the same signal count but different first-signal meanings and
|
|
53
|
+
different keys, and current artifact-context and root checks reject v1. That
|
|
54
|
+
router is what stops a proof built against one proving-key generation from
|
|
55
|
+
being verified against the wrong artifacts.
|
|
56
|
+
|
|
57
|
+
## What the application owns outright
|
|
58
|
+
|
|
59
|
+
The application layer establishes trusted input sources and the policy context.
|
|
60
|
+
The circuit never sees raw sanctions data or credential fields — it sees
|
|
61
|
+
commitments built from them. So the integrity of those commitments inherits
|
|
62
|
+
every assumption of the enrollment and projection pipeline: canonical
|
|
63
|
+
projection arithmetic, credential issuance membership, and the sanctions tree
|
|
64
|
+
build (script `scripts/build_sanctions_tree.py`, root relayed via the
|
|
65
|
+
SanctionsOracle). If an input source is untrusted, the proof is faithfully
|
|
66
|
+
proving a statement about untrusted data.
|
|
67
|
+
|
|
68
|
+
## Practical reading for evaluators
|
|
69
|
+
|
|
70
|
+
Three checks that don't require running anything:
|
|
71
|
+
|
|
72
|
+
1. **Match the profile to the artifacts.** Check the registry's versioned
|
|
73
|
+
router against the manifest's named profile (v2 manifests name it
|
|
74
|
+
explicitly; legacy manifests retain v1 meaning). Never select artifacts by
|
|
75
|
+
signal count alone — v1 and v2 both have eight.
|
|
76
|
+
2. **Ask who maintains the roots.** The sanctions root is relayed to the
|
|
77
|
+
oracle across all deployed chains; a stale root is a live question for any
|
|
78
|
+
deployment you evaluate, and proof verification alone does not establish
|
|
79
|
+
current roots or revocation.
|
|
80
|
+
3. **Trace trusted-input provenance.** The proof binds commitments; the
|
|
81
|
+
application binds the data behind them. Evaluating only the circuit
|
|
82
|
+
under-credits the registry checks and over-credits the math.
|
|
83
|
+
|
|
84
|
+
The opening line is the architecture documentation's own summary, and it is the
|
|
85
|
+
right one: the circuit, the registry and the application each verify a
|
|
86
|
+
different layer, and a complete evaluation reads all three.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Deploy Contracts to Sepolia
|
|
3
|
+
prereqs:
|
|
4
|
+
- sepolia-rpc
|
|
5
|
+
- funded-deployer
|
|
6
|
+
estimated-time: 5 min
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Deploy Contracts to Sepolia
|
|
10
|
+
|
|
11
|
+
Deploy the full contract suite (Groth16Verifier, SanctionsOracle, VASPRegistry, ComplianceRegistry, SanctionsRootRelay) to Sepolia testnet and verify on Etherscan.
|
|
12
|
+
|
|
13
|
+
## 1. Set environment variables
|
|
14
|
+
|
|
15
|
+
```bash:run
|
|
16
|
+
export SEPOLIA_RPC_URL="https://rpc.sepolia.org"
|
|
17
|
+
export PRIVATE_KEY="YOUR_DEPLOYER_PRIVATE_KEY"
|
|
18
|
+
export ETHERSCAN_API_KEY="YOUR_ETHERSCAN_API_KEY"
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Expected: No output (variables set)
|
|
22
|
+
|
|
23
|
+
## 2. Compile contracts
|
|
24
|
+
|
|
25
|
+
```bash:run
|
|
26
|
+
cd packages/contracts && npx hardhat compile
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Expected: `Compiled N Solidity files successfully`
|
|
30
|
+
|
|
31
|
+
## 3. Deploy all contracts
|
|
32
|
+
|
|
33
|
+
```bash:run
|
|
34
|
+
cd packages/contracts && npx hardhat run scripts/deploy.ts --network sepolia
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Expected: Five contract addresses printed, deployment artifacts written to `deployments/sepolia/`
|
|
38
|
+
|
|
39
|
+
## 4. Verify on Etherscan
|
|
40
|
+
|
|
41
|
+
```bash:run
|
|
42
|
+
cd packages/contracts && npx hardhat run scripts/verify-etherscan.ts --network sepolia
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Expected: All five contracts verified on Sepolia Etherscan with green checkmarks
|