Sources and checks

Every claim in the guide can be traced to the public material below. It was read on 28 October 2026 between 9:28 and 9:32 Beijing time, when the official site reported block 973,478. The collection data was checked again at block 973,511 while revising; NAKA's off-chain listings were still not active.

Version record

SHORD is changing fast. Each edition names the data and code it rests on; check the date here first. Later editions go at the top of the table.

EditionLive dataCodeChanges
2026-11-03As before; the project's posts of 27 October and 2 November read on 2 November, the site's /shielded page script downloaded 3 NovemberAs before, plus the site page script 9a2884728479369d.js and its Chinese messages 624a1b6e0181a28a.js (archived in site-2026-11-03)From the project's new posts: NAKA isn't moving to off-chain listings (chapter 05, appendices I07 and K, glossary); claimed SHNAKAS are pouches that split, send privately, trade on the pouch market from 6 November, and burn into Snickets for GTD spots and votes (chapters 06 and 07, the privacy table, appendix I07). From Grok's review: details repeated from legends, cards and the appendix cut from chapters 01, 02 and 07; the miner gets its own row in the flow table; the flow charts' swipe hint names charts; the odd 0 on the copy's sign in plate 01 is red; "nothing hidden" in the privacy table now reads "nothing, all public"; the colophon keeps dates and sources; the relay minutes left the answers (appendix I04 has them). Appendix K's "opening" is now "the note's details". Coined or literal terms replaced throughout the Chinese edition, using the official site's Chinese where it has a word; in English, "reward lot" and "fixed lots" now say pouch (the rules start with three fixed pouches of 80), and the LIST3 window reads as how long a listing lasts. The same day the site's vault, market and lounge were checked page by page with a test vault: voting privacy corrected (the service publishes each vote's tag, made from the nullifier, so once a note is spent anyone can see how it voted, and a listed one shows its number: chapter 06, privacy table, appendices B, I06) and what a bonus claim shows (the pouch stays tied to the piece); the site's warnings added (two receiving addresses, no sends from the paying wallet before the block, the vault-moving code and link are the vault, never open a vault link someone sends); the Shielded Vault's install and PIN, the Staking page, the global Shielded #, instant pouch listings and tester-only trading before 6 November, Snickets and GTD codes, and the Naka Lounge; credits status updated to 3 November. Same day, chapter 01 revised after the Grok and Codex reviews: the rebuild condition follows the site's import page (same wallet, account and address type; anything else opens a new, empty vault); notes are found with the view key and the spend key together (reward notes without a ciphertext come from the nullifier); the return key and the payout are per listing, and card 01 groups the keys by what goes into them. Same day, chapter 08 retitled “Who keeps the ledger, and can you check it?”, the privacy boundaries page moved into appendix B, and the PDF is down to 14 pages. The quick answers are reordered from simple to deep and balanced across two columns; the safekeeping page gets a lead, and its address point follows the site's receive page. On 4 November the appendix lost its repetitions and writes the shielded address one way (128 hex characters), and appendices H and K have some titles and questions rearranged.
2026-11-02Relay status and on-chain records rechecked 2 November (block 974,196); the rest as beforeAs before; site client unchanged on 2 NovemberAfter an outside review, each point checked against the code: ctxNf counted per piece, the address holds the owner key, card 00 encrypts to the view key, 330 sats is the official relay's lock amount and not a protocol limit, the relay window with its source, racing a listing needs another platform signature, one return key per listing, what the digest covers and the order of checks, name lookups and reserved names, dust lines; the relay's new sending wallet since 29 October; five new common questions (taking a piece out, a wrong address, how long a send takes, one address for every collection, what a developer can build). The review's point that a sender can't follow later reward claims and sends does not hold; see appendix K. The same day: two more questions (the hosted API's key, downloading the engine and proving keys), appendix D on the single contribution recorded in the site's proving keys, and appendix H on saving the proving key beforehand. Same day, second pass: repetitions removed throughout, three quick answers replaced (wrong address, how long a send takes, the setup secret), the privacy sheet's two lists merged, dark digits on gold markers; the English chapter 08 had called the relay's 5,517 transactions relayed envelopes and is corrected, no other fact or figure changed
2026-11-01Read 28 October (block 973,478); listings, the relay and shielded names rechecked 29 to 31 October, see the rows belowPublic commit 3cdbdfdf (12 October, still the latest on 1 November); site client SHA-256 57457629…1dc (read 28 October, unchanged on 1 November)First edition

1 Live material that was read

MaterialAddressUsed to check
CollectioncollectionNAKA's rules, fees, listing mode and which child is which piece
StatusstatusHeight 973,478 and 9,947 notes at the time
Public statestatePublic fields, listing locks, order states, reward records
RewardsrewardsThe reward plan, each week, base and bonus claim counts
Official clientshielded-browser.jsKey derivation from the signature, scanning, proofs and transaction building, reward eligibility, splits
Premine transactionmempool.spaceThe SHNAKAS premine: amount, divisibility, which output it points at, whether it was spent
Shared addressmempool.spaceThe NUMS address holding the art and the premine
Relay addressmempool.spaceThe official relay's address for fees and relayed envelopes: transaction shape and count

The client file read was 567,545 bytes with SHA-256 57457629898f529fa3ff8050509620d05202adb50fdfc5318375eca0381c61dc. The code was read, not run, and nobody's keys were touched. Every response was archived with its time, HTTP status and SHA-256, including one status request that timed out.

2 How the guide's claims were checked

ClaimEvidence, and how far it reaches
All inscribed NAKA pieces sit at one NUMS addressThe NUMS point was recomputed following BIP341. In all 26 of NAKA's child inscription transactions, the outputs to this address equal the inscriptions in the transaction, 3,327 in total. The parent isn't included; this counts outputs and is not a full Ordinals replay
The 21M SHNAKAS premine sits at the same addressThe premine's Runestone: Pointer=1, Premine=2100000000000000, Divisibility=8. Output 1 is this NUMS address and was unspent when read. Field meanings checked against the Runes specification
A leaked unlock signature rebuilds the vault, vault BTC includedThe official client holds the fixed message and the derivation: seed = SHA-256("shord/seed/v1" ‖ sig), then shord/spend, shord/view, shord/return, shord/payout, shord/btc, shord/listing and shord/bonus. The vault's withdrawal signs with keys from shord/btc and shord/payout, so a leaked signature exposes the vault's own BTC too. The wallet's own keys are not among them
A confirmed BTC payment is not a completed saleBitcoin script and SHORD validation are separate layers. The protocol document says a BUY that pays wrongly is rejected, and the spent lock closes the listing
The platform can close a listing but can't take the note or the moneyNAKA is a single-key collection: the listing lock's internal key, lockKey, is the platform's key (scripts.mjs; PROTOCOL-v1.md, Listing lock: spending the lock is how the platform closes a listing). Taking the note back needs a CLAIM signed with the seller's return key, and the price goes to the seller's payout script. The 1,008-block relative lock counts from the block that confirms the lock
Nobody can spend from the art's addressThe address's key is the BIP341 NUMS point with no script tree (recomputed, matching the script on chain). "Nobody knows the private key" rests on the usual cryptographic assumptions
Sending to yourself also breaks the current weekThe client's start-week and end-week logic for each note (see card 07). A note made by a reward claim starts in the week it was made, so a normal claim doesn't break the week
A base claim keeps the number private; a bonus claim shows itThe client's code for building base and bonus claims; the bonus carries the number
Private pieces are not private BTCVault receipts and withdrawals use ordinary Bitcoin outputs. One-time addresses are not a mixing pool
The 20,000-sat fee examplecollection has saleFeeBps=200 and saleFeeMin=1000. It is arithmetic, not a market price
NAKA still uses old-style listingscollection shows listings3.active=false for NAKA, and every NAKA listing lock in state is 330 sats. Trollbox and COMMEMORATIVE COINS have LIST3 on, with a 1% fee and a 1% royalty
How weights worknaka-sigil's rules audit: a 100% base; trait floors at 1.25, 1.5, 2 and 3 times the collection floor add 25%, 50%, 75% and 100%; a number bonus; a 400% cap; rescored every block, matched piece by piece against the official weights endpoint. A private claim pays the 100% base; showing the number pays the full weight
The phone app's 24 words are the vault seedThe official vault page's scripts (saved in sources/site-2026-10-28/): the 32-byte vault key plus a checksum byte become 24 words, and the app says "They are not the seed phrase of any other wallet." The forgotten-PIN text says the 24 words, or importing again from UniSat or Xverse, bring the vault back. The restore option reads "The 24 words of a Shielded Vault", and the security note "On a phone, use your browser's Add to Home Screen to keep this wallet as an app": the Shielded Vault opens on a phone or in a browser, and the 24 words give the same vault in either
Private votingThe site's vault page script (archived as sources/site-2026-10-28/f8c37337f94602c5.js, with ordz-vote-v1 and ordz-vote-tag-v1) takes the root at the round's snapshot height, makes a proof with the spend circuit (nullifier among the public inputs, topic, round and choice hashed into hbody) and posts it to /topics/{topic}/ballots at backend-vote-production.up.railway.app/api/vote; the client handles an "already counted" reply. Read-only GET /topics on 29 October 2026: one open topic, round 1 snapshot at height 972,645, 1,399 ballots (archived as vote-topics-20261029.json). Eligibility, deduplication and tallying on the server weren't reproduced
A holder proof doesn't stop someone who soldholder.circom checks only that the leaf is in the tree, and the record tree in tree.mjs only grows, so old leaves stay. The protocol document's "only a 6-block window remains" doesn't match the code, and the guide doesn't repeat it
What the digest coversstateDigest in indexer.mjs (digest v1): tree root, leaf count, the nullifier set, minted numbers, and each listing's number, state, credits and price
The notes need no backup; the keys bring them backThe envelope format in envelope.mjs: mints, transfers, purchases and claims carry an ephemeral public key and an 88-byte ciphertext whose plaintext is the piece, the credits and the two random values (core.mjs). When the official client scans for notes, it opens each ciphertext with the view key; batch reward notes, which have none, take their random values from the previous note, and the commitment is checked. The client is a computation library with no code that uploads a vault; whether the site's pages store anything themselves wasn't checked
A wrong ciphertext leaves the receiver unable to find the notePROTOCOL-v1.md, "Still open": the circuit doesn't check a transfer's ciphertext; in every paid flow the receiver makes the new note
The public code can't recompute the full live ledgerThe public code's message types stop at 6 (MINTN) and anything else fails to parse; the live client also has rewards 7–10, LIST3 11 and SPLIT 12. At block 973,352 the official /status reported 9,882 notes and the public code, run to the same height, 8,678, with a different digest. The gap wasn't traced transaction by transaction
Two indexers agree when the rules matchdocs/STATUS.md in the public repository: no clocks, randomness or server data take part in acceptance; an independent replay on 11 October 2026 matched the official digest at block 970,879
The same wallet always opens the same vaultThe official vault page's scripts: UniSat is called with signMessage(message, "ecdsa") and Xverse with protocol: "ECDSA", both with the payment address used to connect; a different address is refused. The app's own words: "The same wallet always opens the same vault." Saved copies and SHA-256 in sources/site-2026-10-28/SHA256SUMS
The BTC for relay credits goes to the relay payout address in the rulesPROTOCOL-v1.md: relayerPayoutScript receives ticket and inscribe fees, "to the wallet that spends them, so the relayer/inscriber funds itself". indexer.mjs requires buy × ticketPrice paid to that script. NAKA's parent inscription sets relayerPayoutScript 5120be2563233bb4feb149c3a6111f67a2ec5061991921d97406c78ca48614fefe43, i.e. bc1phcjkxgemknltzjwr5cg37eaza3gxrxgey8vhgpk83jjgv987leps3t3cuy, and ticketPrice 2,500. None of the six public message types turns credits back into BTC
Who computes the commitmentThe Notes section of PROTOCOL-v1.md: notes from a mint, purchase or claim are built by the receiver, who publishes only inner and a ciphertext, and "the indexer computes cm from the public assetId and ticket count". In a private transfer the sender's vault computes cmOut and puts it in the envelope, and the circuit proves it matches
What an indexer stores, and what it can't tell after a private sendThe engine fields in indexer.mjs: the record tree, the nullifier set, every block's root and leaf count, the note list (position, commitment, epk, ciphertext), mints, listings and lock positions. checkpoint.mjs states that a loaded engine equals, field for field, one replayed from the start block. A private transfer (mode 0) has assetIdPub = 0 among its public inputs, so the indexer gets only cmOut
While listed the piece is tied to the lock, which can be spent two waysThe Listing lock section of PROTOCOL-v1.md: the lock is P2TR(internal = lockKey, leaf = "<1008> CSV DROP <returnKey> CHECKSIG"); the platform co-signs only a transaction that pays correctly; a cancel carries the seller's CLAIM in the same transaction; a lock spent without a valid BUY closes the listing; after 1,008 blocks the seller can spend the lock alone. Once closed, the seller can send a CLAIM on its own at any time, with no wait: the document says "A lock spent with neither leaves it CLOSED until the seller publishes CLAIM", and indexer.mjs accepts a CLAIM for a CLOSED listing, or an ACTIVE one whose lock this transaction spends. A LIST must make the lock in the same transaction (otherwise "listing lock output missing"); the indexer doesn't check how many sats it holds. One transaction can carry several envelopes: the document's Relay batches section has the relay put a window's envelopes into one transaction (so the lead of chapter 05's second page no longer says one transaction, one envelope per step)
Sale proceeds land at fresh addresses the vault can find againThe official client: the seller's payout script is derived from shord/payout and the listing nullifier, and the vault matches the payout scripts of sold listings to find its own sales
A listing's payout address isn't limited to bc1p; bc1q and 3… work tooPROTOCOL-v1.md sizes the LIST envelope with P2WPKH (381 bytes) and P2TR (393) as examples; envelope.mjs allows a seller script of 1 to 80 bytes; indexer.mjs only requires the price to clear dustFor in rules.mjs (330 for P2TR, 294 for witness v0, 546 otherwise); the site's "Another address" goes through a node's validate-address to get the scriptPubKey (saved site-2026-10-28/f8c37337f94602c5.js, s5 → scriptOf; 62ebc8185a14617d.js, ez); the site's state (2026-10-29, height 973,703, counts in sources/review-2026-10-29/listing-seller-scripts.json) held 5,233 listings: 4,622 starting 5120, 311 starting a914, 300 starting 0014, all three with SOLD entries; on-chain example 5b54a01b…2c18: two LIST envelopes in one transaction, one seller script a914, one 5120
The project's posts of 27 October and 2 November (read 2026-11-02)27 October: "Every Shielded collection except Nakas lists, reprices and cancels instantly. Nakas stay exactly as they are."; pouches split, send privately, list and buy, open to everyone on Friday 6 November. 2 November: "Break any SHNAKAS pouch into up to 16 smaller pouches in one transaction. Send exactly the amount you want to any vault."; SHNAKAS burn one for one into Snickets, burned ones "gone for good", arriving two blocks later; Snickets take GTD spots and vote (against too, and without a Naka); the pouch market opens 6 November: list, buy, sweep up to 10 pouches. Used in chapters 05, 06 and 07, appendices I07 and K, and the glossary. The syndication endpoint returns only the first 303 and 293 characters; the full text came verbatim from an X search
A burned pouch can't be spent; Snickets are kept on the platform's books (chapter 07, appendices B, I07)Site /shielded page script 9a2884728479369d.js (downloaded 2026-11-03, archived in site-2026-11-03), module 403698: burnSpendKey(key) = SHA-256("Shielded Ordinals SNICKETS burn v1" ‖ 0x00 ‖ key), first byte zeroed; burnAddressOf = "shord1" ‖ burnSpendKey ‖ view key; BURN_CONFIRMATIONS = 2; the Snickets key = SHA-256("shord/snickets" ‖ seed) mod the secp256k1 order, signing Schnorr. Balance, burn, spot and vote go to /snickets/balance, /snickets/burn, /snickets/spot and /snickets/vote, each signed with that key; a vote carries topic, round, choice, for or against, votes and price, the price from /snickets/vote-price. Site engine walletFromSeed: owner key pk = Poseidon(sk); the burn address's owner key is a SHA-256 output, so spending it takes a Poseidon preimage. The burn flow (archived f8c37337f94602c5.js) checks decodeAddress(burn address).pk equals burnSpendKey, then sends the whole pouch or splits to it. How the server books Snickets can't be seen. Rechecked against the vault page scripts downloaded on 3 November at 07:07 UTC (archived site-2026-11-03/a926e8a6d1e1b3eb.js, ec986fe65a6649cf.js), all of the above unchanged: BURN_CONFIRMATIONS is still 2, the burn address and the Snickets key are worked out the same way; a burn posts to /snickets/burn/build, signed with the Snickets key over "pending" and the envelope hash, a whole-pouch burn (buildTransfer to the burn address) with opening {assetId, tickets, s}, a burn of part of a pouch (buildSplit into [kept, burned], the burned one to the burn address) with burnOuts and openings {out, ρ, s}; the fee is paid from the vault's BTC (selfPay, spend 0), and the page says "Nothing is relayed.", "1 {rune} burned = 1 Snicket. Whole {rune} only.", "Your Snickets arrive by themselves after {n} blocks". A vote request signs topic, round, choice, direction, votes and price (/snickets/vote, at most 500 votes at once), the price coming from /snickets/vote-price and the server answering a changed one; the page says "Snickets spent on votes are gone for good.", and a vault with no Naka sees "Hold a Naka to vote in the next round, or vote with Snickets below."; each entry of the public log /topics/…/boosts has only an id, the choice, the direction, the votes, the price and a time
Chinese wording follows the site's Chinese interface (助记词, 粉尘限额, 蚀刻, 钱袋, 预付中继, 隐私地址)The site's Chinese messages 624a1b6e0181a28a.js (downloaded 2026-11-03, archived in site-2026-11-03; the page loads it under NEXT_LOCALE=zh-CN): "Recovery phrase" is 助记词, "dust limit" 粉尘限额, rune etching 蚀刻 with commit and reveal as 提交 and 揭示, "Pouch" 钱袋, "Prepaid relays" 预付中继, "shielded address" mostly 隐私地址. The interface has no words for nullifiers, commitments or return keys; the Chinese edition uses plain ones
The vote's public tag log can be matched by nullifier (chapter 06, appendices B, I06, K)The vault page script of 3 November, cd53361caaa1b5b2.js (archived in site-2026-11-03): voting still uses the spend circuit, hbody = SHA-256("ordz-vote-v1" ‖ collection ‖ topic ‖ round ‖ choice), and {choice, publicSignals, proof} is posted to backend-vote-production…/api/vote/topics/{topic}/ballots, publicSignals holding the nullifier; the tag = Poseidon(nullifier, SHA-256("ordz-vote-tag-v1" ‖ topic ‖ round), first byte zeroed). The public /topics/{topic}/tags?round=N lists each vote's tag, choice and time, and /boosts?round=N the Snickets votes (archived as vote-topics, vote-tags-r1, vote-tags-r2, vote-boosts-r2, downloaded 3 November). The vote page: "The vote service sees a one-time tag per Naka per round, never the piece or the vault." Check: tools/vote_tag_check.mjs computes the tag of every nullifier in the site's /state (height 974,323: 7,865 nullifiers, 5,415 listings; archived as state-974323-20261103.json.gz); round 1, 888 of 1,463 votes, 38 from listing nullifiers; round 2, 82 of 774, 8 from listings. Counts only, no pieces recorded
How far the vote's tally, de-duplication and eligibility can be checked (chapter 06 card, appendices B, I06)The vote service (backend-vote-production.up.railway.app) verifies proofs, de-duplicates and tallies on its own server; the vault page script only makes the proof and submits the ballot, so no browser can read that code. What the public records allow: the archived /api/vote/topics of 3 November (topic next-launch-oct, round 2, snapshot 973,899, totals) and all 774 entries of round 2's /tags. tools/vote_round_check.mjs finds: the count per choice matches the totals exactly (774 and 774), and no tag repeats; computing tags from the site's ledger (height 974,323) by the site's formula matches 82 votes, all of them notes spent after the snapshot block, none before; the other 692 have nullifiers still off chain and the proofs aren't published, so their eligibility can't be checked. Round 2 also has one Snickets vote (/boosts); the totals give that choice 23, the same as its tag count, so whether Snickets votes are counted separately can't be told from the data
What the site's vault says and warns (chapters 06, 07, reminders, appendices I07, K)ord-dropz.xyz/wallet walked through on 3 November with a test vault (Pieces, Tokens, Staking, Market, Vote, Activity, Bitcoin, Settings; page text archived in site-2026-11-03/pages/), text checked against the site's message files fbaabcc7fccab287.js and 624a1b6e0181a28a.js: Staking "Nothing to sign, nothing to lock", "A piece you receive or buy starts earning the week after it lands", "One claim pays every week earned so far, so the fee is per claim, not per week"; showing a piece "Those SHNAKAS stay linked to the piece, also after you sell them", "that it was not listed, sold or sent from the start of the first claimed week until now", "If that was your wallet and you have not sent the piece privately since, people can link these claims to that wallet"; receiving "Pieces and bitcoin go to two different addresses", the BTC address "Never send ordinals, inscriptions or runes to this address"; self-paid "Until the block lands, do not send bitcoin from this wallet: a send from the same wallet can replace this transaction"; moving to a phone "Whoever scans this code gets your vault", "This link IS your vault until it is used … It works once", "The link works once and for five minutes", and on opening one "If someone sent you this link, stop. It would open their vault here, and anything you buy or deposit would be theirs"; install from the home screen on iOS, a package on Android, Chrome or Edge on a computer, "No app store"; the PIN "cannot be recovered". Snickets "Whole SHNAKAS only", "One burn comes out of one pouch"; GTD "One spot = one code = one mint, from any wallet", the confirmation "if you don't mint in the GTD phase, the Snickets are not returned" against the codes note "One not used by the end of its phase gives its Snickets back". Pouches "Buying and listing SHNAKAS is open to a few testers first. Sending, splitting and burning are open to everyone", "Trading opens Friday, Nov 6", instant listing "the first listing from this vault makes one 330-sat coin". A Snickets vote is "what a base Naka earns in a week, live"
Collection configs: global numbers, credits, instant listing (glossary, appendices I04, I07)The site's /collection on 3 November (archived as collection-naka, collection-coins, collection-trollbox, collection-shnakas): global.start is 0 for NAKA, 3,333 for COMMEMORATIVE COINS and 3,833 for Trollbox, and the market's and Staking's "Shielded #" is globalNumber = global.start + number (script cd53361caaa1b5b2.js); NAKA relayTokens.creditsOff false, listings3.active false, maxPerWallet 5; SHNAKAS listings3.active true, access "list", split.maxOuts 16, saleFeeBps 200 and saleFeeMin 330, ticketsPerLot 1
Naka Lounge (appendices I07, K)The project's 2 November post (23:13 UTC): No-Limit Hold'em with SHNAKAS chips, connect the vault and deposit with one confirm, cash out to the vault any time; "Every card is locked in before the deal, and your device checks it", "The lounge shows what it owes against what it holds, 1:1"; rake "5% of hands that see a flop, max 2 big blinds", saved and burned; limited time. The lounge page (play.ord-dropz.xyz, seen 3 November): "Chips are real SHNAKAS, held in the lounge box while you play". Vault text walletLounge: the lounge gets an ID made from the vault and the vault's address (code connectAnswer: the player key account, the shielded address home, the vault's BTC address btcHome and a signature, archived as site-2026-11-03/7f10f4358f40d09a.js), "every cash-out comes back here and only here", "It can never move anything in your vault". Deposit code (cd53361caaa1b5b2.js): buildSplit cuts the pouch into [rest, deposit], the deposit to the lounge's address, the same transaction paying the lounge's fee address 330 + prepaySats + houseFeeSats; the 21 such splits this machine recorded up to 3 November all pay 3,330 sats to the fee address, to 13 different addresses (each read from the local esplora)
No third-party access to the lounge or the vault (appendix K)Vault page scripts (downloaded 3 November, archived as site-2026-11-03/7f10f4358f40d09a.js, ec986fe65a6649cf.js): LOUNGE_ORIGINS defaults to https://play.ord-dropz.xyz, LOUNGE_APIS to https://lounge-api.ord-dropz.xyz; connect and deposit requests go through loungeOriginAllowed and loungeApiAllowed, and anything else shows "{origin} is not the Naka Lounge. Nothing was shared."; connecting gives only loungeKeyOf (a player key from the seed and "naka-lounge/v1"), the shielded address, the BTC address and a signature. Holder proofs (a926e8a6d1e1b3eb.js): the Prove button's purpose is fixed as holder-demo, sent to the site's /holder/verify; listing coins use listing-coins. The public repository's README: "The code that builds transactions (minting, listing, buying, sending, withdrawing) and the wallet are not in this repository."
The founder's posts on X (read 2026-10-30)Price public, holder private: post 1; credits no longer sold later on, network fees paid from vault BTC, prepaid relays kept, listing/reprice/cancel to stay off chain until the sale, SHNAKAS shares skipped while listed: post 2; sale proceeds sent out from the vault to a bc1 address, shord1 is not a Bitcoin address: post 3; rules in the parent inscription, indexer to be open for anyone to run: post 4. Used in appendix I04 and the quick answer on where the BTC goes after a sale; since 3 November chapter 05's line on off-chain listings rests on the 27 October post in the next row. Only the first 297 characters of the long post could be fetched here (the syndication endpoint omits long text); the "CREDITS GONE" section was quoted verbatim by the search: "Same update kills relay credits. No more buying tickets to do private actions. Your vault's own bitcoin pays the network fee, same as any wallet. Old credits still work if you have them, nobody loses anything. Prepaid relays stay as an option for people who want the extra privacy. The platform never pays for anything, which is what keeps it honest."
The trusted setup secret: what it allows, and the fixdocs/STATUS.md: "The proof setup was a single contribution … The secret from that run is discarded by the software, but nobody outside can verify that it was. Someone who held it could forge a proof and create a duplicate of a piece (never take one out of a vault)." ceremony/ceremony.mjs: phase 1 is the public Perpetual Powers of Tau; the script runs a phase-2 multi-party ceremony, "the key is safe as long as ANY ONE contributor destroyed their randomness", ending with a Bitcoin block hash named in advance. indexer.mjs: a transfer is checked only for its anchor, an unseen nullifier and a valid proof, and only then is the nullifier recorded and the commitment added. The site's state on 2026-10-29 (height 973,703, 5,233 listings) has no number with two ACTIVE listings at once, and none listed again before its previous listing ended. PROTOCOL-v1.md: "The indexer refuses to start with any other key, so the parent inscription pins the ceremony forever"; the NAKA parent carries no spendVkeyHash and its key is pinned in src/v1/collections.mjs. indexer.mjs takes one verification key and throws if it does not match the parent's hash. The founder's 19 October post: "A key of ours sits in the loop so that if anyone found a hole we could stop it … The next update removes it. No key of ours in the protocol, nothing of ours in the money path.", i.e. the platform's signing key in the trading flow
Payment transactions are built by the platform; the vault checks only the total leavingThe saved site script 62ebc8185a14617d.js: buying prepaid relays gets a platform-built PSBT from /tokens/build and hands it to the wallet's signPsbt; paying from the vault's BTC (payFromPrivateWallet) asks the server for a PSBT and signs it with the engine's signVaultPsbt. signVaultPsbt (saved browser-engine.js) checks only that the inputs are vault coins and that the net amount leaving is within what was expected ("would take … sats from your private wallet, more than the … expected. Not signed."), not where outputs go. For off-chain listings signOffer signs the listing-coin input and the seller's output with SIGHASH_SINGLE\ANYONECANPAY. docs/API.md: "buying happens only on Ord Dropz". The purchase page's own code isn't saved
What a shielded address is made of and used for (appendix I01)The note table in PROTOCOL-v1.md: ownerPk = Poseidon(sk), inner = Poseidon(ownerPk, rho, s); "The view key is an x25519 key … The address is shord1‖pk‖viewPk"; "Notes the owner builds for themselves (mint, buy, claim) are proof-less". The site engine (saved review-2026-10-27/browser-engine.js) encodes an address as "shord1" + hex(pk ‖ viewPk), and decodeAddress splits it back into {pk, viewPk}, refusing anything but 64 bytes. Site copy: "Your shielded address · for pieces", "For pieces only, never bitcoin. It does not show what you hold."
The web vault's signed text and seed (appendix I01, K)The site's engine shielded-browser.js (downloaded 2026-11-01, 567,545 bytes): VAULT_KEY_MESSAGE, four lines verbatim; seedFromSignature = SHA-256("shord/seed/v1" ‖ signature, at least 64 bytes); walletFromSeed: sk = SHA-256("shord/spend" ‖ seed) reduced, view key = SHA-256("shord/view" ‖ seed), ownerPk = Poseidon(sk), the view public key on x25519; return, payout, vault BTC and listing-coin keys under the labels shord/return, shord/payout, shord/btc, shord/listing. Archived site script 62ebc8185a14617d.js: UniSat signMessage(…,"ecdsa"), Xverse protocol:"ECDSA", signing with the connected payment address. f8c37337f94602c5.js: the app makes a new vault with crypto.getRandomValues(new Uint8Array(32)), encoded with a one-byte SHA-256 checksum as 24 words from the BIP39 list
Chapter 01: the rebuild condition, another wallet's empty vault, what the shielded address is for, the two listing keys, scanning with both keysThe site's wording in English fbaabcc7fccab287.js and Chinese 624a1b6e0181a28a.js (saved in site-2026-11-03): the import page's intro “Connect the exact wallet, account and address type you minted or bought with, and sign one message. It moves no bitcoin. A different wallet opens a different, empty vault.”; the vault page's addressHint “Only needed when someone sends you a piece directly. Buying and selling need nothing from you.”; the recovery words' onlyHere “They are not the seed phrase of any other wallet.”; the private payout of a listing, in Chinese “一个只用于这次挂单、只有你的保险库能控制的全新地址” (a new address for this listing only, controlled only by your vault). The site's engine (saved in archive/ord-dropz-site/engine/2026-11-02/shielded-browser.js): the return key Pc(wallet, the listed note's nf) and the payout Vd(wallet, the listing's nf), both SHA-256(label ‖ seed ‖ nf); vault BTC addresses Kd(wallet, number) with a 4-byte number, change going to changeIndex; scanNotes opens notes that have a ciphertext with the view key, derives ρ for those without one from the previous note's nullifier, and computes every nullifier with sk as Wd(sk, ρ)
How mining works: SHNAKAS as a collection of pouches, one pouch per claim, unclaimable shares never issued, the totalsThe site's SHNAKAS collection settings collection-shnakas-20261103.json (saved in site-2026-11-03): kind rune, rune.etching 92ff6274…, premine 2100000000000000, divisibility 8, supply 519,951, three fixed pouches of 80 at the start (minted 0), reward pouch numbers from 3, 519,948 of them, poolPerWeek 26,664,000,000,000, claimUntil 1,102,740; pouches from splits are numbered from 519,951 (split.nextId 520,252), lots 1,288. The site's engine (archive/ord-dropz-site/engine/2026-11-02/shielded-browser.js) checks the rules: “lots.count must be 2 x pieces x weeks”, “lots must end at the supply”, “pool exceeds the premine”, and a rune collection with no reward programme must have “lots must add up to the premine”; only the fixed pouches can be minted (mintable = lots.from); the rune fields are checked for format only, not against the etching on chain. The claim envelopes REWARD and REWARD2 carry the nullifier, the new commitment, the proof and the pouch's lotInner and ciphertext, BONUS and BONUS2 the number and a signature, and the pouch number is the indexer's nextId; each week's eligibility tree is the record tree cut at that week's leafCount (rewardTreeAt). The site's ledger state-974323-20261103.json.gz: 987 pouches, numbers 3–989 in a row, 506 base pouches totalling 74,989.90801104 and 481 bonus pouches totalling 92,265.79299642, the first at block 972,709; week 1's eligibility tree holds 7,640 notes. The token page script 7f10f4358f40d09a.js: the ceiling constant 21e6 and the description “21,000,000 is the ceiling, not the supply: whatever is never claimed is never issued, and burned pouches are gone for good.”; on the site, “premine” appears only in the description of another product, Forge. The founder's posts (saved in sources/x-posts/): 7 October, “All 21M $SHNAKAS are locked in the same NUMS parking address as the Nakas.”; the long post of 19 October, “It is never issued, and it can never be bought back. Same for Nakas that were never minted. 21M is the ceiling, not the supply. … The burn started on block one.”
A private send keeps s; ρ′ comes from the public nullifier; the nullifier needs the spend key, or anyone could chain the moves (chapter 04 technical notes, appendix I01, I04, K)The circuit's header comment: nf = Poseidon(sk, rho, 7) "only the owner can compute it". circuits/spend.circom: mode 0 "cmOut is a new note for pkOut with the SAME assetId and s, rhoOut = Poseidon(nf, 11)", public inputs include nf, cmOut, spend, buy; the engine's buildTransfer likewise uses Poseidon(nf, 11) and the old note's s; PROTOCOL-v1.md: "piece secret s: conserved across private sends; replaced on every sale, mint or claim"; the engine's buildBuy and buildClaim draw a fresh ρ and s with zd() (64 random bytes reduced), while buildTransfer and reward claims keep the old s
Note encryptionThe site's engine: each encryption makes a one-time x25519 key with randomSecretKey(), key = SHA-256("shord/note/v1" ‖ shared secret ‖ one-time public key), ChaCha20-Poly1305 over 72 bytes of plaintext (number, credits, ρ, s), an 88-byte ciphertext; the view key finds notes by trying each one
Nobody can look up what a shielded address received (appendix K)Public code src/v1/view.mjs: exportState serves every note (pos, cm, epk, ct, txid, height, kind) with no owner, and its comment says "The wallet downloads ALL notes and scans them locally, so the server never learns which notes … belong to whom"; the site engine's scan tries each note with viewSk and checks the commitment against its own owner key. When relaying, the site's page sends a body of just envelopeHex and the prepaid tokens, plus a header with the locally stored private-beta access code shord.pouchAccess (archived sources/site-2026-10-28/f8c37337f94602c5.js)
A sender can prove the recipient by handing over the note's details (appendix K)Site engine buildTransfer: ρ′ = Poseidon(nf, 11), cmOut = Poseidon(number, credits, Poseidon(recipient owner key, ρ′, s)), s kept from the old note; the encryption returns only epk and ct and keeps no one-time secret, so the sender can't let a third party open the ciphertext. PROTOCOL-v1.md: "There is no in-circuit check of the TRANSFER ciphertext", "Sender-recovery ciphertext is not implemented". The site page's SHNAKAS burn flow (archived f8c37337f94602c5.js): a whole-pouch transfer sends {assetId, tickets, s} as its opening, a split sends {out, rho, s} as openings, with the envelope hash, to /snickets/burn/build; how the server checks them can't be seen. Engine buildSplit gives a pouch sent to another address a fresh random ρ and s and returns only inner, epk and ct; the burn address uses the vault's own view key, which is why ρ and s can be opened there. A pouch's size is public by its id through lotSizeOf (the rules' lots table, or lotSizes in the state). The way to export these details rests on the engine's exports: seedFromSignature, walletFromSeed (sk, viewSk and the rest from the seed), scanNotes (opens each note the ledger holds for you, spent ones included, with ρ, s and nf), parseEnvelope; none of the API routes the site's pages use signs for a user or exports these details
A whole pouch is sent like a piece; giving part means a split, then a send, and a split shows the pouch number and the new sizes (chapter 04, appendix I07)Site engine archive/ord-dropz-site/engine/2026-11-02/shielded-browser.js: a whole pouch goes through buildTransfer (mode 0, number hidden); buildSplit is for rune collections only ("a split is for a rune lot"): 2 to 16 pouches, each at least 1, adding up to the lot; the envelope carries the old number, the credits and each new size, and the proof runs in mode 1 with assetIdPub set to the old number; its to option takes one address per new pouch ("to: one address (or null) per pouch"). The vault script archived on 3 November, cd53361caaa1b5b2.js, calls buildSplit in three places: the Split button passes no to and pays only through selfPay; burning into Snickets passes to:[null, burn address]; depositing into Naka Lounge passes to:[null, Lounge address] (or halves a pouch of exactly that size and gives both to Lounge). The English strings (fbaabcc7fccab287.js): "Splitting a pouch into smaller ones (1, 5, 10 of a kind) works like a send: one private transaction, paid from your own bitcoin." and "Pouches move whole. Pick one."
The site's "Prove" button uses the holder proof; who gets it (chapter 06, appendix K)Archived site script dff9f0e18378b9ad.js: purpose "holder-demo", claimant the connected wallet's paymentAddress (prompt "to name who the proof is for"), holderContext then buildHolderProof, sent to /holder/verify; success text "Verified: you hold a piece of this collection. The verifier did not learn which one."; hint "This is what Discord roles and whitelists will use.". The engine's holderContext = hash(cid ‖ purpose ‖ claimant); circuits/holder.circom makes root, context and ctxNf public. The vault script of 3 November, a926e8a6d1e1b3eb.js (archived in site-2026-11-03), still does this: holderContext(view, "holder-demo", payment address), then buildHolderProof, posted to /holder/verify with purpose, claimant and the proof; in the same script other collections request listing coins with a holder proof too (purpose "listing-coins", posted to /coins/request with the coins' public keys); NAKA has no instant listing, so it doesn't
How the multi-party ceremony runs (appendix K)ceremony/ceremony.mjs: init → hand 0000.zkey and transcript.json to the first contributor → each runs contribute <circuit> --name on their own machine and gets a contribution hash → verify checks the whole chain → beacon --height finishes with a block named in advance → page writes the public record; circuits spend and holder. The public documents give no sign-up or dates
Where the components come from (appendix D)zk/spend_vkey.json: protocol groth16, curve bn128; circuits/lib.circom includes circomlib's poseidon.circom; the public repository's documents and code don't mention Zcash or Zerocash
The relay's new sending wallet since 29 October (chapter 08, appendix I08, K)status read 2 November: relayer.address bc1pr5vsx…5hcp73, batchWindowMs 300000. mempool.space: the old address bc1phcjk…3t3cuy has 5,554 transactions and a zero balance, its last (83409f79…, block 973,777) sending its coins to the new address; the new address starts with fe200a20… (block 973,769), spending the old address's coins, and its later transactions keep the SHORD OP_RETURN plus 330-sat lock shape. The rules' relayerPayoutScript is still 5120be25…fe43
The public relayer's batches and locks (appendix I04)relayer/relayer.mjs: mainnet default BATCH_MS = 600000, each batch waits BATCH_MS × (0.5 to 1.5); a listing gets a lock of value: 330
How an indexer finds a listing lock, what the digest holds, the order of checks (appendix A, card 08)indexer.mjs: a listing's lock output is found by lockScript alone, its amount recorded but not checked; transfers and listings check the anchor, then whether the nullifier was seen, the proof last, and a failed check is only logged as refused; in rules.mjs ANCHOR_WINDOW is 100 and K_MIN 1, so the root must be from the last 100 blocks and older than the current one; stateDigest holds the root, the leaf count, the nullifiers, the minted numbers, and each listing's nullifier, state, number, credits and price, and docs/API.md says it leaves out a note's ciphertext, txid, height and kind, and a listing's block, lock, seller script, return key and sale txids
How checkpoints are saved, loaded and rolled back (chapter 08, appendices H, I08)The Restarts section of docs/RUN-AN-INDEXER.md and checkpoint.mjs: one every 6 blocks at the tip, the newest 4 kept; a start uses the newest that passes every check, else an older one, else a full replay from the start block; a reorg goes back to the newest one still on the best chain, replays alongside and swaps at the tip, answering from the old state until then
The public code's replay matched the site's digest on 11 October (chapter 08, appendix H)docs/STATUS.md: release-2 replayed from block 969,342 on its own and reached the Ord Dropz server's state digest at block 970,879 (7,090 notes)
What the two status interfaces give (chapter 08, appendix F)The site's status and the public API Ord Dropz hosts, /status, read together on 3 November and saved as sources/site-2026-11-03/status-official-20261103.json and status-hosted-20261103.json: both at block 974,394 with 11,160 notes and the same digest; the site's has no block hash, the hosted one has. The public repository's docs/API.md says Ord Dropz runs the hosted API
Racing a listing needs another platform signature (appendix K)src/v1/cosign.mjs refuses while a transaction for the same listing is pending: "this listing is already being bought or cancelled"; NAKA's single-key platform signer is not public
A shielded address has no checksum (appendix K)The site engine's decodeAddress checks only the shord1 prefix, 64 bytes and a first half below the field size ("non-canonical field element"); there is no checksum
Reserved names and dust lines (appendix J, I05)RESERVED_LABELS in names.mjs, 35 labels; dustFor in rules.mjs: 34 bytes starting 0x51 is 330, starting 0x00 (bc1q, P2WSH) 294, the rest 546
What a developer can use, and the two interfaces (appendix K)The public repository's LICENSE is MIT. docs/API.md: a key for the hosted API at shielded-public-api-production.up.railway.app comes from /verify and /apikey on the Ord Dropz Discord; without one only /status, /collections, /names/info and /health answer, at 30 units a minute per network address; with one, 60 units a minute and 5,000 a day, the full /state costing 20. Tried 2 November: the hosted /listings and /state answer 401 without a key; the site's own interface, shielded-api.ord-dropz.xyz/api/shielded, serves /listings and /state without one (height 974,197), and its /names/bob.naka answers only {"available":true}
Checking the site's proving keys (appendix D, K)Downloaded 2 November from the site's /engine/: shielded-browser.js 567,545 bytes, spend.wasm 2,513,090, spend.zkey 6,285,499, holder.wasm 2,446,304, holder.zkey 5,624,582. Verification keys exported with snarkjs 0.7.5's zKey.exportVerificationKey and hashed as rules.mjs vkeyHash does: spend gives e7dbcdb0…e788, the hash collections.mjs pins for NAKA and that of zk/spend_vkey.json; holder gives 644ad887…2a82, that of zk/holder_vkey.json. Section 10 of each zkey, read by the file format, records one contribution of type 0 (an ordinary contribution, not a block-hash beacon), named "proto" and "local dev (pre-ceremony)". In the verification keys δ is neither the G2 generator nor equal to γ
A name is recognised by its content; the inscription isn't followedscanBlock in registry.mjs: reads the inscriptions of every transaction in a block (readInscriptions), keeps those that are JSON or plain text and that readNameRecord accepts, and hands them to NameIndex in transaction, then inscription, order; later blocks never look at that inscription again
Shielded names (appendix J)The header of names.mjs: a name is an ordinary inscription with content {"p":"shord","op":"name","name","to"}; "Anyone may inscribe one … No parent, no fee rule, no signature", "First is first", "The label … is unique across both endings", "to is fixed by the inscription: moving or selling the inscription never changes where it points", "METADATA ONLY: nothing in the protocol's acceptance rules depends on it"; NAMES_START mainnet 969800; the 3-to-20 label rule; RESERVED_LABELS; the running digest sha256(previousheightidnameto). tools/names-indexer.mjs builds your own index and --compare checks another; docs/STATUS.md: "A name bought through the wallet was inscribed by the relayer from an unrelated coin … (mainnet, dub.naka)". Site copy (saved 1981f5467097dc93.js): "It is inscribed on Bitcoin, and the first to inscribe a name owns it", "A name is public and points at your shielded address. It does not show what your vault holds, and it is not inscribed with your bitcoin". Read on 2026-10-30, the site names interface: enabled true, fee 2500, endings naka/shield, index at height 973,831 with 533 names; the public interface at the same height with the same digest 877d9f00…aa59
Reward weights can be recomputed without the siterewards.weights in the on-chain SHNAKAS rules inscription (saved as sources/onchain/programme-shnakas.json): base 4, cap 16, steps [[300,4],[200,3],[150,2],[125,1]], numbers [[10,8],[100,4],[1000,2]], zeroListed {minPieces 20, units 4, sales 3}, asks {minPrice 546, scripts p2tr/p2wsh/p2wpkh/p2sh/p2pkh}, traitsSha256 and traits (types, values, pieces). The inputs are the ledger's listings and sales. The vault page fetches /rewards/weights/now (saved site-2026-10-28/f8c37337f94602c5.js); the engine only parses a weight snapshot and doesn't recompute. The 27 October weight snapshot (sources/review-2026-10-27/weights-now.json) takes its 351 trait floors from listings 175, sales 106, zero-listed 62, last block 8; every zero-listed trait has at least 20 pieces and gets +4 units (100%), every sales-rated one fewer than 20. The rules don't say where listings are read from; the site describes an off-chain listing as "Nothing went on chain: the listing is a signed note this marketplace holds"
Relay credits travel with the pieceSite copy creditsHint: "Each private send, listing or cancel uses one credit. Credits stay with the piece, even when you send or sell it."; the per-piece button "Relay credits for #{id}… Buy # credits" and "#{id} will have {count} relay credits after the next Bitcoin block"
SHNAKAS is so far the only private runeAll 15 entries in the saved local-collections.json are collections; the only rune programme is programme-shnakas (its rewards.collection points at NAKA's parent). No second rune programme was found, hence "so far the only"
The official relay's address is the relay payout address in the rules, and relayed envelopes are paid from itrelayer.address in the site's status interface is bc1phcjkxgemknltzjwr5cg37eaza3gxrxgey8vhgpk83jjgv987leps3t3cuy (saved in sources/review-2026-10-27/site-status.json), the same address NAKA's parent inscription sets as relayerPayoutScript 5120be2563233bb4feb149c3a6111f67a2ec5061991921d97406c78ca48614fefe43. On chain (mempool.space, checked 2026-10-29): 5,517 transactions, balance about 0.018 BTC; the recent ones all spend this address's own change, carry one OP_RETURN starting with SHORD, add a 330 sats lock for a listing and return change here, with miner fees of 672 to 1,971 sats. The 1.27 BTC received includes its own change; net income wasn't computed
The site also sells prepaid relays, kept only in this browserbuyRelays in the saved vault scripts (site-2026-10-28/62ebc8185a14617d.js): each unit gets a 32-byte secret and blinding factor from crypto.getRandomValues, is bought with BTC (/tokens/build, unit price collection.relayTokens.unitSats = 2,500), blind-signed (/tokens/mint), unblinded and stored in localStorage under shielded_relays_v1:network:vault address:site, then handed to /relay with an envelope. Site copy (1981f5467097dc93.js): the Relays tab, "Prepaid relays… A prepaid relay pays the network fee of one private send, listing or cancel… kept in this browser's vault, for every piece you hold"; payChoice offers four: Use 1 relay credit, Pay from my wallet, Pay from my private wallet, Use a prepaid relay (none left: buy some under Relays); "This needs {units} prepaid relays at today's network fee". NAKA has relayTokens.creditsOff = false, so in-note credits still work
A NAKA buyer pays the price and the platform fee, plus miner feesThe site's buyer total is price + platform fee + royalty + settle fee, and the settle fee is counted only for off-chain listings (settleFee read only when offchain, capped at 20,000 sats). None of the 114 NAKA listings read at 20:17 on 28 October 2026 has a settleFee field. Saved as sources/site-2026-10-28/listings-20261028T2017.json
The site bundles 3 credits with each mint by defaultticketsPerMint in the site's scripts: the rules' ticketsPerMint if set, otherwise 3 when the rules carry no spendVkeyHash. NAKA's rules have neither and relayTokens.creditsOff is false, so 3, i.e. 7,500 sats
A listing adds no leaf; keys alone need the full list of notesIn indexer.mjs only mints, private transfers, purchases and claims call _addNote; a listing doesn't. envelope.mjs throws on an unknown type, so a public-code indexer can't list notes made by rewards, splits and the other newer types
Why the nullifier uses the spend keyThe Notes section of PROTOCOL-v1.md: nf = Poseidon(sk, rho, 7), and a private send's new rho = Poseidon(nf, 11), "unique, so a sender can't collide notes". In a private send the sender builds the new note (in mode 0 the sender supplies cmOut and the ciphertext), so the sender knows its rho
An indexer sees a lock spent by a transaction with no envelopefollow.mjs from line 448: every transaction keeps the coins it spends ("a listing lock being spent"), so one without an envelope still reaches the rules engine. _applyTx in indexer.mjs collects spent locks first, and a listing without a valid BUY becomes CLOSED after that transaction. The Listing lock section of PROTOCOL-v1.md: spending the lock without a valid BUY closes the listing, and the platform's "kill switch" is spending the lock
Self-publishing and relay batchesThe Self-publish section of PROTOCOL-v1.md: an envelope with spend = 0 can go in a transaction you pay for, at the cost of showing the paying wallet. The Relay batches section: a relay puts the envelopes of one window into one transaction in random order. batchWindowMs in the site's status is 300000, i.e. five minutes. The site's "self send" (selfPublish) builds the transaction from the connected wallet and its coins

That nobody knows a private key for the NUMS address, and that it has no script path, rests on the usual cryptographic assumptions. The shared address's output script is 5120192c2a30cbd7d0352f94d4c31a43f767f1ef43d7ff6438839880ec075d81a9f6.

3 Public code and the live version

The public protocol code is shielded-ordinals; this guide was checked against commit 3cdbdfdf of 12 October 2026. The live interfaces and client already have rewards, splits and more; the guide follows the live material and doesn't use the older version to argue against newer features.

The team says newer code will be published. That is their plan; this guide hasn't verified it and can't promise a date. A full independent replay also needs the matching rules, verification parameters and activation settings.

The live reward service was not reproduced independently. The voting service's code never reaches the browser, so only its public records can be checked: the tally and de-duplication match, eligibility can only be sampled (the voting row in section 2). The limits found in the old public holder circuit offline can't be presented as a flaw in live voting.

The guide also used naka-sigil's public code and documents (rules, snapshots, reward checks), reading only code and documents, never anyone's holdings or wallet.

4 Where the cards come from

CardEvidence
00 One private send: where each thing comes from and livesThe Notes section and the "who can do what" table at the end of PROTOCOL-v1.md; the engine fields of indexer.mjs (what is stored) and _addNote (the indexer completes cm for mints, purchases and claims). Proofs are checked and not kept; see the fields saved by checkpoint.mjs
01 One signature, every keyThe engine's derivation functions (section 2: spend and view from the seed alone, return and payout with that listing's nullifier, btc with a number), the vault page's signing call (UniSat ecdsa, Xverse ECDSA) and the import page's wording
02 Rules in the parent, payments checked against themThe Collection = rules section of PROTOCOL-v1.md and the field comments at the top of rules.mjs (mintPrice to the artist script, mintFee to the platform, inscribeFee and ticketPrice to the relay, saleFee = max(min, price × bps / 10000), royalty only in v2); NAKA's numbers from the archived collection.json (mintPrice 15000, mintFee 0, inscribeFee 3000, saleFeeBps 200, saleFeeMin 1000, ticketPrice 2500, v 1), where the artist and platform scripts were also compared byte for byte; the gateKey permit coin and the 20-piece MINTN limit from PROTOCOL-v1.md and indexer.mjs. Rechecked in round 68 (collection-naka-20261103.json, PROTOCOL-v1.md): the same numbers, no cosigners (a single key); MINT must spend a P2TR(gateKey) coin and MINTN spends one for the whole batch (“one P2TR(gateKey) coin for the whole batch”); payments are summed per scriptPubKey, “artist, platform and relayer may all be the same address”; collections come pre-inscribed (children) or as a file mint (artRoot, children inscribed by the platform in batches after the mint), NAKA being the latter; cid = sha256(parent id)[0..8] (rules.mjs collectionId); the site's default of 3 credits per mint is in this table's row on it. Added in round 69: a BUY's tx must spend the listing lock (the BUY row of PROTOCOL-v1.md's envelope table), and the card's example uses 2% (2,000 on 100,000, above the 1,000 floor); the parent goes to NUMS after the last child is inscribed, “so the rules and supply can never change” (end of the Collection = rules section)
03 One note; on chain, only its commitment and ciphertextnoteCommitment = Poseidon(assetId, tickets, inner) in core.mjs; PROTOCOL-v1.md: notes owners build for themselves (mint, buy, claim) carry no proof, only inner, and the indexer completes cm; a private send's cmOut is a public input of its proof; the address shord1‖pk‖viewPk gives the receiver's owner key; indexer.mjs adds commitments to the record tree in chain order; the tree is 20 levels deep. Rechecked in round 70: the ciphertext encrypts 72 bytes, the number (u32), the credits (u32), ρ and s, without the owner key (the site engine's Fr/Mc in archive/ord-dropz-site/engine/2026-11-02/shielded-browser.js), 88 bytes with the 16-byte tag; the public indexer's _addNote puts only cm into the record tree and keeps epk and ct in its note list for vaults to scan, and MINTN adds one leaf per piece (indexer.mjs line 196); the tree is 20 deep (engine vr = 20); a proof's root must be from the last 100 blocks (indexer.mjs, “anchor in [H-100, H-1]”); the NUMS address's key is BIP341's NUMS point with no script tree (scripts.mjs NUMS_X, and this table's row on the address nobody can spend) Added in round 71, how SHNAKAS is kept: a pouch note has the same five fields as a piece note, its number being the pouch number; a pouch's amount is looked up by that number (the engine's lotSizeOf: the rules' lots for the fixed pouches, the ledger's lotSizes for the rest), added at scanning, not in the note or its ciphertext; the 21 million SHNAKAS sit at the same address as the NAKA pieces (appendix G).
A nullifier can't be grabbed; a listing lock spent without a sale closes the listingindexer.mjs: the public inputs of a transfer or listing are [root, nf, hbody, cmOut, spend, buy, mode, assetId, tickets], hbody being the SHA-256 of the whole body before the proof (core.mjs hashBody), and a nullifier already recorded or repeated in the same transaction is rejected; each transaction first collects the listing locks it spends, and after its envelopes any listing without a valid BUY becomes CLOSED; CLAIM needs a CLOSED listing (or the lock spent in the same transaction) and a BIP340 signature by the record's returnKey over the SHA-256 of its body, and the new commitment is noteCommitment(number, credits − spent, inner). scripts.mjs: the lock is a P2TR with internal key lockKey and leaf "1008 CSV DROP returnKey CHECKSIG". cosign.mjs: a co-signer signs one input with SIGHASH_DEFAULT ("commits to every input and output"), only after its own indexer finds a valid BUY or the seller's CLAIM in the transaction, and remembers what it signed so it won't sign a second sale of the same piece; NAKA runs the single-key mode, whose signing code isn't in the public repository
04 One envelope, each part to its placeThe TRANSFER layout in src/v1/envelope.mjs: header 15, anchor 4, nf 32, cmOut 32, spend 1, buy 2, epk 32, ciphertext 88, proof 256, 462 bytes in all. In indexer.mjs the nullifier joins the set, cmOut joins the tree and the proof is checked, not stored. The SPLIT line at the foot: the site engine's buildSplit (section 2)
05 One lock, three ways out (was "While listed, the piece is tied to the lock")The Listing lock section of PROTOCOL-v1.md (see section 2 above); the BUY and CLAIM checks in indexer.mjs. Fee rates from collection
06 Three uses, and what each hands over (was "Three proofs": the vote and the base reward both run on the spend circuit; only the holder proof is a circuit of its own)The vote row from the archived vault page script (spend circuit, snapshot eligibility, hbody binding topic/round/choice, the fields posted to the voting service); the reward row from the archived client's buildReward / buildRewardBatch (spend circuit, eligibility root, the REWARD envelope on chain, nullifier public) and the envelope layouts in RESEARCH-RUNES.md §4.2 and §4.4; the holder-proof row from circuits/holder.circom (tree membership and ctxNf only, no nullifier check), the Holder proof section of PROTOCOL-v1.md and HOLDER_ROOT_WINDOW = 6 in rules.mjs; "6 blocks don't keep out old leaves" is in appendix E; the holder row's "hands over" follows the site's actual request (the proof and the claimant address, see the Prove button row in section 2); the foot's bonus is a separate BONUS envelope, signed, number shown: flow chart 03 and appendix I06
07 A week is 1,008 blocksThe client's start-week and end-week logic: a week counts when the note was created at h ≤ the week's start and spent at t > its end. A transfer spends the old note and creates the new one in the block where it confirms. From rewards: start 971,700, 266,640 a week, 78 weeks, deadline 1,102,740. Rechecked in round 82 against the site engine of 2 November (archive/ord-dropz-site/engine/2026-11-02/shielded-browser.js): Tr puts block t in week floor((t − start − 1) / 1008), so a week is (start + 1008w, start + 1008(w+1)] and week 3 is blocks 973,717–974,724; ns gives an ordinary note the first week ceil((h − start) / 1008), and a note of kind reward the week it is in (a reward claim's new note keeps the week); Qn gives a spent note the last week floor((t − 1 − start) / 1008) − 1, so a spend in a week's last block still loses it. The bonus is a separate, optional BONUS envelope; the base pouch pays 100%
08 What the indexer checks, what the digest coversThe order of validation and the 100-block anchor window in PROTOCOL-v1.md, the fields saved by indexer.mjs and checkpoint.mjs, and the consistency conditions and reorg handling in appendix F

5 Images

The people and the art in the plates are all Shielded Nakas pieces: holder A is #2, B is #0, buyer C is #21, and #4 is the piece bought and sold across the plates; the others that appear are #1, #3, #7, #12, #14, #15, #37, #42, #46 and #49. The cover is a street with a place for each chapter: A #2 holds the signed sheet outside the vault, #7 arrives at the mint with a note made at home, #4 hangs at twice its size upstairs in the museum with the portraits of #15, #1 and #3 downstairs, #42 points #4 out to #14, B #0 holds the opened letter in the window of B's house, C #21 brings a bag of coins to the stall, #46 holds a proof card up at the checking booth, #12 raises the reward coin by the clock tower and #37 holds the digest at the indexer's kiosk. In plate 02 the minter is A; in plate 06 the prover is #46.

The numbers in the guide are asset numbers, starting at 0. The images the official art interface returns for /art/0 and /art/1 are identical to #0 and #1 here. Card titles on the official site may show a number one higher: naka-sigil's page code records that the site displays assets 0, 1 and 2 as #1, #2 and #3.

The landscape picture-and-text layout takes a cue from catvm.pdf, without its images, characters or text.

6 What this guide is and isn't

It is community learning material that explains how SHORD works and what to watch for when using it. It is not a security audit of the protocol, the wallets, the parameters or the live services.

7 Details left out of the guide

These were checked but add little on a first encounter with SHORD: