{"id":15640546,"url":"https://github.com/soatok/rawr-x3dh","last_synced_at":"2025-04-14T22:45:18.274Z","repository":{"id":56036307,"uuid":"313453941","full_name":"soatok/rawr-x3dh","owner":"soatok","description":"TypeScript Implementation of X3DH","archived":false,"fork":false,"pushed_at":"2023-03-15T06:27:39.000Z","size":139,"stargazers_count":91,"open_issues_count":2,"forks_count":5,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-10T15:34:28.968Z","etag":null,"topics":["crypto","cryptography","diffie-hellman","ed25519","furry","javascript","key-agreement","libsodium","nodejs","typescript","x25519","x3dh"],"latest_commit_sha":null,"homepage":"https://soatok.blog/2020/11/14/going-bark-a-furrys-guide-to-end-to-end-encryption/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/soatok.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-11-16T23:32:30.000Z","updated_at":"2025-04-09T02:14:16.000Z","dependencies_parsed_at":"2024-10-23T05:26:14.187Z","dependency_job_id":null,"html_url":"https://github.com/soatok/rawr-x3dh","commit_stats":{"total_commits":12,"total_committers":2,"mean_commits":6.0,"dds":0.08333333333333337,"last_synced_commit":"c783ef7ab1fd678cff3ac3a5c6113d1c0059c9c5"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soatok%2Frawr-x3dh","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soatok%2Frawr-x3dh/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soatok%2Frawr-x3dh/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/soatok%2Frawr-x3dh/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/soatok","download_url":"https://codeload.github.com/soatok/rawr-x3dh/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248247980,"owners_count":21072040,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["crypto","cryptography","diffie-hellman","ed25519","furry","javascript","key-agreement","libsodium","nodejs","typescript","x25519","x3dh"],"created_at":"2024-10-03T11:37:16.081Z","updated_at":"2025-04-14T22:45:18.254Z","avatar_url":"https://github.com/soatok.png","language":"TypeScript","funding_links":["https://patreon.com/soatok"],"categories":[],"sub_categories":[],"readme":"# ![Rawr X3DH](.github/RawrX3DH-Github.png)\n\nTypeScript implementation of X3DH, as described in\n***[Going Bark: A Furry's Guide to End-to-End Encryption](https://soatok.blog/2020/11/14/going-bark-a-furrys-guide-to-end-to-end-encryption/)***.\n\n[![Support me on Patreon](https://img.shields.io/endpoint.svg?url=https%3A%2F%2Fshieldsio-patreon.vercel.app%2Fapi%3Fusername%3Dsoatok%26type%3Dpatrons\u0026style=for-the-badge)](https://patreon.com/soatok)\n\n[![Travis CI](https://travis-ci.org/soatok/rawr-x3dh.svg?branch=master)](https://travis-ci.org/soatok/rawr-x3dh)\n[![npm version](https://img.shields.io/npm/v/rawr-x3dh.svg)](https://npm.im/rawr-x3dh)\n\n## [OwO](https://soatok.files.wordpress.com/2020/09/soatoktelegrams2020-06.png) What's This?\n\nThis library implements the [Extended Triple Diffie-Hellman](https://signal.org/docs/specifications/x3dh/)\nkey exchange, with a few minor tweaks:\n\n1. Identity keys are Ed25519 public keys, not X25519 public keys.\n   [See this for an explanation](https://soatok.blog/2020/11/14/going-bark-a-furrys-guide-to-end-to-end-encryption/#why-ed25519-keys-x3dh).\n2. Encryption/decryption and KDF implementations are pluggable\n   (assuming you implement the interface I provide), so you aren't\n   married to HKDF or a particular cipher. (Although I recommend hard-coding\n   it to your application!)\n\n## Installation\n\nFirst, you'll want to install this library via your package manager.\n\n```terminal\nnpm install rawr-x3dh\n```\n\nIf you're working server-side, you'll also want to install [sodium-native](https://www.npmjs.com/package/sodium-native),\nso that [sodium-plus](https://www.npmjs.com/package/sodium-plus) will run faster.\n\nIf you're working in a browser or browser extension, don't install sodium-native.\n\n## Usage\n\nFirst, you'll want to import the X3DH class from our module.\n\n```typescript\nimport { X3DH } from 'rawr-x3dh';\n\nconst x3dh = new X3DH();\n```\n\nNote: You can pass some classes to the constructor to replace my algorithm implementations\nfor your own.\n\n```typescript\nimport { X3DH } from 'rawr-x3dh';\n\nconst x3dh = new X3DH(\n    sessionKeyManager, /* SessionKeyManagerInterface */\n    identityKeyManager, /* IdentityKeyManagerInterface */\n    symmetricEncryptionHandler, /* SymmetricEncryptionInterface */\n    keyDerivationFunction /* KeyDerivationFunction */\n);\n```\n\nOnce your X3DH object's instantiated, you will be able to initialize handshakes\neither as a sender or as a recipient. Then you will be able to encrypt additional\nmessages on either side, and the encryption key shall ratchet forward.\n\n```typescript\nconst firstEncrypted = await x3dh.initSend(\n    'recipient@server2',\n    serverApiCallFunc,\n    firstMessage\n); \n```\n\nThe `serverApiCallFunc` parameter should be a function that sends a request to the server\nto obtain the identity key, signed pre-key, and optional one-time key for the handshake.\n\nSee the definition of the `InitClientFunction` type in `lib/index.ts`.\n\nOnce this has completed, you can call `encryptNext()` multiple times to append messages\nto send.\n\n```typescript\nconst nextEncrypted = await x3dh.encryptNext(\n    'recipient@server2',\n    'This is a follow-up message UwU'\n);\n```\n\nOn the other side, your communication partner will use the following feature.\n\n```typescript\nconst [sender, firstMessage] = await x3dh.initRecv(senderInfo);\nconst nextMessage = await x3dh.decryptNext(sender, nextEncrypted);\n```\n\nNote: `initRecv()` will always return the sender identity (a string) and the\nmessage (a `Buffer` that can be converted to a string). The sender identity\nshould be usable for `decryptNext()` calls.\n\nHowever, that doesn't mean it's trustworthy! This library only implements\nthe X3DH pattern. It doesn't implement the \n[Gossamer integration](https://soatok.blog/2020/11/14/going-bark-a-furrys-guide-to-end-to-end-encryption/#identity-key-management).\n\n## Should I Use This?\n\nDon't use it in production until version 1.0.0 has been tagged.\nThe API can break at any moment until that happens (especially if\nI decide I hate the default key management classes I wrote).\n\nHowever, feel free to test and play with it.\n\n## Questions and Answers\n\n### Any Interest in Porting This to $LANG?\n\nI'd love to port this to more languages! That will also allow me to write end-to-end integration tests.\n\nAs long as there's a good [libsodium implementation](https://libsodium.gitbook.io/doc/bindings_for_other_languages),\nit should be doable.\n\nHowever, I don't have *nearly* as much free time as I'd like, so I can't commit to\nbuilding or supporting multiple implementations right now.\n\nConversely, if you've ported this to another language, let me know and I'll maintain\na list here:\n\n* (Currently, none.)\n\n### Why \"Rawr\"?\n\nThe canonical abbreviation for the eXtended 3-way Diffie Hellman\ndeniable authenticated key exchange is X3DH.\n\nThere is a [cursed furry copypasta/meme](https://knowyourmeme.com/memes/notices-bulge-owo-whats-this) \nthat begins with \"rawr x3\". The juxtaposition of \"x3\" and \"X3DH\" is too perfect\nan opportunity for dumb jokes to pass up.\n\n### Is this a furry thing?\n\n[![You betcha!](https://soatok.files.wordpress.com/2020/08/soatoktelegrams2020-03.png)](https://soatok.blog/2020/11/14/going-bark-a-furrys-guide-to-end-to-end-encryption/)\n\nAnd remember: It's not *furry trash*, it's *yiff-raff*.\n\n#### Why? Just, Why?\n\nI've written a lot of words to answer this line of questioning already on [my blog](https://soatok.blog).\n\nYou will probably find the answer you're seeking [here](https://soatok.blog/2020/07/09/a-word-on-anti-furry-sentiments-in-the-tech-community/)\nor [here](https://soatok.blog/2020/10/23/solving-for-why-furry-blogging-about-cryptography/).\n\n![Comic by loviesophiee](https://soatok.files.wordpress.com/2020/07/increase-the-thing.png)\n\n#### This is Unprofessional\n\nFolks often say there's an XKCD for Everything! And thus:\n\n[![XKCD](https://imgs.xkcd.com/comics/dreams.png)](https://xkcd.com/137/)\n\n#### Who Made That Awesome Project Logo?\n\n[Sophie](https://twitter.com/loviesophiee) made it.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoatok%2Frawr-x3dh","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsoatok%2Frawr-x3dh","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsoatok%2Frawr-x3dh/lists"}