{"id":16417259,"url":"https://github.com/Consensys/constellation","last_synced_at":"2025-10-26T20:30:24.919Z","repository":{"id":66195902,"uuid":"73673710","full_name":"Consensys/constellation","owner":"Consensys","description":"Peer-to-peer encrypted message exchange","archived":true,"fork":false,"pushed_at":"2020-07-06T12:57:42.000Z","size":253,"stargazers_count":378,"open_issues_count":3,"forks_count":114,"subscribers_count":75,"default_branch":"master","last_synced_at":"2024-05-23T02:32:22.405Z","etag":null,"topics":["crypto","encryption","haskell","p2p","peer-to-peer","privacy"],"latest_commit_sha":null,"homepage":null,"language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Consensys.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2016-11-14T06:27:55.000Z","updated_at":"2024-04-23T01:49:41.000Z","dependencies_parsed_at":null,"dependency_job_id":"536d61a3-a890-4082-83a9-ef4739667786","html_url":"https://github.com/Consensys/constellation","commit_stats":null,"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Consensys%2Fconstellation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Consensys%2Fconstellation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Consensys%2Fconstellation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Consensys%2Fconstellation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Consensys","download_url":"https://codeload.github.com/Consensys/constellation/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238394323,"owners_count":19464583,"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","encryption","haskell","p2p","peer-to-peer","privacy"],"created_at":"2024-10-11T07:11:23.549Z","updated_at":"2025-10-26T20:30:19.500Z","avatar_url":"https://github.com/Consensys.png","language":"Haskell","readme":"# Constellation\n\nConstellation is a self-managing, peer-to-peer system in which each\nnode:\n\n  - Hosts a number of NaCl (Curve25519) public/private key pairs.\n\n  - Automatically discovers other nodes on the network after\n    synchronizing with as little as one other host.\n\n  - Synchronizes a directory of public keys mapped to recipient hosts\n    with other nodes on the network.\n\n  - Exposes a public API which allows other nodes to send encrypted\n    bytestrings to your node, and to synchronize, retrieving\n    information about the nodes that your node knows about.\n\n  - Exposes a private API which:\n\n      - Allows you to send a bytestring to one or more public keys,\n        returning a content-addressable identifier. This bytestring is\n        encrypted transparently and efficiently (at symmetric\n        encryption speeds) before being transmitted over the wire to\n        the correct recipient nodes (and only those nodes.) The\n        identifier is a hash digest of the encrypted payload that\n        every recipient node receives. Each recipient node also\n        receives a small blob encrypted for their public key which\n        contains the Master Key for the encrypted payload.\n\n      - Allows you to receive a decrypted bytestring\n        based on an identifier. Payloads which your node has sent or\n        received can be decrypted and retrieved in this way.\n\n      - Exposes methods for deletion, resynchronization, and other\n        management functions.\n\n  - Supports a number of storage backends including LevelDB,\n    BerkeleyDB, SQLite, and Directory/Maildir-style file storage\n    suitable for use with any FUSE adapter, e.g. for AWS S3.\n\n  - Uses mutually-authenticated TLS with modern settings and various trust\n    models including hybrid CA/tofu (default), tofu (think OpenSSH), and\n    whitelist (only some set of public keys can connect.)\n\n  - Supports access controls like an IP whitelist.\n\nConceptually, one can think of Constellation as an amalgamation of a\ndistributed key server, PGP encryption (using modern cryptography,)\nand Mail Transfer Agents (MTAs.)\n\nConstellation's current primary application is to implement the\n\"privacy engine\" of Quorum, a fork of Ethereum with support for\nprivate transactions that function exactly as described in this\nREADME. Private transactions in Quorum contain only a flag indicating\nthat they're private and the content-addressable identifier described\nhere.\n\nConstellation can be run stand-alone as a daemon via\n`constellation-node`, or imported as a Haskell library, which allows\nyou to implement custom storage and encryption logic.\n\n## Installation\n\n### Prerequisites\n\n  1. Install supporting libraries:\n    - Ubuntu: `apt-get install libdb-dev libleveldb-dev libsodium-dev zlib1g-dev libtinfo-dev`\n    - Red Hat: `dnf install libdb-devel leveldb-devel libsodium-devel zlib-devel ncurses-devel`\n    - MacOS: `brew install berkeley-db leveldb libsodium`\n\n### Downloading precompiled binaries\n\nConstellation binaries for most major platforms can be downloaded [here](https://github.com/jpmorganchase/constellation/releases).\n\n### Installation from source\n\n  1. First time only: Install Stack:\n    - Linux: `curl -sSL https://get.haskellstack.org/ | sh`\n    - MacOS: `brew install haskell-stack`\n\n  2. First time only: run `stack setup` to install GHC, the Glasgow\n     Haskell Compiler\n\n  3. Run `stack install`\n\n## Generating keys\n\n  1. To generate a key pair \"node\", run `constellation-node --generatekeys=node`\n\n  If you choose to lock the keys with a password, they will be encrypted using\n  a master key derived from the password using Argon2id. This is designed to be\n  a very expensive operation to deter password cracking efforts. When\n  constellation encounters a locked key, it will prompt for a password after\n  which the decrypted key will live in memory until the process ends.\n\n## Running\n\n  1. Run `constellation-node \u003cpath to config file\u003e` or specify configuration\n     variables as command-line options (see `constellation-node --help`)\n\nFor now, please refer to the [Constellation client Go library](https://github.com/jpmorganchase/quorum/blob/master/private/constellation/node.go)\nfor an example of how to use Constellation. More detailed documentation coming soon!\n\n## Configuration File Format\n\nSee [sample.conf](sample.conf).\n\n## How It Works\n\nEach Constellation node hosts some number of key pairs, and advertises\na publicly accessible FQDN/port for other hosts to connect to.\n\nNodes can be started with a reference to existing nodes on the network\n(with the `othernodes` configuration variable,) or without, in which\ncase some other node must later be pointed to this node to achieve\nsynchronization.\n\nWhen a node starts up, it will reach out to each node in `othernodes`,\nand learn about the public keys they host, as well as other nodes in\nthe network. In short order, the node's public key directory will be\nthe same as that of all other nodes, and you can start addressing\nmessages to any of the known public keys.\n\nThis is what happens when you use the `send` function of the Private\nAPI to send the bytestring `foo` to the public key\n`ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc=`:\n\n  1. You send a POST API request to the Private API socket like:\n     `{\"payload\": \"foo\", \"from\": \"mypublickey\", to: \"ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc=\"}`\n\n  2. The local node generates using `/dev/urandom` (or similar):\n       - A random Master Key (MK) and nonce\n       - A random recipient nonce\n\n  3. The local node encrypts the payload using NaCl `secretbox` using\n     the random MK and nonce.\n\n  4. The local node generates an MK container for each recipient\n     public key; in this case, simply one container for `ROAZ...`,\n     using NaCl `box` and the recipient nonce.\n\n     NaCl `box` works by deriving a shared key based\n     on your private key and the recipient's public key. This is known\n     as elliptic curve key agreement.\n\n     Note that the sender public key and recipient public key we\n     specified above aren't enough to perform the\n     encryption. Therefore, the node will check to see that it is\n     actually hosting the private key that corresponds to the given\n     public key before generating an MK container for each recipient\n     based on SharedKey(yourprivatekey, recipientpublickey) and the\n     recipient nonce.\n\n     We now have:\n\n       - An encrypted payload which is `foo` encrypted with the random\n         MK and a random nonce. This is the same for all recipients.\n\n       - A random recipient nonce that also is the same for all\n         recipients.\n\n       - For each recipient, the MK encrypted with the\n         shared key of your private key and their public key. This\n         MK container is unique per recipient, and is only transmitted to\n         that recipient.\n\n  5. For each recipient, the local node looks up the recipient host,\n     and transmits to it:\n\n       - The sender's (your) public key\n\n       - The encrypted payload and nonce\n\n       - The MK container for that recipient and the recipient nonce\n\n  6. The recipient node returns a SHA3-512 hash digest of the\n     encrypted payload, which represents its storage address.\n\n     (Note that it is not possible for the sender to dictate the\n     storage address. Every node generates it independently by hashing\n     the encrypted payload.)\n\n  7. The local node stores the payload locally, generating the same\n     hash digest.\n\n  8. The API call returns successfully once all nodes have confirmed\n     receipt and storage of the payload, and returned a hash digest.\n\nNow, through some other mechanism, you'll inform the recipient that\nthey have a payload waiting for them with the identifier `owqkrokwr`,\nand they will make a call to the `receive` method of their Private\nAPI:\n\n  1. Make a call to the Private API socket `receive` method:\n     `{\"key\": \"qrqwrqwr\"}`\n\n  2. The local node will look in its storage for the key `qrqwrqwr`,\n     and abort if it isn't found.\n\n  3. When found, the node will use the information about the sender as\n     well as its private key to derive SharedKey(senderpublickey,\n     yourprivatekey) and decrypt the MK container using NaCl `box`\n     with the recipient nonce.\n\n  4. Using the decrypted MK, the local node will decrypt the encrypted\n     payload using NaCl `secretbox` using the main nonce.\n\n  5. The API call returns the decrypted data.\n\n# Getting Help\nStuck at some step? Please join our \u003ca href=\"https://www.goquorum.com/slack-inviter\" target=\"_blank\" rel=\"noopener\"\u003eslack community\u003c/a\u003e for support.\n\n","funding_links":[],"categories":["Haskell"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FConsensys%2Fconstellation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FConsensys%2Fconstellation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FConsensys%2Fconstellation/lists"}