From a git push to a proof no author can rewrite.
Aletheia (ἀλήθεια, un-concealment) anchors every push to Monad and hands anyone — human or judging agent — the means to re-verify the whole record from a fresh clone. This page is the full mechanism: the architecture, the contract, and the threat model it was designed against.
What it proves — and what it doesn't
Git history is author-controlled. git commit --date and GIT_COMMITTER_DATE fabricate any timeline after the fact; a force-push rewrites it silently. A block timestamp is produced by consensus at a moment in time and cannot be retroactively manufactured.
It proves
- Existence by time T — the attested tree of source existed at or before its block timestamp.
- Continuity — the sequence of attestations shows incremental evolution, not a single late dump.
It does not prove
- Authorship or originality — someone can attest code they copied. Aletheia proves timing, not who wrote it.
- We say this plainly in the UI and README rather than overstate the guarantee.
System architecture
A push flows through an ingestion layer that verifies and forwards it, into a single event-sourced contract, and back out to two independent readers — the proof page and the verification CLI.
Verify & forward
The bridge checks the X-Hub-Signature-256 HMAC over the raw body, dedupes the delivery ID, resolves the repo to a projectId, and submits attest / attestBatch through a serialized nonce-managed queue.
Seal on chain
The registry emits one Attested event per commit carrying the commit hash, tree hash, and block.timestamp. Events, not storage — every consumer reads them via eth_getLogs.
Read two ways
The proof page renders the timeline from chain events (GitHub metadata is optional garnish). The CLI re-derives the same hashes from a raw clone and compares.
Why the tree hash, not just the commit
Attesting only commit hashes admits a cheat: push empty or junk commits on time, then later force-push real content and claim the old hashes. The commit hash does commit to its content — but verifying that requires the original objects, which a force-push can vanish.
So Aletheia attests the tree hash alongside the commit. Verification recomputes both from the public repo:
If the repo's current objects don't reproduce the attested pair, verification fails visibly. A cheater would need a pre-image of the attested tree hash that matches their later-written code — computationally infeasible. Git SHA-1 ids are 20 bytes, left-aligned and zero-padded into bytes32; SHA-256 repos fill all 32, and the CLI detects which encoding a repo uses.
Two attestation paths
Hosted bridge
A GitHub webhook hits a Fastify service that verifies the HMAC, dedupes replays, and submits with a low-privilege attestor key. Fastest to set up — one webhook URL and secret pasted into repo settings.
Convenience · you trust the bridge's uptimeTrustless GitHub Action
A published workflow lets a project attest its own pushes with its own key, writing to the same contract with the same semantics. No one has to trust Aletheia's server at all.
Zero third-party trustBoth paths still attest a force-push (the new head is real content at a real time) but mark it as a rewrite on the timeline — honesty includes showing rewrites.
Contract reference
A single, event-sourced contract. Storage holds only per-project control state; all commit data lives in events, which are far cheaper and are what every reader consumes.
State-changing functions
registerProject(bytes32 repoHash, string repoUrl, address attestor)One project per repo — reverts RepoAlreadyRegistered. repoUrl travels only in the event.
attest(uint256 projectId, bytes32 commitHash, bytes32 treeHash)Attestor-only, unsealed-only. Emits one Attested with block.timestamp.
attestBatch(uint256 projectId, bytes32[] commitHashes, bytes32[] treeHashes)Multi-commit pushes. Array lengths must match and be non-empty (BadInput).
linkContract(uint256 projectId, address deployed, string label)Owner-only. Binds a deployed contract into the build timeline.
setAttestor(uint256 projectId, address newAttestor)Owner-only. Rotates the attestor key if the bridge key is compromised.
seal(uint256 projectId)Owner-only, idempotence-guarded. After sealing, every mutating call reverts forever.
Events
Errors
Deployed on Monad Testnet · chain 10143
Threat model
Covered
- shieldForged commit dates — chain timestamp wins.
- shieldPost-hoc history rewrite — missing commits flagged by the CLI.
- shieldContent substitution — tree-hash mismatch.
- shieldJunk-commit-then-replace — tree-hash pre-image infeasibility.
- shieldPost-submission additions — sealing closes the record.
- shieldBridge key theft — low-privilege, rotatable; worst case is spurious attestations, never fund loss.
- shieldWebhook forgery / replay — HMAC + delivery-ID dedupe.
Out of scope, stated honestly
- radio_button_uncheckedProving authorship — someone can attest code they copied — timing, not originality.
- radio_button_uncheckedPre-writing code before registering — mitigated socially; the timeline's shape during the event is the signal judges read.
- radio_button_uncheckedGitHub lying about tree contents — defeated by independent CLI recomputation from a raw clone.
Independent verification
Anyone re-runs the whole proof with nothing but Node ≥ 20 and a system git. No keys, no writes, no trust in Aletheia's servers.
Green — verified
Commit present and its recomputed tree matches the attested hash. An honest repo that never rewrites published history stays all-green and exits 0.
Yellow — missing
An attested commit is gone from history — rewritten after attestation. Fails: a tool that passed these would let a rewritten repo look clean.
Red — mismatch
A present commit whose recorded tree never matched it. The residual case; also fails and exits non-zero.
Read it straight from the chain
Every proof on this site is reproducible. Verify a repository, browse the registry, or read the source — the record answers to the chain, not to us. Hackathon clock starts 2026-07-13.