How to verify a Proovik proof without trusting Proovik
This page describes, step by step and with real values, how anyone verifies by purely mathematical means that a document existed before a given date. No node, no API, no cooperation from us is required: only the proof file, a hash calculator and this page.
What is claimed, exactly
Precision matters more than eloquence here, because whether the proof survives cross-examination depends on it.
That a byte string whose SHA-256 is a given value was placed into a Kaspa transaction, that this transaction was committed inside a block header, and that a valid proof of work was executed over that header, which includes a timestamp. Because the timestamp sits inside the data the work was done on, altering it invalidates the work. The date is nobody's declaration: it is a physical quantity already spent.
Who created the document, whether its content is true, whether its author was entitled to create it, or that the document did not exist earlier. It establishes priority to an instant, not authorship or truthfulness. Proovik never sees the document: it only receives its hash.
SHA-256 is a 256-bit digest function. Finding two different documents with the same digest has never been achieved and the estimated effort exceeds what humanity can compute. So if the digest of the submitted document matches the one on chain, the document is the same, with no practical room for doubt.
The four links
Verification is a chain. Each link connects to the next, and a single broken link makes the proof worthless. The values shown below are real: they belong to a certificate issued on 24 January 2026.
The transaction payload is the document digest
Links the document to the blockchain
Every Kaspa transaction accepts a free field, payload. Proovik writes there the 32 bytes of the document's SHA-256, and nothing else. The check is a literal comparison.
- documento
- 8ea578dd12b3e8c55b8b53f3db80f6cd23fe1ed22a0d7af5c46fc8e25f45294c
- payload
- 8ea578dd12b3e8c55b8b53f3db80f6cd23fe1ed22a0d7af5c46fc8e25f45294c
The transaction is committed in the block header
Links the transaction to the block · 64-byte witness
Every header on the chain records a commitment to the transactions that block accepts. Since KIP-15 took effect, that field, acceptedIdMerkleRoot, is not a plain Merkle root but a chained value: it combines the parent block's commitment with the root of the accepted transactions. A recomputation that ignores that chaining fails, and that is the single most common cause of failed verifications.
- AIMR
- b3bc256951640ff6468511fb62ec8fb280dafb99ebf7ecd00245d0cc3c9debb3
- seq. padre
- 2b3265225d51e5b051e46b9f164dc116cf2e21d566827abc8a7b1ae036d8330d
- calculado
- 7843221eda25f05ddf9872ed57b59fb95c4f15aa7bf15017105e9797ef09caa5
- in header
- 7843221eda25f05ddf9872ed57b59fb95c4f15aa7bf15017105e9797ef09caa5
The order of the accepted transactions is the canonical order fixed by KIP-15, not the order an API returns them nor a by-hash order. And a block tree's leaves —when inclusion, not acceptance, is verified— are not the txid but the tx::hash, computed with the full encoding (signature scripts and the storage-mass commitment included).
The header produces the declared block hash
Links the block to its identity
A block's hash is the digest of its serialized header. Recomputing it proves the submitted header is exactly what it claims to be, and that none of its fields —the timestamp included— has been touched.
The header commits to all parent levels —today 56 of them, with more than two hundred hashes—. If a single one is missing, the digest cannot be reconstructed. This is why the proof file must capture the whole header at anchoring time: after some thirty hours the network discards that data and public services return a truncated header.
A valid proof of work was executed over that header
Turns the block into a physical fact and dates the document
This is where the proof stops being an assertion and becomes a finding of fact. Kaspa requires the result of applying its work function (kHeavyHash) to the header to fall below a threshold. Reaching it takes quadrillions of attempts: real energy, irreversibly spent.
- pre
- 6e4f2ca8feb279a54f2c4ac8d57c867917f1766a7936a5bd7bd9351557d3c6f7
- result
- 0x15222b53caabb3b049ec84e25d0a0c7a35512f9d557adb4bc20
- target
- 0x2345b0000000000000000000000000000000000000000000000
Why the date is a physical quantity, not a declaration
This is the part cross-examination usually demands, so it is better shown than argued. The timestamp sits inside the header, and the header is the input to the proof of work. Change the time and you change the input, and the work is no longer valid. It is checked experimentally by altering the header verified in step 4 and repeating the computation:
| Header | Work result | Verdict |
|---|---|---|
| Original, untouched | 0x15222b53caabb3b049ec… | Valid |
nonce + 1 | 0x6775abc19ba960657f66… | Invalid |
timestamp moved forward one second | 0xaee1e8274b1d268866ed… | Invalid |
To present the document with a different date one would have to redo that header's proof of work against the network's real difficulty. This is not a cost barrier: it is a compute barrier on the order of the whole network's aggregate power over the interval one intends to falsify. Nobody declares the date. The date is paid for.
Will it still work after future hardforks?
The honest answer is yes, and it is worth understanding why. A captured proof is not a live query to the network: it is a historical fact, verified under the rules in force at the moment it was anchored. Kaspa changes over time —the Crescendo/Toccata transition, for instance, altered the DAA cadence and the difficulty count— but that does not erase the past: it just means a January 2026 block is verified with January 2026 rules, and one three years from now with the rules of three years from now.
The reference verifier is built exactly for this: it distinguishes eras. It knows the activation point of each consensus change (for example, the CRESCENDO_DAA_MAINNET constant) and applies to each block the rules of its epoch, not today's. A later hardfork adds a new era; it does not invalidate the earlier ones.
The permanence of the proof then rests on three conditions, all under the control of whoever holds it:
Save the whole header at anchoring time, before the network discards the full data (some 30-40 hours).
The proof file (or the PDF that embeds it) is self-sufficient: it points to no server and no online lookup.
248 lines of open code, no dependencies, re-derivable from Kaspa's public source. Even if lost, it can be rewritten.
Verify it yourself
The reference verifier is 248 lines of Python with no external dependencies: it implements keyed blake2b, the Keccak-f[1600] permutation, the xoshiro256++ generator and the matrix arithmetic. It reads in an afternoon and audits in two.
$ python3 verificador_kaspa.py prueba.json 8ea578dd12b3e8c55b8b53f3db80f6cd23fe1ed22a0d7af5c46fc8e25f45294c OK 1. El payload on-chain es el hash del documento OK 2. La transaccion esta en el arbol Merkle del bloque OK 3. La cabecera produce el hash de bloque declarado OK 4. La prueba de trabajo de esa cabecera es valida RESULTADO: PRUEBA VALIDA
Two files. Put them in the same folder and run the first. They install nothing and never reach the network.
Anyone who prefers not to run someone else's code can reimplement it: the four algorithms are described above without ambiguity, and every parameter comes from rusty-kaspa's public source. It is equally legitimate to look the transaction up in any public Kaspa explorer as a cross-check, but the difference matters: the explorer is testimony; the computation is a demonstration. This specification exists so as not to depend on the former.
Legal scope
Proovik provides a non-qualified electronic time stamp service within the meaning of Article 3.16(i) of Regulation (EU) 910/2014. It is worth being explicit about what that means.
- Under Article 41.1 of that Regulation, an electronic time stamp shall not be denied legal effect or admissibility as evidence in legal proceedings solely on the grounds that it is in electronic form or does not meet the requirements of a qualified stamp.
- A non-qualified stamp does not enjoy the presumption of accuracy of the date and time of Article 41.2, which is reserved for qualified ones. If challenged, the burden of substantiating the proof falls on the party presenting it.
- That is precisely why this specification exists: so that this burden is met with an arithmetic check anyone can reproduce, rather than with the provider's declaration.
Proovik does not verify the content, authorship or lawfulness of documents, and never accesses them: it receives only their cryptographic digest. What is established is a proof of existence and prior date to a given instant.