Trust and open questions
The Attacks page covers what the Script stops. This page covers the rest: what the tokens don’t guarantee, the parties they ask us to trust, what we haven’t tested yet, and the questions we think are most worth a researcher’s time.
What the token does not guarantee
Section titled “What the token does not guarantee”These are limits of the design, not defects. Each one has an answer at the wallet or the application, which our Host security rules set out.
- That a transfer will be mined (N1). The sender can sign two transfers of the same token before either is mined, and only the network decides which one wins. A payee counts a token as received only once the network has the transfer.
- That the Issuer is honest (N2). An Issuer can issue as many tokens as it likes. The identity anchor names the Issuer, and we trust it as we would the person or company behind it.
- That a reissue keeps the token’s identity (N3). A successor has a new Token ID. The links connect it to the token it succeeds, but they are checked by wallets, not by the Script.
- That a token without links is the newest form of its lineage (N4). A holder can leave the links out.
- Privacy (N5). Every transfer carries the token’s whole history since issuance, or since its last reset.
Whom the tokens ask us to trust
Section titled “Whom the tokens ask us to trust”The Issuer’s Rabin key. Anyone holding it can issue tokens that verify as the Issuer’s. The plugins never see it, and only take Attestations. An identity anchor can’t rotate its Rabin key yet (K4): a new key needs a new anchor and new issuances.
The attesters of a resettable fungible token. Two of the three can create a token of any amount by signing for a fabricated outpoint, which the tests demonstrate. They are fixed at issuance, so a holder knows who they are before accepting the token. The NFT and the fuelled family have no attesters and can’t be reset.
A Voucher’s Issuer, near the expiry. An Issuer that broadcasts its forced redemption before the expiry height can’t have it mined early, but nodes that hold it will refuse the holder’s two-input spends (a top-up, or a funded redemption) for as long as it waits. The holder’s one-input transfer and redemption still go through.
What is not yet tested
Section titled “What is not yet tested”- Mainnet. No Lineage Token has been used on mainnet.
- The fungible token on a node. The NFT and every mode have been mined on a regtest node. The fungible token has been tested through the Script interpreter only.
- Some wallet paths. libtokensv’s
doc/spiffy/SECURITY.mdlists the known gaps (K1 to K5): among them, the BEEF of a plugin payment carries no ancestors and no proofs (K1), and the recovery of a token received while its plugin wasn’t registered (K3) is untested.
Open questions
Section titled “Open questions”These are the places we would look first, if we were in your shoes.
- The dependency on version 1. The tokens refuse any Transaction version but 1, because the Chronicle release relaxes the encoding rules for later versions, and a re-encoded unlock would change the txid that the next hop rebuilds. The design depends on version 1’s strict rules staying in force on every node. Whether those rules are consensus or only policy deserves independent confirmation.
- The rebuild against real nodes. The tests check that dartsv reads and writes every Transaction back to the same bytes. A node that serialises a Transaction differently from the bytes it was given would break the rebuild. We have seen no such node, but we have tested against only one implementation on regtest.
- Growth without a limit. The record grows by a fixed number of bytes at every hop (Figure 2 on Concepts), so a token passed on long enough eventually meets a node’s limits on Transaction or script size. Redeeming and reissuing, or a reset, brings it back down. Where those limits sit in practice, and what a holder whose token crosses them can still do, is worth measuring.
- The preimage parse. The Script reads its own code out of the Sighash preimage, and assumes the code’s length fits a 3-byte varint (
lt_nft_test.dart:131checks it does). Any assumption the Script makes about the layout of the preimage or of a record is a place to probe. - The attesters’ policy. Two of three is a parameter, fixed in the code. Other thresholds, and how a holder should judge a set of attesters, are open.
- Host mistakes. Most of the ways to lose a token are a host’s, not the Script’s: spending a token as a coin, or changing a token Transaction’s bytes. The plugins guard against these, but only while they are registered and used as documented.
We would like to hear about anything you find. Please open an issue on libtokensv, or, for anything that puts tokens at risk, contact us privately before you publish.

