# Commitments

> A commitment is the keccak256 hash of exact content — how Elgora addresses a document, and how anyone checks they were served the right one.

A **commitment** is `keccak256(bytes)` — the hash of exact content, and nothing
more. Same bytes, same 32-byte value; one byte different, an unrelated one.

It does two jobs. It **addresses** content: one value names one document, which
is how a bounty refers to its challenge and how the API is keyed. And it makes
content **checkable**: anyone holding the bytes recomputes the value and knows
they have the same document as everyone else.

So storage here is an availability layer, not a source of truth. Wrong bytes
are caught by re-hashing them, and if storage disappears the record of what was
committed survives on-chain.

`keccak256` because it is the EVM's native hash. The digests inside a
Submission envelope are SHA-256 — those are checked off-chain.

## What a commitment is not

| Not          | Because                                                                                                                  |
| ------------ | ------------------------------------------------------------------------------------------------------------------------ |
| Secret       | A hash of public bytes hides nothing. Submissions are private because they are encrypted, not because they are committed |
| Access       | Holding a `submission_commitment` gets you nothing. The API decides access from live contract state                      |
| Authorship   | It says a document exists, never who wrote it. Signatures do that                                                        |
| Availability | It proves what the bytes were, not that anyone still has them                                                            |

## The three on-chain commitments

| Commitment              | Commits to                                     | Written by | Recorded on-chain at  |
| ----------------------- | ---------------------------------------------- | ---------- | --------------------- |
| `spec_commitment`       | The exact approved `bounty_challenge.md` bytes | The Poster | Bounty creation       |
| `submission_commitment` | One Solver's sealed Submission envelope        | The Solver | Each `submit` call    |
| `report_commitment`     | One Guardian's written Verdict document        | A Guardian | Each recorded Verdict |

There is no canonicalization step for the challenge: a single changed byte is a
different commitment, and therefore a different bounty.

### `spec_commitment`

`keccak256(bounty_challenge.md UTF-8 bytes)`. This is what makes a published
challenge immutable: the Poster cannot soften a criterion after Solvers start
work, and Elgora cannot serve one page to a Solver and a different one to a
Guardian.

Reproduce it with no network, no wallet, and no configuration:

```sh
elgora-cli spec-commitment ./bounty_challenge.md
```

What it does **not** cover: discovery metadata, where the page is served from,
drafting history, written Verdicts, or Submission artifacts. And if the
challenge lists outside input files, their names, locations, and stated SHA-256
hashes are committed — the file *bytes* at those locations are not. The listed
hash is what identifies them.

### `submission_commitment`

`keccak256` of the canonical JSON of your sealed envelope. The envelope
contains the deployment context, digests of the encrypted bundle, the
recipients commitment for the pinned Guardian roster, the reveal policy, the
time-locked key bag, and the storage locator of the ciphertext — but no
plaintext and no usable key.

So the commitment proves *which sealed submission* you recorded, at the block
you recorded it, without revealing anything about its content. A Guardian later
fetches the envelope, re-derives the commitment, and refuses to judge anything
that does not match what the contract has.

One per Solver per bounty: re-submitting overwrites the value on-chain.

### `report_commitment`

`keccak256` of a Guardian's written Verdict document. The on-chain Verdict
carries the commitment; the document itself is published through the API and is
public from the moment it exists.

Note what the contract counts as agreement: outcome, named winner, awarded
submission commitment, and payout data. The `report_commitment` is **not** part
of that tuple — Guardians must reach the same *decision*, not write the same
words.

## Resolving a commitment back to its bytes

| Have                    | Want                | Do this                                                                                                                                           |
| ----------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `spec_commitment`       | The challenge       | `GET /api/bounties/{bounty_id}` returns the committed Markdown; re-hash it and compare                                                            |
| `submission_commitment` | The envelope        | `GET /api/bounties/{bounty_id}/submissions/{submission_commitment}/content` — authenticated, and only for the funding Poster or a pinned Guardian |
| `report_commitment`     | The written Verdict | `GET /api/written-verdicts/{report_commitment}` — public                                                                                          |

In every case the same rule applies: &#x2A;*re-derive and compare before you rely on
it.** A commitment you did not recompute is a claim, not a proof.

## Where to keep them

They are all public, so there is nothing to protect — only something to not
lose.

* **Posters:** keep `bounty_id`, `spec_commitment`, and the creation
  transaction hash. Keep your own copy of the approved `bounty_challenge.md`
  too; it is the preimage, and holding it means you can prove what you
  published without depending on anyone's storage.
* **Solvers:** keep your final `submission_commitment` and its transaction
  hash. Keep your artifact directory: it is the only copy of your plaintext
  that exists anywhere.
* **Integrators:** commitments are the natural join key. Both the API and the
  subgraph key on them, so recording the commitment is enough to look
  everything else up later.

## What auditability actually gives you

Chain state is permanent and independently verifiable: which bounty existed,
what it committed to, who submitted what and when, which Guardians voted for
which outcome, and how the money moved.

The **readable** artifacts — the challenge text, the written Verdicts, the
Submission envelopes — are off-chain. As long as those bytes are still
available, from Elgora or from a copy you kept, anyone can prove they are the
committed ones. If a preimage is lost, the commitment remains as a record that
something specific was committed, but the document itself is not recoverable
from the chain. That is the honest boundary: the chain proves *integrity*, not
*availability*.
