(STRATA)
[ written once, read forever ]
Robinhood Chain · rpc.mainnet · id 4663

STRATA/1 specification

A minimal, contract-free convention for anchoring cryptographic commitments in the calldata of Robinhood Chain transactions, inheriting Ethereum's data availability and finality by way of the rollup's batch posting.

Version 1, frozen. This document is normative; the site is a reference implementation of it. Where the two disagree, the document is right and the site is a bug.

§1Overview

STRATA defines a proof-of-existence primitive. A party in possession of some bytes computes a 32-byte commitment to them, embeds that commitment in a fixed 38-byte payload, and sends the payload as calldata in a zero-value transaction to a well-known address. Once the transaction is included in a block, the chain constitutes evidence that the commitment — and therefore, under the collision resistance of keccak-256, the underlying bytes — existed no later than that block's timestamp.

The design goals, in order of priority:

  1. No trusted intermediary. No contract owner, no upgrade key, no server, no database. A record cannot be revoked, reordered, or censored after inclusion.
  2. No state. The protocol writes nothing to chain state. Its entire footprint is calldata, which is exactly the surface that is published to Ethereum.
  3. Recomputable from first principles. A reader with a JSON-RPC endpoint and a keccak-256 implementation can verify any record. No indexer, no SDK, no API key.
  4. Constant, minimal cost. Every record is the same size regardless of what it commits to: one file or ten thousand.
Design noteSTRATA deliberately declines to deploy a contract for version 1. A contract would add a storage write (dominating the fee), an upgrade surface, and a party to trust. The rollup's own transaction index already provides everything a registry would: ordering, timestamps, authorship, and permanence.

§2Payload

A STRATA record is a transaction whose to field is the sink, whose value is zero, and whose input is exactly 38 bytes laid out as follows.

offset  len  field     encoding
0x00    4    magic     0x53545241  ASCII "STRA", fixed
0x04    1    version   0x01        this specification
0x05    1    kind      0x00        keccak-256 digest of a byte string
                       0x01        sorted-pair Merkle root over keccak-256 leaves
0x06    32   digest    big-endian 32-byte commitment
total   38 bytes

A reader MUST reject a transaction as a STRATA record if any of the following hold:

A reader SHOULD surface, rather than reject, a record whose version byte is unrecognised: future versions are expected to keep the magic and the version byte in place, so a version-1 reader can still report "this is a STRATA record of a version I do not understand" rather than silently discarding it.

The kind byte is advisory. It tells a reader how the digest was constructed so that a verifier can reproduce it, but the chain enforces nothing about it. A record whose kind is 0x01 and whose digest happens to be a plain keccak-256 hash is well-formed and indistinguishable; the semantics live entirely in the manifest the sealer keeps off chain.

§3The sink

All records are addressed to a single address, the sink:

0x00000000000000000000000000000000005ea1ed   the low bytes spell "5EA1ED"

The sink has three properties that matter:

It has no code.
A transaction to it executes nothing. The gas cost is the intrinsic transaction cost plus calldata, and there is no execution path that can revert, so a well-formed seal cannot fail for protocol reasons.
It has no known private key.
The address is a low-numbered constant chosen for legibility, far outside the range any keypair generator will produce. Nothing sent to it can be moved. This is intentional: the sink is a destination, not an account.
It is a filter, not a gate.
Addressing every record to one place turns "find all STRATA records" into a single indexed query on any block explorer, and makes a record trivially distinguishable from ordinary traffic. It confers no authority: anyone may send to it, and nobody may stop them.
Do not send valueEther sent to the sink is destroyed. The protocol specifies value = 0 and the reference implementation hard-codes it. Wallets that helpfully "round up" a transaction's value should not be used for sealing.

§4Digest construction

For kind = 0x00, the digest is the keccak-256 hash of the committed byte string, with no prefix, no length encoding, and no domain separator:

digest = keccak256(bytes)

This is the same primitive Ethereum uses, so every existing tool already computes it: cast keccak, ethers.keccak256, web3.keccak, pysha3, js-sha3. Note that this is the original Keccak padding, not NIST SHA3-256; the two produce different output for the same input and are not interchangeable.

For text, the committed bytes are the UTF-8 encoding of the string, unnormalised. Two strings that differ only in Unicode normal form produce different digests. Applications that need stable text commitments should normalise (NFC) before hashing and say so in their manifest.

For files, the committed bytes are the file's contents verbatim. Filenames, timestamps and permissions are not committed to; if they matter, commit to an archive or to a manifest that names them.

§5Merkle manifests

For kind = 0x01, the digest is the root of a binary Merkle tree over the keccak-256 leaves of each committed item, using sorted-pair hashing:

parent(a, b) = keccak256( min(a,b) ‖ max(a,b) )

Sorting the pair before concatenation removes the need to carry a left/right bit in each proof step, which halves the bookkeeping in a verifier at the cost of not distinguishing sibling order. This is the same construction OpenZeppelin's MerkleProof library uses, so an on-chain verifier for STRATA manifests is four lines of Solidity.

Tree construction rules:

Manifest format

The manifest is the off-chain half of a kind = 0x01 record. It is not consensus-critical and the chain never sees it; it exists so a third party can be handed one file out of a set and check it against the root.

{
  "strata": 1,
  "kind": "merkle",
  "root": "0x<32 bytes>",
  "algorithm": "keccak-256 / sorted-pair",
  "leaves": [
    { "name": "contract-v3.pdf",
      "size": 184320,
      "leaf":  "0x<32 bytes>",
      "proof": [ "0x<sibling>", "0x<sibling>" ] }
  ]
}

To verify one item: hash the file, check it equals leaf, then fold the proof with sorted-pair hashing and check the result equals root. Then verify root against the chain per §7. The manifest is worth keeping alongside the files it describes; without it, a root commits to the set but cannot be opened for any individual member.

§6Writing a seal

A seal is an ordinary transaction. Any signer that can set an arbitrary data field on chain 4663 can produce one; the reference site is a convenience, not a dependency.

From a browser wallet

await ethereum.request({
  method: 'eth_sendTransaction',
  params: [{
    from,
    to:    '0x00000000000000000000000000000000005ea1ed',
    value: '0x0',
    data:  '0x53545241' + '01' + '00' + digestHex
  }]
});

From the command line

# foundry
cast send 0x00000000000000000000000000000000005ea1ed \
  --rpc-url https://rpc.mainnet.chain.robinhood.com \
  --private-key $KEY \
  --value 0 \
  0x535452410100$(cast keccak "$(xxd -p file.bin | tr -d '\n')" | cut -c3-)

Network parameters

ParameterValue
Chain ID4663 (0x1237)
NameRobinhood Chain mainnet
RPChttps://rpc.mainnet.chain.robinhood.com
Explorerhttps://robinhoodchain.blockscout.com
Native currencyETH, 18 decimals
ArchitectureArbitrum Nitro rollup settling to Ethereum

The public RPC endpoint is rate limited and is not intended for production write loads. An application sealing at volume should run its own node or use a dedicated provider; the protocol is indifferent to which endpoint a writer uses.

§7Reading a seal

Verification is four RPC-free steps and two RPC calls. No part of it requires this site, and a verifier should not use this site if the thing being verified is adversarial to its operator.

  1. Fetch the transaction. eth_getTransactionByHash. If the node returns null, the hash is unknown to that node; try another before concluding anything.
  2. Check the envelope. to equals the sink; input is 38 bytes; magic matches. Reject otherwise.
  3. Extract the digest. The last 32 bytes of input.
  4. Fetch the block. eth_getBlockByNumber on tx.blockNumber. Its timestamp is the upper bound on when the digest existed. Its l1BlockNumber names the Ethereum block the rollup referenced, which is the anchor for §8.
  5. Recompute. Hash the bytes you hold and compare, constant-time or otherwise, to the extracted digest.

A verifier MUST confirm the transaction has a non-null blockNumber. A transaction in the mempool has been seen but not ordered, and carries no timestamp claim whatsoever.

What a match provesThat the party who paid for this transaction possessed bytes hashing to this digest at or before this block's timestamp. Nothing more. It does not prove authorship, originality, ownership, or that the bytes were not also known to others.

§8Fees

The cost of a seal is the intrinsic transaction cost plus the calldata cost of 38 bytes, priced under the rollup's fee model. Nitro chains charge an L2 execution component and an L1 data component; the latter dominates for a transaction that does nothing but carry bytes, and it tracks Ethereum's base fee rather than Robinhood Chain's.

ComponentCost
Intrinsic21,000 gas
Calldata38 bytes, 16 gas per non-zero byte, 4 per zero byte
Storagenone — the protocol writes no state
L1 datacompressed share of the batch, charged by the sequencer

The site estimates the live figure with eth_estimateGas against the current base fee and displays it in layer.03 before you sign. In practice a seal has been costing a small fraction of a US cent; it is not a number worth designing around, but it is not zero, and an application sealing per-event at high frequency should batch into a Merkle root instead.

§9Settlement

Inclusion in a Robinhood Chain block is not the same as finality on Ethereum, and a rigorous verifier distinguishes three stages:

Sequenced (seconds)
The sequencer has ordered the transaction and emitted a block. This is what eth_getTransactionReceipt returns and what the site reports as "sealed". It is a commitment by the sequencer, backed by its reputation and the rollup's escape hatch, not yet by Ethereum.
Batched (minutes)
The transaction's calldata has been compressed into a batch and posted to Ethereum. From this point the data is available to anyone reconstructing the chain from L1, and the record survives the sequencer disappearing entirely. The l1BlockNumber field on the block names the L1 block the rollup was tracking at the time, which bounds where to look.
Settled (the challenge window)
The state root covering the block has been posted and its dispute period has elapsed without a successful challenge. For a proof-of-existence claim this stage adds little: the claim rests on data availability, which batching already provides, not on the correctness of any state transition.

This distinction is the practical answer to "how long should I wait?" — for a timestamp claim, until batched. STRATA reports the sequenced block immediately and gives you the L1 reference so the batch can be located; it does not currently watch for the batch itself, which is item two on the roadmap.

§10Threat model

Stating what a system does not do is more useful than restating what it does.

What STRATA resists

What STRATA does not resist

§11FAQ

Why Robinhood Chain rather than Ethereum directly?

Cost and the same guarantee. The bytes end up on Ethereum either way — that is what a rollup does — but they arrive compressed and amortised across a batch, so the marginal cost of one 38-byte record is a fraction of what the equivalent L1 transaction costs. The data-availability property a timestamp claim rests on is preserved.

Is there a token?

No. There is nothing to buy, nothing to stake, and no mechanism by which the protocol could have one: it is a byte layout and an address.

Can I seal the same digest twice?

Yes, and nothing stops you. Duplicate records are well-formed; the earliest one is the meaningful claim. A reader looking for the first occurrence of a digest should scan the sink's history and take the lowest block number.

Can someone else seal my digest?

Yes. Anyone who learns a digest can seal it from their own address. What they cannot do is produce the preimage, which is what an opened claim requires. If the ordering of claims matters to your application, bind the digest to an identity — hash bytes ‖ address, or sign the digest and commit to the signature.

What if the explorer index is down?

Layer.05 degrades to seals made from your own browser and says so. Verification in layer.04 is unaffected because it reads from an RPC node, not from the explorer. The index is a convenience over the chain; it is not the chain.

Is the site custodial in any way?

No. It never receives a file, never receives a private key, and holds no funds. Hashing happens in your tab, the transaction is signed by your wallet, and the destination is an address nobody controls.

§12Roadmap

Version 1 is frozen. Everything below is additive and none of it invalidates an existing record.

Salted commitments (kind = 0x02)
A specified salting scheme, so low-entropy preimages get a documented answer rather than a footnote in §10. The manifest carries the salt; the chain sees only the salted digest.
Batch watcher
Follow a sealed transaction from sequenced to batched and report the L1 batch transaction that carries it, closing the gap described in §9.
Registry v2 (optional contract)
A contract exposing sealedAt(digest) and a Sealed event, for applications that need on-chain lookup or log-based indexing. It costs a storage write and is strictly optional; version 1 records remain valid and readable without it. Source is in contracts/StrataRegistry.sol.
Reader library
A dependency-free reader, under 100 lines, published so that verification does not route through a web page at all.

§13Changelog

VersionStatusChange
STRATA/1frozenInitial specification. Magic, version, kind, digest. Kinds 0x00 and 0x01. Sink fixed.

This document describes an experimental protocol on a public blockchain. Records are permanent and public. Nothing here is legal, financial, or evidentiary advice, and a blockchain timestamp is not a substitute for a jurisdiction's rules of evidence.