Whitepaper
v1.0 · October 2026

Null Bond

Null Bond lets you hold a claim about an asset privately and prove it to exactly one counterparty at a time. Everything runs in the browser. The chain stores 32 bytes per bond, and only if you choose to anchor it.

1. Why

To prove you hold something onchain today, you usually connect a wallet. That hands the site your whole history: every balance, every transfer, every counterparty. Most of the time the other side needs to know one thing, not everything.

Null Bond separates the two. You seal one asset claim into a bond, keep the receipt to yourself, and show that receipt to the person who needs to check it. They learn that bond and nothing next to it.

2. Terms

TermMeaning
AssetA description of what the bond is about: type, network, contract or identifier, amount or token ID, and an optional memo.
CommitmentA 32-byte SHA-256 hash that binds the asset to a random salt and key. It reveals none of them.
ReceiptThe asset, salt, key and commitment together. Whoever holds the receipt can open and prove the bond.
AnchorAn optional Robinhood Chain transaction that carries the commitment, giving it a public timestamp.
PackageA receipt encrypted under a passphrase, used to hand a bond to someone else.

3. Sealing

The browser draws a 16-byte salt and a 32-byte key from crypto.getRandomValues, then computes:

A          = canonical JSON of the asset
commitment = SHA-256( "nullbond/v1" ‖ u32be(len(A)) ‖ A ‖ salt[16] ‖ key[32] )

The canonical JSON always lists the same five keys in the same order, with string values: type, network, id, amount, memo. The length prefix keeps the asset from bleeding into the salt, and the domain tag keeps a Null Bond hash from being confused with any other SHA-256 value.

Because the salt and key are random, two bonds over the same asset have unrelated commitments, and nobody can guess the asset from the hash. The label you give a bond in the console is never part of the hash and never leaves your device.

4. Receipts

A receipt is a small JSON object:

{
  "nullbond": 1,
  "asset": { "type", "network", "id", "amount", "memo" },
  "salt": "0x…16 bytes",
  "key": "0x…32 bytes",
  "commitment": "0x…32 bytes",
  "created": "ISO-8601",
  "anchor": { "chainId": 4663, "tx": "0x…" } | null,
  "prev": "0x…previous commitment" | null
}

To paste it in a message, the console encodes it as text: nullbond:receipt:1: followed by the JSON in base64url. The console accepts either form.

5. Anchoring

Anchoring is optional. It sends a zero-value transaction on Robinhood Chain (chain ID 4663) from your wallet to your own address, with this data:

data = 0x4e554c4c ‖ commitment      // "NULL" + 32 bytes

The transaction gives the commitment a block number and timestamp that anyone can read. It costs the gas of a plain transfer plus 36 bytes of calldata. Nothing else from your vault is sent.

Privacy note. The anchoring address is public, like any transaction sender. If you don't want a bond linked to your main wallet, anchor from a fresh one.

6. Proving and verifying

To prove a bond, send its receipt to one counterparty, or a proof link that carries the receipt in the URL fragment (/app#verify=…). Browsers never send the fragment to the server.

The verifier's browser:

  1. recomputes the commitment from the asset, salt and key in the receipt;
  2. compares it with the commitment in the receipt, and with an expected commitment if the verifier already has one;
  3. if the receipt names an anchor, reads that transaction on Robinhood Chain and checks that its data is exactly 0x4e554c4c ‖ commitment and that it succeeded.

The answer is one bit: true or false. The verifier sees the asset in that receipt, and nothing else you own.

7. Handing over

A hand-over moves a bond from one holder to the next without a server:

  1. The sender encrypts the receipt into a package. The key is derived with PBKDF2-SHA256 (600,000 rounds, 16-byte salt) from a passphrase; the receipt is sealed with AES-256-GCM (12-byte IV) and the associated data nullbond/package/1.
  2. The sender shares the package and the passphrase over two different channels.
  3. The recipient decrypts the package, checks that the bond inside verifies, and reseals the same asset under a fresh salt and key. The new receipt records the previous commitment in prev.

The sender's receipt still verifies after a hand-over until the sender discards it. Retiring the old commitment onchain is the job of the bond contract (section 9).

8. Storage and backups

The console keeps your receipts in this browser's local storage. There is no account and no server copy. You can export the whole vault as one backup file, encrypted the same way as a package (associated data nullbond/vault/1), and import it on another device.

If you lose both the browser data and the backup, the bonds cannot be opened again by anyone.

9. $NULL and roadmap

$NULL is the project token on Robinhood Chain, launched through Pons. Two contracts are planned around it:

Status. Sealing, anchoring as a plain transaction, hand-overs, backups and verification are live in the console today. Neither the bond contract nor the fee hook is deployed. Until they are, a bond is a cryptographic claim: it does not lock, escrow or move the underlying asset.

10. Security model and limits

11. Test vector

asset = {"type":"ERC-20 token","network":"Robinhood Chain",
         "id":"0x0000000000000000000000000000000000000001",
         "amount":"1000","memo":"example"}        // 134 bytes
salt  = 0x00112233445566778899aabbccddeeff
key   = 0x1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f

commitment = 0x4dc0dccf29190411cac65b3b8040755b6db5ca0898a3afe799a057c63a771043
anchor data = 0x4e554c4c4dc0dccf29190411cac65b3b8040755b6db5ca0898a3afe799a057c63a771043

The full implementation is a single file, nb-core.js, readable in any browser.