Proofs
A proof is a cryptographic Merkle proof-of-inclusion that demonstrates a specific file was part of a published snapshot. Proofs enable selective disclosure: you can prove the existence and content of individual files without revealing the full file tree.
Why Proofs Exist
Snapshots anchor a Merkle root representing the entire repository state. But sometimes you need to demonstrate that a specific file -- a license, a configuration, a critical module -- was present in a specific version, without disclosing everything else.
Proofs let you answer the question: "Was this exact file, with this exact content, included in this snapshot?" The answer is cryptographically verifiable by anyone, without needing access to the full snapshot or the CodeQuill platform.
How Proofs Work
A Merkle proof-of-inclusion works by providing the minimal set of sibling hashes needed to reconstruct the root from a specific leaf:
- The leaf is computed:
keccak256(0x00 || path_hash || file_hash) - The proof provides the sibling nodes at each level of the tree.
- A verifier folds the proof (hashing pairs at each level) to reconstruct the Merkle root.
- If the reconstructed root matches the on-chain Merkle root, the file was provably included.
Privacy Considerations
Because file paths are salted before hashing, generating a proof requires knowledge of the salt. The salt is derived from the workspace encryption key, which means:
- Proof generation requires authority -- You must be a workspace member with passkey access.
- Proof verification is public -- Once generated, anyone can verify the proof without any authentication.
When generating a proof, the CLI initiates a device-approval flow (similar to the login flow) where you approve the path resolution using your passkey in the browser. This ensures the salt is never exposed to the CLI directly.
The --disclose Option
By default, proofs do not include the plaintext file path. They contain only the salted path hash, which is sufficient for cryptographic verification but does not reveal which file was proven.
If you want the proof to include the plaintext path (for human readability), use the --disclose flag. This is a privacy tradeoff -- the proof becomes more informative but reveals the file's location in the repository.
Using the CLI
Generate a Proof
codequill prove <file> <snapshot-id>
Arguments:
| Argument | Required | Description |
|---|---|---|
<file> |
Yes | Path to the file to prove inclusion for |
<snapshot-id> |
Yes | The snapshot ID to prove against |
Options:
| Option | Type | Default | Description |
|---|---|---|---|
--disclose |
boolean | false | Include the plaintext path in the proof |
--out <file> |
string | .codequill/proofs/proof-<hash>.json |
Output path for the proof file |
Example: Generate a Proof
codequill prove src/main.ts snap_abc123
The CLI will:
- Read and hash the target file (
keccak256). - Fetch the snapshot manifest from the backend.
- Initiate a device-approval flow to resolve the salted path hash.
- Locate the file in the manifest.
- Build the Merkle proof.
- Write the proof to
.codequill/proofs/proof-<hash>.json.
Example: Proof with Path Disclosure
codequill prove src/main.ts snap_abc123 --disclose
Example: Custom Output Path
codequill prove LICENSE snap_abc123 --out evidence/license-proof.json
Verify a Proof
Proof verification is a separate, offline operation that requires no authentication:
codequill verify-proof <proof-file>
Arguments:
| Argument | Required | Description |
|---|---|---|
<proof-file> |
Yes | Path to the proof JSON file |
The verification process:
- Reads the proof file (must follow
codequill-proof:v1schema). - Recomputes the leaf hash from the path hash and file hash.
- Folds the Merkle proof using the sibling nodes.
- Compares the computed root against the Merkle root in the proof.
codequill verify-proof .codequill/proofs/proof-abc123.json
Proof verification: VALID
Merkle Root: 0x789abc...
File Hash: 0xdef012...
Proof Steps: 12
If the proof is valid, it cryptographically demonstrates that the file was included in the snapshot identified by the Merkle root. The verifier can then cross-reference the Merkle root against the on-chain record to confirm the snapshot was anchored at a specific time by a specific authority.
Proof File Format
Proofs follow the codequill-proof:v1 schema:
{
"version": "codequill-proof:v1",
"merkle_root": "0x...",
"file": {
"path_hash": "0x...",
"hash": "0x...",
"path": "src/main.ts"
},
"proof": [
{ "hash": "0x...", "position": "left" },
{ "hash": "0x...", "position": "right" }
]
}
The file.path field is only present if --disclose was used during generation.
Auditor Context
For auditors: a verified proof demonstrates that a file with a specific content hash was included in a snapshot with a specific Merkle root. Combined with the on-chain anchor of that Merkle root, this constitutes evidence that the file existed at the time of anchoring. See Interpreting Evidence.