{"id":28396165,"url":"https://github.com/ssbc/ssb-buttwoo-spec","last_synced_at":"2026-01-29T10:48:03.388Z","repository":{"id":39710981,"uuid":"483200410","full_name":"ssbc/ssb-buttwoo-spec","owner":"ssbc","description":"Spec for a new binary feed format for SSB","archived":false,"fork":false,"pushed_at":"2023-01-02T23:19:46.000Z","size":28,"stargazers_count":12,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-14T18:23:35.882Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ssbc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-04-19T10:32:12.000Z","updated_at":"2025-07-14T05:03:46.000Z","dependencies_parsed_at":"2022-08-09T15:24:54.683Z","dependency_job_id":null,"html_url":"https://github.com/ssbc/ssb-buttwoo-spec","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ssbc/ssb-buttwoo-spec","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssbc%2Fssb-buttwoo-spec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssbc%2Fssb-buttwoo-spec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssbc%2Fssb-buttwoo-spec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssbc%2Fssb-buttwoo-spec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ssbc","download_url":"https://codeload.github.com/ssbc/ssb-buttwoo-spec/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssbc%2Fssb-buttwoo-spec/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28875855,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-29T10:31:27.438Z","status":"ssl_error","status_checked_at":"2026-01-29T10:31:01.017Z","response_time":59,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-05-31T21:37:06.348Z","updated_at":"2026-01-29T10:48:03.360Z","avatar_url":"https://github.com/ssbc.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# Buttwoo feed format\n\nStatus: **Ready for use**\n\nButtwoo is a new binary feed format for [SSB]. It draws inspiration\nfrom [bamboo] and [meta feeds].\n\nThe format is designed to be simple to implement, be easy to integrate\ninto existing implementations, be backwards compatible with existing\napplications and lastly to be performant.\n\nButtwoo uses [bipf] for encoding since its a good foundation for an\nappend-only-log system (write once, many reads). It uses [ssb-bfe] for\nbinary encodings of feed IDs and message IDs.\n\n## Format\n\nA buttwoo message consists of a bipf-encoded array of 3 fields:\n\n- `metadata`\n- `signature`\n- `content`\n\nThe message ID is the BFE encoding of the [blake3] hash of the\nconcatenation of `metadata` bytes with `signature` bytes.\n\n### Metadata\n\nThe `metadata` field is a bipf-encoded array with 8 fields:\n\n - `author`: [ssb-bfe]-encoded buttwoo feed ID, an ed25519 public key\n - `parent`: [ssb-bfe]-encoded buttwoo message ID used for subfeeds. \n   For the top feed this must be BFE nil.\n - `sequence`: integer representing the position for this message in\n   the feed. Starts from 1.\n - `timestamp`: double representing the UNIX epoch timestamp of \n   message creation\n - `previous`: [ssb-bfe]-encoded message ID for the previous message \n   in the feed. For the first message this must be BFE nil.\n - `tag`: a byte with extensible tag information (the value `0x00`\n   means a standard message, `0x01` means subfeed, `0x02` means\n   end-of-feed). In future versions other tags to mean something\n   else.\n - `contentLength`: the length of the bipf-encoded `content` in bytes\n - `hash`: concatenation of `0x00` with the [blake3] hash of the \n    bipf-encoded `content` bytes\n    \n### Signature\n\nThe `signature` uses the same HMAC signing capability (`sodium.crypto_auth`) \nand `sodium.crypto_sign_detached` as in the classic SSB format (ed25519).\n\nIt is important to note that one author can have multiple feeds, each\nfeed defined as author + parent. `sequence` and `previous` relates to\nthe feed. Also note that unless parent is used, this behaves exactly\nlike an ordinary classic SSB feed.\n\n### Content\n\nThe `content` is a free form field. When unencrypted, it MUST be a\nbipf-encoded object. If encrypted, `content` MUST be an [ssb-bfe\nencrypted data format].\n\n## Subfeeds\n\nAs noted above it is possible to have multiple feeds with the same\nauthor. To initiate a subfeed one create a special message on the\nfeed. This message must use the `0x01` tag and content can include\nextra information about what is contained in the subfeed, such as the\nfeed purpose. The id of this message serves as the parent id of each\nmessage on the subfeed.\n\nIn contrast with [bendy butt], subfeeds maintain the same feed\nidentitier. This makes it easier to work with in situations where,\nwhat in classic SSB would be single feed, is split into multiple\nparts. As an example, a feed could be split into: about messages, the\nsocial graph and ordinary messages. While on the other hand [bendy\nbutt] had a clear separation between what are meta feeds and what are\nnormal feeds, allowing normal feeds to use different feed formats. In\nthis way, they can be seen as complementary.\n\n## Performance\n\nA benchmark of a prototype shows the time it takes to validate and\nconvert for storing in a database to be reduced in half for single\nmessage validation. Similar to classic it is possible for lite clients\nto queue up messages for validation and only check the signature of a\nrandom or the latest message. This can improve the bulk validation\nsubstantially in onboarding situations.\n\n## Size\n\nThere is roughly a 20% size reduction in network traffic compared to\nclassic format.\n\n## Validation\n\nA buttwoo message MUST conform to the following rules:\n - Metadata must be an bipf encoded array of 8 elements:\n   - a [ssb-bfe] encoded author\n   - a [ssb-bfe] encoded parent message id\n   - a sequence that starts with 1 and increases by 1 for each message\n     on the feed\n   - a timestamp representing the UNIX epoch timestamp of message\n     creation\n   - a [ssb-bfe] encoded previous messages key on the feed\n   - a byte representating a tag of either: `0x00`, `0x01` or `0x02`\n   - the content length in bytes. This number must not exceed 16384.\n   - content hash MUST start with `0x00` and be of length 33\n - Signature MUST sign the encoded metadata using the authors key. It\n   MUST be 64 bytes.\n\nContent, if available MUST conform to the following rules: \n - The byte length must match the content size in value\n - Content hashed with blake3 must match the content hash in values\n\n## Integration with existing SSB stack\n\n### EBT\n\nData sent over the wire should be bipf encoded as:\n\n```\ntransport:  [metadata, signature, content]\nmetadata:   [author, parent, sequence, timestamp, previous, tag, contentLen, contentHash]\n```\n\nIf content is not encrypted, then this value will be a bipf encoded\nbuffer. If encrypted, this will be a base64 encoded BFE string\nrepresentation.\n\nThe feedId should be author + parent.\n\n## Design choices\n\n### Keeping timestamps\n\nOne difference between buttwoo and bamboo is that bamboo does not have\ntimestamps in the format, instead leaving those to be part of the\ncontent. This is important for private messages. This choice was\nmostly formed from an backwards compatible perspective. It should be\nnoted that with meta feeds it becomes possible to store the messages\nof a private group in a feed that is only exchanged with members of\nthe group, thus leaving the potential metadata leak problem void.\n\n### Lipmaa links\n\nAnother difference between buttwoo and bamboo is that lipmaa links are\nnot included. Lipmaa links allows partial replication in cases where\nthe specific subset of messages are not important, only that they form\na valid chain back to the root message. This comes at the cost that\nvalidation is now more expensive because for roughly every second\nmessage an additional link needs to be checked.\n\nFurthermore with meta feeds we can now partition the data of a feed\ninto subsets (such as the friends graph and about messages in separate\nfeeds). This leaves public messages where lipmaa links based partial\nreplication could be useful. Also note for this to really work, the\nfriend graph needs to include the root hash besides the feed,\notherwise an adversary (given the private key) could still create a\nfake feed. \n\nLastly we already have another mechanism for doing partial\nreplication, namely tangles where messages from multiple feeds are\nlinked together and form their own chain.\n\nTo sum up, the advantages does not outweight the disadvantages for\nSSB.\n\n### Sign hash of the content\n\nSimilar to bamboo the signature is over the hash of the content and\nnot the actual content. This allows validation of a log without the\nactual content. It should be noted that deletion is a whole topic in\nitself, this is just to note that this format also supports this case.\n\n### Bipf encoding\n\nWhile many encodings could be used for encoding of especially the\nmetadata part, bipf is a relatively simple format. The JavaScript\nimplementation is roughly 250 lines for encode and decode. Bipf allows\nthe content to be reused when encoding for the database in [ssb-db2]\nresultating in roughly half the time used compared to existing feed\nformat.\n\n[SSB]: https://ssbc.github.io/scuttlebutt-protocol-guide/\n[meta feeds]: https://github.com/ssb-ngi-pointer/ssb-meta-feeds-spec\n[bendy butt]: https://github.com/ssb-ngi-pointer/bendy-butt-spec\n[bipf]: https://github.com/ssbc/bipf\n[bamboo]: https://github.com/AljoschaMeyer/bamboo/\n[ssb-bfe]: https://github.com/ssb-ngi-pointer/ssb-bfe-spec\n[ssb-bfe encrypted data format]: https://github.com/ssb-ngi-pointer/ssb-bfe-spec#5-encrypted-data-formats\n[blake3]: https://github.com/BLAKE3-team/BLAKE3\n[EBT]: https://github.com/ssbc/ssb-ebt\n[ssb-db2]: https://github.com/ssb-ngi-pointer/ssb-db2\n[Why it is ok to sign hashes instead of full messages]: https://crypto.stackexchange.com/questions/6335/is-signing-a-hash-instead-of-the-full-data-considered-secure\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fssbc%2Fssb-buttwoo-spec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fssbc%2Fssb-buttwoo-spec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fssbc%2Fssb-buttwoo-spec/lists"}