PATINA docs

Attestations

Depth says the output has not moved. An attestation adds that somebody with the key is here today. It costs nothing and spends nothing.

What you will know after this page
  • The exact string to sign: the tag PTNA/attest, then the artifact id, then a recent block hash, with nothing between them.
  • Why the block hash is what stops a signature from having been made earlier.
  • How to verify one starting from the carrier in the artifact record, rather than from an address somebody sent you.
  • The three things an attestation shows and the three it does not, including whether anybody else holds a copy of the key.

The message

An attestation is a BIP-322 signature over one exact string, produced by the key that controls the carrier.

"PTNA/attest" || artifact_id_hex || block_hash_hex

All three parts are concatenated with no separator, no newline, and no spaces. The two hashes are lowercase hex. A worked example, with the values computed by docs/tools/vectors.mjs:

PTNA/attestd3b8d3013c23dd3df76882034df80935ba55aa75772007f0b142b63adce5eff06b86b9521630996bec957312d95d273f4e19e1d87e00ca8928f3c736c6d73308

The cuts always fall at the same two offsets, so a message of the wrong length is the first thing to check when a signature will not verify.

The three parts of the message above.
PartLengthValue
Tag11 charactersPTNA/attest
Artifact id64 charactersd3b8d301...ce5eff0
Block hash64 characters6b86b952...6d73308

Why a block hash

The block hash is the timestamp. It cannot be predicted before that block is mined, so a signature over it cannot have been made earlier. That turns "I have the key" into "I had the key at or after this block".

  • Pick a recent block. A signature over a block from last year proves you had the key last year, which is much weaker.
  • Whoever verifies it decides what counts as recent. A common rule is within 144 blocks.
  • Signing again later is normal. Attestations are meant to be repeated, not permanent.

Producing one

  1. Get the artifact id

    From your own records, or from GET /patina/artifacts/:id. Use the lowercase hex form exactly as it appears.

  2. Get a recent block hash

    bitcoin-cli getbestblockhash

    Use the block hash in the standard display order, the same string a block explorer shows.

  3. Build the message and sign it

    Concatenate the three parts. Sign with BIP-322 using the key that controls the carrier output. Do not sign with a different key from the same wallet, because a verifier checks the signature against the carrier's address.

  4. Publish the three items together

    The signature alone is useless. Publish artifact id, block hash, and signature, so anyone can rebuild the message and check it.

Verifying one

Five steps, in this order. The node commands for the lookups in steps one to three are on the public page for verifying it yourself.

  1. Fetch the artifact and read carrier.txid and carrier.vout.
  2. Look up the address that carrier output pays.
  3. Confirm the block hash is a real block on the chain you care about, and note its height.
  4. Rebuild the message exactly and verify the BIP-322 signature against that address.
  5. Decide whether the block is recent enough for your purpose.
Verify against the carrier, not against a claim

Always read the carrier from the artifact record at verification time. If you verify against an address someone told you about, you are trusting the teller. The point of the exercise is to avoid that.

What it proves and what it does not

The left column is what a verifier can state after the signature checks out. The right column is what people will assume anyway, and none of it is supported.

Reading an attestation honestly.
ProvesDoes not prove
Somebody could sign for the carrier at or after that blockThat the signer is the original minter
The key is not lost, at least for that signerThat only one person holds the key
Combined with depth: unmoved since height H, and signable nowThat the same person held it for the whole stretch

Keys can be copied and keys can be sold. An attestation raises the floor on what is verifiable. It does not close the gap, and no message signature can. See What it does not promise.

Attestations are off chain

  • They cost nothing, publish nothing to the blockchain, and cannot reset depth.
  • The indexer does not require them and does not store them. Nothing in the state model depends on an attestation.
  • You can produce as many as you like, for as many different blocks as you like.
  • An artifact with no attestation is not suspicious. It is just an artifact whose holder did not sign anything.