{"id":28396162,"url":"https://github.com/ssbc/bendy-butt-spec","last_synced_at":"2026-02-19T04:32:21.881Z","repository":{"id":45270707,"uuid":"370806286","full_name":"ssbc/bendy-butt-spec","owner":"ssbc","description":null,"archived":false,"fork":false,"pushed_at":"2021-12-26T09:04:37.000Z","size":59,"stargazers_count":6,"open_issues_count":3,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-10-11T13:18:42.342Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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":"LICENSES/CC0-1.0.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-05-25T19:28:32.000Z","updated_at":"2022-10-18T17:24:15.000Z","dependencies_parsed_at":"2022-09-13T16:10:44.770Z","dependency_job_id":null,"html_url":"https://github.com/ssbc/bendy-butt-spec","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ssbc/bendy-butt-spec","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssbc%2Fbendy-butt-spec","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssbc%2Fbendy-butt-spec/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssbc%2Fbendy-butt-spec/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssbc%2Fbendy-butt-spec/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ssbc","download_url":"https://codeload.github.com/ssbc/bendy-butt-spec/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ssbc%2Fbendy-butt-spec/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29603074,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-19T04:01:40.476Z","status":"ssl_error","status_checked_at":"2026-02-19T04:01:12.960Z","response_time":117,"last_error":"SSL_read: 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:05.651Z","updated_at":"2026-02-19T04:32:21.856Z","avatar_url":"https://github.com/ssbc.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003c!--\nSPDX-FileCopyrightText: 2021 Anders Rune Jensen\n\nSPDX-License-Identifier: CC0-1.0\n--\u003e\n\n# Bendy Butt\n\nWhat is Bendy Butt?\n\n\u003e A new feed format designed for [meta feeds]\n\nWhy a new feed format, when we already have [gabby grove] and [bamboo]?\n\n\u003e Because we would want to offer a feed format that is simple and easy\n\u003e to implement in any programming language by reusing an established\n\u003e format ([bencode]) with existing encoder libraries.  Furthermore, as\n\u003e meta feeds makes it easier to have multiple feed formats, we wanted\n\u003e to show that creating a new feed format does not have to be hard.\n\nCan't you just use the classic format?\n\n\u003e That would mean clients would have to support reading and writing\n\u003e the classic format forever, even for applications that only use\n\u003e newer feed formats.\n\nWhat is wrong with the classic format?\n\n\u003e There are multiple problems, most of them come from the fact that it\n\u003e is very tied to the internals of the v8 engine for Javascript. JSON\n\u003e is good as an exchange format for values of data but not well suited\n\u003e to cryptographically sign messages where a canonical representation\n\u003e of each value is paramount.\n\nCan I use Bendy Butt for purposes other than meta feeds?\n\n\u003e Yes, but Bendy Butt was not designed as a general purpose feed \n\u003e format. We do not intend to extend Bendy Butt to cover any other\n\u003e use cases besides meta feeds, but if the feed format constraints\n\u003e are sufficient for your use cases, nothing stops you from using it.\n\u003e To preserve the simplicity of this spec, we recommend not sending\n\u003e patches to the spec to generalize it.\n\n## Definitions\n\nThe key words \"MUST\", \"MUST NOT\", \"REQUIRED\", \"SHALL\", \"SHALL NOT\", \"SHOULD\",\n\"SHOULD NOT\", \"RECOMMENDED\", \"MAY\", and \"OPTIONAL\" in this document are to be\ninterpreted as described in RFC 2119.\n\n**Notations for bencode and BFE**\n\nTo avoid confusion with JSON, we shall use the notation `{ \"a\" =\u003e 1, \"b\" =\u003e 2 }`\nto denote a [bencode] *dictionary* with two entries: key \"a\" mapping to value\n`1` and key \"b\" mapping to value `2`.  We shall use the notation `[a, b, c]` to\ndenote a [bencode] *list* of three values `a`, `b`, and `c`.\n\nFor sequences of bytes, we use the notation `\u003c03 02 01\u003e` to represent the\nsequence of bytes `03` followed by `02` followed by `01`. We use the notation\n`a + b + c` to denote *byte concatenation* of the byte sequences `a` followed by\n`b` followed by `c`. In other words `\u003c05 04\u003e + \u003c03 02 01\u003e` equals\n`\u003c05 04 03 02 01\u003e`.\n\nFor abstract substitutions, we use `(something)` to denote whatever `something`\ndescribes. In other words, anything wrapped in parentheses is just a placeholder\nfor something else.\n\n## Specification\n\nA *Bendy Butt message* is encoded in [bencode] as a list of message `payload`\nand `signature`, which we shall denote `[payload, signature]`. SSB Binary Field\nEncodings ([SSB-BFE]) is used to encode all non-list non-dictionary non-integer\nvalues contained in the `payload` and `signature`. BFE also helps to\ndisambiguate binary data like feed IDs and message IDs from generic data types\nsuch as strings.\n\nThe message `payload` is a bencode list with 5 elements in this specific order,\nin other words, `[author, sequence, previous, timestamp, contentSection]`:\n\n1) `author`, a BFE-encoded \"feed ID\"\n2) `sequence`, a [bencode integer] greater than or equal to 1\n3) `previous`, a BFE-encoded \"message ID\" of the previous message\n  on the feed. For the first message this must be the BFE \"nil\" generic data\n  type.\n4) `timestamp`, a [bencode integer] representing the UNIX epoch timestamp of message\n  creation.\n5) `contentSection` can be one of two possible shapes:\n    1. `[content, contentSignature]` such that `content` is any bencode\n    dictionary representing the message contents, all of which are internally\n    encoded with BFE; and `contentSignature` is a BFE-encoded \"signature\". The\n    signature is applied on `prefix + content`, where `prefix` is the string\n    \"bendybutt\" encoded as UTF8 bytes. The signature uses some cryptographic\n    keypair which **MAY** be different from the `author` keypair (for example,\n    under the [meta feeds] spec, this will be the subfeed keypair).\n    2. BFE-encoded \"encrypted data\". Upon decryption, it takes the shape\n    `[content, contentSignature]` as described above.\n\nThe message `signature` is applied on `payload` using the `author`'s\ncryptographic keypair.\n\nBoth the `signature` and the `contentSignature` use the same [HMAC signing capability]\n(`sodium.crypto_auth`) and `sodium.crypto_sign_detached` as in the classic\nSSB format (ed25519).\n\nThe key or ID of a Bendy Butt message is the SHA256 hash of the bencoded bytes\nfor `[payload, signature]`, i.e. `key = SHA256([payload, signature])`.\n\n## Example\n\nFollowing our `[a, b]` and `{ \"a\" =\u003e 1, \"b\" =\u003e 2}` notation, which may look\nsimilar to JSON, here is a Bendy Butt message with the `content` dictionary\nequal to `{ \"type\" =\u003e 'greet', \"text\" =\u003e 'Good morning!' }`.\n\n```\n[\n  [\n    \u003c00 03 5c 27 ac 6e f0 cd fb d0 f8 9a 89 a1 b6 5a 36 04 77 a3 3e c7 9c b7 ab 14 cd 90 76 25 59 be e2 ff\u003e,\n    1,\n    \u003c06 02\u003e,\n    12345,\n    [\n      {\n        \"type\" =\u003e \u003c06 00 67 72 65 65 74\u003e,\n        \"text\" =\u003e \u003c06 00 47 6f 6f 64 20 6d 6f 72 6e 69 6e 67 21\u003e\n      }\n      \u003c04 00 51 a6 7a 43 6a 66 f6 6d e0 3d 77 73 c0 b7 ba 98 84 61 32 46 c6 ee 6c 74 1b 1d 9e 59 18 24 b3 c7 1d a3 ec 35 bf e0 32 cf 86 55 7c f8 72 30 e9 56 ... 16 more bytes\u003e\n    ]\n  ],\n  \u003c04 00 6d 57 9f 55 14 d2 d8 69 09 ad 7b 31 f8 24 4f a7 fc 6a 0d c1 1e f4 1a 92 71 86 fb 8d 1b fc d5 17 b3 88 05 f0 a6 48 aa ba 24 f4 46 b0 9e 65 64 b6 ... 16 more bytes\u003e\n]\n```\n\nNotice that is has the shape:\n\n```\n[\n  [\n    author,\n    sequence,\n    previous,\n    timestamp,\n    [\n      content,\n      contentSignature\n    ]\n  ],\n  signature\n]\n```\n\nHere is the same data as above, but displayed in raw binary (hexadecimal):\n\n```\n    Offset   00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n    000000   6C 6C 33 34 3A 00 03 5C 27 AC 6E F0 CD FB D0 F8   ll34:..\\'¬nðÍûÐø\n    000010   9A 89 A1 B6 5A 36 04 77 A3 3E C7 9C B7 AB 14 CD   ..¡¶Z6.w£\u003eÇ.·«.Í\n    000020   90 76 25 59 BE E2 FF 69 31 65 32 3A 06 02 69 31   .v%Y¾âÿi1e2:..i1\n    000030   32 33 34 35 65 6C 64 34 3A 74 65 78 74 31 35 3A   2345eld4:text15:\n    000040   06 00 47 6F 6F 64 20 6D 6F 72 6E 69 6E 67 21 34   ..Good morning!4\n    000050   3A 74 79 70 65 37 3A 06 00 67 72 65 65 74 65 36   :type7:..greete6\n    000060   36 3A 04 00 51 A6 7A 43 6A 66 F6 6D E0 3D 77 73   6:..Q¦zCjfömà=ws\n    000070   C0 B7 BA 98 84 61 32 46 C6 EE 6C 74 1B 1D 9E 59   À·º..a2FÆîlt...Y\n    000080   18 24 B3 C7 1D A3 EC 35 BF E0 32 CF 86 55 7C F8   .$³Ç.£ì5¿à2Ï.U|ø\n    000090   72 30 E9 56 8E D5 7B 25 F6 77 FE 58 3B 17 3D BD   r0éV.Õ{%öwþX;.=½\n    0000A0   E7 08 82 0F 65 65 36 36 3A 04 00 6D 57 9F 55 14   ç...ee66:..mW.U.\n    0000B0   D2 D8 69 09 AD 7B 31 F8 24 4F A7 FC 6A 0D C1 1E   ÒØi.­{1ø$O§üj.Á.\n    0000C0   F4 1A 92 71 86 FB 8D 1B FC D5 17 B3 88 05 F0 A6   ô..q.û..üÕ.³..ð¦\n    0000D0   48 AA BA 24 F4 46 B0 9E 65 64 B6 9A DE 97 F9 18   Hªº$ôF°.ed¶.Þ.ù.\n    0000E0   04 AF 5F 7A F3 5E 5D 4B FD 85 0B 65               .¯_zó^]Ký..e\n```\n\n\n## Validation\n\nFor validation we differentiate between *message validity* and *content\nvalidity*. Since the content can be encrypted, there is potentially no way to\nvalidate that. This means a message should only be rejected before insertion\ninto the local database if it fails the message validation rules. A message\nshould not be included in the bendy butt feed if its content is not valid.\n\nThe message **MUST** conform to the following rules:\n\n - Has the shape of a bencode list `[payload, signature]`\n - The payload has the shape of bencode list `[author, sequence, previous, timestamp, contentSection]`\n - The `previous` field matches the previous message's ID\n - The `signature` field must be correctly signing the `payload`\n - The [SSB-BFE] *type-format* for `author` is `0x0003` (there is no\n upgradeability in the middle of a feed)\n - The [SSB-BFE] *type-format* for `previous` is `0x0104`\n - The `author` is the same as in previous messages on the feed\n - The maximum size of a `[payload, signature]` in bytes must not exceed 8192 bytes\n\nUnder the Bendy Butt spec, the content is free-form, but under the [meta feeds]\nspec there are strict constraints applied to this bencode dictionary.\n\n[SSB]: https://github.com/ssbc/\n[gabby grove]: https://github.com/ssbc/ssb-spec-drafts/tree/master/drafts/draft-ssb-core-gabbygrove/00\n[bamboo]: https://github.com/AljoschaMeyer/bamboo\n[meta feeds]: https://github.com/ssb-ngi-pointer/ssb-meta-feed-spec\n[SSB-BFE]: https://github.com/ssb-ngi-pointer/ssb-binary-field-encodings\n[HMAC signing capability]: https://github.com/ssb-js/ssb-keys#signobjkeys-hmac_key-obj\n[bencode]: https://en.wikipedia.org/wiki/Bencode\n[bencode integer]: https://wiki.theory.org/index.php/BitTorrentSpecification#Integers\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fssbc%2Fbendy-butt-spec","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fssbc%2Fbendy-butt-spec","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fssbc%2Fbendy-butt-spec/lists"}