{"id":13687634,"url":"https://github.com/deliberative/crypto","last_synced_at":"2025-04-09T23:07:29.133Z","repository":{"id":57749067,"uuid":"519554496","full_name":"deliberative/crypto","owner":"deliberative","description":"Cryptographic operations in WASM, C, Typescript for Nodejs and the browser.","archived":false,"fork":false,"pushed_at":"2023-11-30T13:09:33.000Z","size":5670,"stargazers_count":29,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-12-17T16:48:42.469Z","etag":null,"topics":["c","crypto","cryptography","elliptic-curves","end-to-end-encryption","hash","javascript","libsodium","merkle-tree","public-key-cryptography","rollup","shamir-secret-sharing","typescript","webassembly"],"latest_commit_sha":null,"homepage":"https://deliberative.github.io/crypto","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/deliberative.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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},"funding":{"github":"deliberative"}},"created_at":"2022-07-30T15:36:14.000Z","updated_at":"2024-11-27T19:55:16.000Z","dependencies_parsed_at":"2023-11-30T13:45:48.786Z","dependency_job_id":"0fadc6aa-6446-4917-b6d6-908dd2d74fe6","html_url":"https://github.com/deliberative/crypto","commit_stats":null,"previous_names":[],"tags_count":56,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deliberative%2Fcrypto","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deliberative%2Fcrypto/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deliberative%2Fcrypto/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deliberative%2Fcrypto/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/deliberative","download_url":"https://codeload.github.com/deliberative/crypto/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":234475795,"owners_count":18839412,"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":["c","crypto","cryptography","elliptic-curves","end-to-end-encryption","hash","javascript","libsodium","merkle-tree","public-key-cryptography","rollup","shamir-secret-sharing","typescript","webassembly"],"created_at":"2024-08-02T15:00:57.829Z","updated_at":"2025-01-18T14:37:47.513Z","avatar_url":"https://github.com/deliberative.png","language":"TypeScript","funding_links":["https://github.com/sponsors/deliberative"],"categories":["c","Built with TypeScript"],"sub_categories":["Libraries"],"readme":"# @deliberative/crypto\n\n[![codecov][codecov-image]][codecov-url]\n[![Known Vulnerabilities](https://snyk.io/test/github/deliberative/crypto/badge.svg?targetFile=package.json)](https://snyk.io/test/github/deliberative/crypto?targetFile=package.json)\n\u003cbr\u003e\n![NPM Version](https://img.shields.io/npm/v/@deliberative/crypto)\n![NPM License](https://img.shields.io/npm/l/@deliberative/crypto)\n[![code-style-prettier][code-style-prettier-image]][code-style-prettier-url]\n\u003cbr\u003e\n![NPM Downloads](https://img.shields.io/npm/dw/@deliberative/crypto)\n[![](https://data.jsdelivr.com/v1/package/npm/@deliberative/crypto/badge)](https://www.jsdelivr.com/package/npm/@deliberative/crypto)\n\n[codecov-image]: https://codecov.io/gh/deliberative/crypto/branch/master/graph/badge.svg\n[codecov-url]: https://codecov.io/gh/deliberative/crypto\n[code-style-prettier-image]: https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square\n[code-style-prettier-url]: https://github.com/prettier/prettier\n\nThis repository is part of the reference implementation of the Deliberative Ledger Protocol, the infrastructure for futuristic democracies.\n\nIt does not have any native dependencies and can be used in both Nodejs and the browser.\n\nThe API is not completely stable and the code has not undergone external security audits. Use at your own risk.\n\n## Introduction\n\nThis library relies heavily on [libsodium](https://github.com/jedisct1/libsodium) for cryptographic operations, which is a battle-tested project, compiled to WebAssembly for speed. In comparison to [tweetnacl](https://github.com/dchest/tweetnacl-js) this library is much faster. You can see some [Benchmarks](#benchmarks) below.\n\nWe have also introduced [Shamir secret sharing](https://en.wikipedia.org/wiki/Shamir%27s_secret_sharing) functionality, where a user can split and restore a secret through the Shamir threshold sharing scheme. To our knowledge, there is not any well-tested open-source implementation of it in WebAssembly and we use it heavily on the Deliberative Ledger protocol.\n\nThe library also has mnemonic generation, validation and Ed25519 key pair from mnemonic functionality that was inspired by [bip39](https://github.com/bitcoinjs/bip39) but instead of Blake2b we use Argon2 and instead of SHA256 we use SHA512, both of which can be found in libsodium.\n\nFinally, you can calculate [Merkle roots](https://en.wikipedia.org/wiki/Merkle_tree), proofs and validate proofs from trees of arbitrary types, as\nlong as you provide a serializer.\n\n## Files\n\nThe [libsodium](https://github.com/deliberative/libsodium) directory contains a fork of libsodium whose only differences with the master branch of libsodium are name changes to the implementation structs.\n\nThe [asymmetric](src/asymmetric) directory contains asymmetric key cryptography functions. The encryption/decryption\nschema is AEAD with forward secrecy, meaning that a throwaway x25519 keypair is generated inside WebAssembly to make the\nkey exchange with the x25519 equivalent of the client's Ed25519 public key.\n\nThe [symmetric](src/symmetric) directory contains AEAD encryption/decryption with a symmetric key.\n\nThe [mnemonic](src/mnemonic) directory contains all the relevant to mnemonic generation functions.\n\nThe [hash](src/hash) directory contains a sha512 hashing function and an Argon2 with optional salt hashing function.\n\nThe [merkle](src/merkle) directory contains a Merkle root getter function, a Merkle\nproof artifacts getter, a root from proof getter and a proof verification function.\n\nThe [shamir](src/shamir) directory contains a WASM implementation of a cryptographic technique called [Shamir's secret\nsharing](https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing), which allows one to split a secret into random shares that can only recreate it if a threshold of them is combined.\nUnder the hood it uses the libsodium randombytes js method to generate random coefficients for the polynomial.\n\nThe [utils](src/utils) directory contains helper methods such as cryptographic random slicing of arrays etc.\n\n## Getting Started\n\nTo get started you have to install the package with\n\n```\nnpm install @deliberative/crypto\n```\n\nYou can include as ES module\n\n```typescript\nimport dcrypto from \"@deliberative/crypto\";\n```\n\nas CommonJS module\n\n```javascript\nconst dcrypto = require(\"@deliberative/crypto\");\n```\n\nor as UMD in the browser with\n\n```html\n\u003cscript src=\"https://cdn.jsdelivr.net/npm/@deliberative/crypto@latest/lib/index.min.js\"\u003e\u003c/script\u003e\n```\n\n## Examples\n\nYou can visit the [examples](examples/js) folder, where you will find examples in\n[CommonJS](examples/js/test.cjs), [ES module](examples/js/test.mjs) and\n[html in the browser](examples/js/test.html).\nFor thorough tests of every exposed function you can look the [**tests**](__tests__) folder.\n\nFor Curve25519 public key cryptography we have the following methods\n\n```typescript\nimport dcrypto from \"@deliberative/crypto\";\n\n// Words from dictionary create random seed for Ed25519 private key.\n// Default entropy is 128bits, which results in 12 words.\nconst mnemonic = await dcrypto.generateMnemonic();\nconsole.log(`Mnemonic with 128 bits of entropy =\u003e 12 words: ${mnemonic}`);\n// Max entropy is 256bit, where generateMnemonic(256) results in 24 words.\n\n// Keypair is an object representing an Ed25519 keypair with { publicKey: Uint8Array(32), secretKey: Uint8Array(64) }\nconst keypair = await dcrypto.keyPairFromMnemonic(mnemonic);\nconsole.log(\n  `Keypair from mnemonic: {\\n\\\n  secretKey: ${Buffer.from(keypair.secretKey).toString(\"hex\")}\\n\\\n  publicKey: ${Buffer.from(keypair.publicKey).toString(\"hex\")}\\n}\\\n`,\n);\n\n// Generates a Uint8Array(128) full of random bytes\nconst message = await dcrypto.randomBytes(128);\n\n// EdDSA\nconst signature = await dcrypto.sign(message, keypair.secretKey);\n\nconst verify = await dcrypto.verify(message, signature, keypair.publicKey);\nconsole.log(verify); // true\n\nconst hash = await dcrypto.sha512(message);\n\nconst keypair2 = await dcrypto.keyPair();\n\n// Forward secrecy box.\n// Encryptor generates a random keypair. The public key is contained in the\n// \"encrypted\" box and the secret key is used for the key exchange with\n// \"keypair2.publicKey\" and then it is removed from memory.\nconst encrypted = await dcrypto.encryptForwardSecrecy(\n  message,\n  keypair2.publicKey,\n  hash,\n);\n\nconst decrypted = await dcrypto.decryptForwardSecrecy(\n  encrypted,\n  keypair2.secretKey,\n  hash,\n);\n\n// To test equality for two Uint8Arrays in js you need to check if each of their elements are equal\n// The === operator does not work\nfor (let i = 0; i \u003c message.length; i++) {\n  if (message[i] !== decrypted[i]) console.error(\"Arrays unequal\");\n}\n\nconst symmetricKey = await dcrypto.randomBytes(\n  dcrypto.interfaces.crypto_kx_SESSIONKEYBYTES,\n);\nconst encrypted1 = await dcrypto.encrypt(message, symmetricKey, hash);\nconst decrypted1 = await dcrypto.decrypt(encrypted1, key, hash);\n```\n\nFor Shamir secret sharing you can test the following\n\n```typescript\nimport dcrypto from \"@deliberative/crypto\";\n\nconst keypair = await dcrypto.keyPair();\n\n// 100 splitted shares, you need 60 to recreate keypair.secretKey\n// Note that you can have max 255 shares and threshold \u003c= shares\nconst shares = await dcrypto.splitSecret(keypair.secretKey, 100, 60);\n\n// Should be equal to keypair.secretKey\nconst sk1 = await dcrypto.restoreSecret(shares);\n\nconsole.log(\"sk1 and kaypair.secretKey are equal\");\n\n// Remove 40 shares to see if it will still work\nconst lessShares = shares.slice(0, shares.length - 40);\n\n// Should be equal to sk1 and keypair.secretKey\nconst sk2 = await dcrypto.restoreSecret(lessShares);\n\nconsole.log(\"sk2 and kaypair.secretKey are equal\");\n\nconst evenLessShares = lessShares.slice(0, lessShares.length - 1);\n\n// Should not be equal to sk1 and sk2.\nconst sk3 = await dcrypto.restoreSecret(evenLessShares);\n\nconsole.log(\"sk3 and kaypair.secretKey are NOT equal\");\n```\n\nIn order to find the Merkle root, proof and to verify the proof you can do the following:\n\n```typescript\nimport dcrypto from \"@deliberative/crypto\";\n\nconst randomArrays: Uint8Array[] = [];\nfor (let i = 0; i \u003c 50; i++) {\n  randomArrays.push(await dcrypto.randomBytes(32));\n}\n\n// dcrypto.constants.crypto_hash_sha512_BYTES\n// Function also accepts any type of data but it then requires a serializer function.\nconst randomArraysMerkleRoot = await dcrypto.getMerkleRoot(randomArrays);\n\n// Multiple of dcrypto.constants.crypto_hash_sha512_BYTES\nconst randomArrayMerkleProof = await dcrypto.getMerkleProof(\n  randomArrays,\n  randomArrays[43],\n);\n\nconst elementHash = await dcrypto.sha512(randomArrays[43]);\n\nconst verify = await dcrypto.verifyMerkleProof(\n  elementHash,\n  randomArraysMerkleRoot,\n  randomArrayMerkleProof,\n);\n\nconsole.log(verify); // should be true\n```\n\nFor more examples you can see the [tests](__tests__) directory.\n\n## Development\n\nIf you want to bundle the library yourselves, you need to have [Emscripten](https://github.com/emscripten-core/emscripten)\ninstalled on your machine in order to compile the C code into WebAssembly.\nWe have the `-s SINGLE_FILE=1` option for the `emcc` compiler, which converts the `wasm` file to a `base64` string\nthat will be compiled by the glue js code into a WebAssembly module. This was done for the purpose of interoperability\nand modularity.\n\nClone the repo, download the libsodium submodule and install packages:\n\n```\ngit clone https://github.com/deliberative/crypto.git\ngit submodule init\ngit submodule update\nnpm i\n```\nOnce you have all the dependencies installed, you can run\n\n```\nnpm run build\n```\n\nand [Rollup](https://github.com/rollup/rollup) will generate the UMD, ESM and CJS bundles.\n\nFor development compilation you can run\n\n```\nnpm run build:debug\n```\n\nand everything will work in debug mode.\n\n## Benchmarks\n\n```\n\u003e node benchmarks/hash/index.js\n# sha512 native crypto 10000 times\nok ~33 ms\n\n# sha512 @deliberative/crypto 10000 times\nok ~37 ms\n\n# sha512 tweetnacl 10000 times\nok ~84 ms\n\n\u003e node benchmarks/symmetric/index.js\n# X25519 e2e encrypt/decrypt native crypto 10000 times\nok ~83 ms\n\n# X25519 @deliberative/crypto 10000 times\nok ~5.73 s\n\n# X25519 tweetnacl 10000 times\nok ~12 s\n\n\u003e node benchmarks/asymmetric/index.js\n# Ed25519 sign/verify native crypto 10000 times\nok ~1.34 s\n\n# Ed25519 @deliberative/crypto 10000 times\nok ~1.91 s\n\n# Ed25519 tweetnacl 10000 times\nok ~1.65 min\n```\n\n## Releases\n\nReleases are available on [Github](https://github.com/deliberative/crypto/releases)\nand [npmjs.com](https://www.npmjs.com/package/@deliberative/crypto)\n\n## License\n\nThe source code is licensed under the terms of the Apache License version 2.0 (see [LICENSE](LICENSE)).\n\n## Copyright\n\nCopyright (C) 2022-2023 Deliberative Technologies P.C.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeliberative%2Fcrypto","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdeliberative%2Fcrypto","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeliberative%2Fcrypto/lists"}