Tools.

Tools

Make and check BitGraphs from your own software.

Every tool here does the same one thing the Make page does: it hashes your file where it is and sends only the SHA-256. The enclave binds it in one atomic action and the proof comes back to you. Checking a proof needs none of them, and nothing of BitGraph’s running.

For AI agents

The MCP server.

Claude Code, Claude Desktop and any MCP client. One line to add it:

claude mcp add bitgraph -- npx -y @mikeargento/bitgraph-mcp
  • bitgraph_record makes a BitGraph of each file or folder given; each proof is saved beside its file as <file>.bitgraph.json.
  • bitgraph_check says whether files or digests are on record, and where. Read-only.
  • bitgraph_get_proof fetches a proof by digest, BitGraph number or file path. Read-only.

Clients that connect by URL can use the hosted server at https://bitgraph.ing/mcp.

SDK and CLI

For any stack.

npm install @mikeargento/bitgraph-sdk
import { BitGraph } from "@mikeargento/bitgraph-sdk";

const [b] = await new BitGraph().bind("run-042.log");
console.log(b.number, b.proofUrl); // run-042.log.bitgraph.json is saved beside the file

The same verbs from any language that can run a command, with --json for machines:

npx -p @mikeargento/bitgraph-sdk bitgraph make run-042.log
npx -p @mikeargento/bitgraph-sdk bitgraph check run-042.log
npx -p @mikeargento/bitgraph-sdk bitgraph verify run-042.log
npx -p @mikeargento/bitgraph-sdk bitgraph serve   # the same on 127.0.0.1

HTTP API

Send a SHA-256, get the proof.

curl -X POST https://bitgraph.ing/api/commit \
  -H 'content-type: application/json' \
  -d '{"digests":[{"digestB64":"<sha-256, base64>","hashAlg":"sha256"}]}'

Every BitGraph is kept. Fetch one by its hash:

curl https://bitgraph.ing/api/proofs/<sha-256, base64url>

Add "ceiling": true to a commit to have its proof hash written to Base afterwards (the Base plugin, below).

Check it offline

No account, nothing of BitGraph’s running.

With the file and its proof (download it from the proof page), pinning the enclave’s measurement so nothing else is accepted:

npx @mikeargento/bitgraph-sdk verify <file> --proof <proof>.json --pcr0 cf1ca497e1c3f678cce99ec2215f3991c72fd1b54f083a1f58563e88f5fe742e5190c7ebaf27f3aa98622605687e27c9

That is the whole check. What it does step by step, and how to rebuild the enclave image yourself, are under Reference at the end of this page. Rely on a check you run; a verdict on BitGraph’s own pages is a convenience.

How it’s made

One atomic action.

A BitGraph is made inside an AWS Nitro hardware enclave, a measured trusted execution environment. The enclave keeps one monotonic counter. Each BitGraph takes the next two counts in a single atomic action:

  1. Count N, the nonce. 32 bytes from the Nitro hardware’s random number generator, made inside the enclave and seen by nobody until the content is bound.
  2. Count N+1, the content. The SHA-256 of your bits. The file itself never reaches BitGraph: it is hashed where it is.

Both counts are signed together with the enclave’s Ed25519 key and attested by the Nitro hardware, which names the exact enclave image that did it. There is no partial state: if any step fails, no proof exists, the nonce is discarded without ever leaving the enclave, and the counter does not move.

The nonce is used once, and the enclave never gives out the same count twice, so every proof is one of a kind.

Two BitGraphs bracket an interval: anything bound between them was bound after the first and before the second. Work made from the first one’s nonce could not have existed before it. Plugins, below, builds on this.

Plugins

Built from ordinary BitGraphs.

Two switches on the Make page add to a BitGraph without changing it. Each plugin is made of ordinary BitGraphs, every one the same two counts; nothing about either one enters the enclave or the proof format.

One position for many files.

The files are hashed into a Merkle tree in your browser (RFC 6962, SHA-256: a leaf is SHA-256 of a zero byte and the file, a node is SHA-256 of a one byte and its two children, and an odd last node rises unchanged). One BitGraph is made of merkle-root.txt, a short text file holding the root. You keep merkle-tree.json, which lists every file’s leaf and every level. One position covers a million files as well as one.

To check a file: drop it on the Make page with merkle-tree.json and merkle-root.txt (switches off). The page walks the file up the tree to the root and looks the root file up as a BitGraph. By hand: hash the file as a leaf, combine it with its neighbours up the levels, compare with the root in merkle-root.txt, and verify merkle-root.txt against its proof like any file.

Base time window.

Three steps, two BitGraphs:

  1. BitGraph 1 is the floor. The latest Base block (number, hash, time) is written to base-block.json and bound. A block hash cannot be known before its block exists.
  2. BitGraph 2 is the content, bound right after BitGraph 1 in the same sequence.
  3. The ceiling. BitGraph 2’s proof hash is written to Base by BitGraph’s writer, in a later block. The proof existed by then.

The content was bound after the first block and before the second: a window in real time, read from a public chain, around a position. The site checks the pair before it records BitGraph 1 as BitGraph 2’s floor: base-block.json hashes to BitGraph 1’s digest, Base has that block with that hash and time, and both BitGraphs are in the ledger in the same epoch with BitGraph 2 after BitGraph 1. The record is kept beside the ledger and shown on BitGraph 2’s proof page.

To check a window yourself, with the download from the Make page:

  1. Verify both files against their proofs with the command above.
  2. Open the block in base-block.json on any Base explorer and compare its hash and time.
  3. Compare the two proofs’ commit.epochId (the same) and counts (BitGraph 2’s after BitGraph 1’s).
  4. Find BitGraph 2’s Base transaction from its proof page and check that it carries the proof hash.

Without the Base switch, a BitGraph is a position only: where your bits were bound in the sequence, with no claim about clock time.

Epochs

A fresh key every day.

The enclave restarts once a day, at 23:59 UTC. Each run is an epoch: a new Ed25519 key made inside the enclave, a counter starting at zero, and an epoch ID that is the base64 SHA-256 of the public key and a fresh boot nonce. The key never leaves the enclave and is gone when the epoch ends, so an epoch that has ended cannot sign anything new (unless its key was stolen while it ran). Each epoch’s first proof links, signed, to the preceding epoch’s final published proof, so a verifier can follow the declared sequence across restarts. The enclave has no storage of its own: the counter’s continuity is kept by the enclave’s code within each run, not carried by the hardware from one run to the next. While the enclave restarts, requests fail closed; nothing is made.

Limits, in full

Where exact bits were bound. Nothing else.

A valid proof says these exact bytes were bound at this position in one sequence, after a value nobody could predict. Byte identity is the unit of every claim: change one byte and the proof no longer covers the file (barring a SHA-256 collision, which is infeasible).

It does not prove:

  • Truth. The proof binds bytes, not their meaning.
  • Authorship. It attests the enclave that bound the digest, not the person or program that made the file.
  • Ownership. Nothing in the protocol touches rights.
  • First creation. The same bytes may have existed elsewhere before, and an old file can be bound today. What is fixed is the position the bytes took here, not how old they are.
  • Completeness. A record that was never made leaves no trace.
  • That an event happened. Whether something occurred is for whatever produced the record. BitGraph has no sensor path.
  • Correct input. If the software hashes the wrong bytes, BitGraph binds that digest faithfully.
  • Legal effect. Admissibility and weight are not something the protocol establishes.

A record changed after it was bound is caught: its hash no longer matches. A record that was false when it was bound is not: nothing in a proof inspects content.

What you trust, in full

One vendor, one build.

To accept a proof, a reader trusts:

  • The enclave image identified by its measurement (PCR0), which is published and reproducible from this repository’s source.
  • The AWS Nitro hardware and its security module, which draw the randomness and sign the attestations.
  • The AWS Nitro root certificate, built into the verifier as a constant.
  • Ed25519 and SHA-256.
  • The verifier running on their own machine.

A reader does not trust the host machine around the enclave (it only carries messages), the network, this website, BitGraph’s stored copies of proofs (a convenience, not the evidence), or Argento Computing Inc. Accepting the hardware root is a one-time decision, not an ongoing dependency: a proof is portable and checks without asking anyone.

The design prevents reusing a nonce, swapping positions, changing any signed field, and signing new proofs as an epoch that has ended: its key is destroyed when the epoch ends, so only a key stolen while the epoch ran could. It does not protect against a malicious client or a compromised build pipeline, and a flaw in the enclave image would affect every epoch that runs it. The implementation has not had an independent security audit.

BitGraph controls availability and publication. Anyone can verify a proof independently, but a proof alone cannot establish that every commitment has been disclosed. A proof withheld from the middle of the published sequence shows as a missing count; the most recent ones, withheld, would not show at all.

Privacy: a digest is public once it is bound, and digests are not salted. A hash does not reveal the file, but a file someone can guess (a short text, a public document) can be identified by hashing the guess and looking it up.

Questions

Short answers.

Does BitGraph upload my file? No. Only its SHA-256 is sent. (A client you did not write could send more; this site’s drop boxes and the published packages send only the hash.)

Can the same file get two proofs? Yes. Each is its own BitGraph at its own position, with its own nonce.

What if someone edits the proof? Any change to a signed field breaks the signature, and the check fails.

Why not just trust a timestamp? A time written by the party a check exists to catch is a claim, not evidence. A BitGraph’s place comes from a counter and a value nobody could predict, signed by measured hardware.

Does the Base switch change the BitGraph? No. The bind is the same two counts. The window comes from a second BitGraph (the block) and a write to Base afterwards, both outside the bind.

Is a tree weaker than one BitGraph per file? Every file in it shares one position: they were all bound together, at that point in the sequence. To tell the files apart in order, make them separately.

What does it cost to check? Nothing. Verification is free and permissionless.

Reference

The proof, and the full check.

A small signed JSON document:

  • artifact: hashAlg (sha256) and digestB64, the content’s SHA-256.
  • commit.nonceB64: the nonce, revealed now that the content is bound.
  • commit.slotCounter: the nonce’s count (N). commit.counter: the content’s count (N+1), a decimal string.
  • commit.slotHashB64: the SHA-256 of the nonce’s signed position record, carried in slotAllocation.
  • commit.prevB64: the hash of the previous proof in the sequence, so proofs form a chain.
  • commit.epochId, commit.chainId (bitgraph:main), commit.atomic (true).
  • signer: the enclave’s Ed25519 publicKeyB64 and signatureB64.
  • environment: enforcement (measured-tee), measurement (PCR0) and the Nitro attestation document.
  • proofHash: the SHA-256 of the signed body, added after signing; it is the attestation’s user_data.

The signature covers the canonical form of the body: object keys sorted by Unicode code point, serialized with no whitespace, encoded as UTF-8. The nonce’s record and the content’s commit are bound four ways: the same nonce, the same key, the record’s hash in the commit, and the nonce’s count below the content’s.

What a full check does, in order:

  1. Hash the file and compare it with artifact.digestB64.
  2. Rebuild the signed body in canonical form and check the Ed25519 signature.
  3. Check the nonce’s position record: its own signature, its hash in the commit, the same nonce and key, its count below the content’s.
  4. Check the attestation: a COSE_Sign1 document signed with ES384, whose certificate chain ends at the AWS Nitro root; its PCR0 must equal environment.measurement and its user_data the proof hash.
  5. Pin the measurement: accept only an enclave image you have checked (the verify command’s --pcr0 flag). A verifier that accepts any measurement has verified a signature by an unknown key.

The AWS Nitro root certificate’s SHA-256:

641a0321a3e244efe456463195d606317ed7cdcc3c1756e09893f3c68f79bb5b

The enclave’s published measurement (PCR0):

cf1ca497e1c3f678cce99ec2215f3991c72fd1b54f083a1f58563e88f5fe742e5190c7ebaf27f3aa98622605687e27c9

Rebuild the enclave image yourself and compare. Any linux/amd64 machine with Docker and git; no Nitro hardware needed. The image file differs between builds (its header holds the build time); PCR0 does not.

git clone https://github.com/mikeargento/bitgraph.git
cd bitgraph
./server/commit-service/reproducible-build/build-eif.sh enclave-v12