elastic_elgamal/
lib.rs

1//! [ElGamal encryption] and related cryptographic protocols with pluggable crypto backend.
2//!
3//! # ⚠ Warnings
4//!
5//! While the logic in this crate relies on standard cryptographic assumptions
6//! (complexity of discrete log and computational / decisional Diffie–Hellman problems
7//! in certain groups), it has not been independently verified for correctness or absence
8//! of side-channel attack vectors. **Use at your own risk.**
9//!
10//! ElGamal encryption is not a good choice for general-purpose public-key encryption
11//! since it is vulnerable to [chosen-ciphertext attacks][CCA]. For security,
12//! decryption operations should be limited on the application level.
13//!
14//! # Overview
15//!
16//! - [`Ciphertext`] provides ElGamal encryption. This and other protocols use
17//!   [`PublicKey`], [`SecretKey`] and [`Keypair`] to represent participants' keys.
18//! - Besides basic encryption, `PublicKey` also provides zero-knowledge proofs of
19//!   [zero encryption](PublicKey::encrypt_zero()) and of
20//!   [Boolean value encryption](PublicKey::encrypt_bool()). These are useful in higher-level
21//!   protocols, e.g., re-encryption.
22//! - Zero-knowledge range proofs for ElGamal ciphertexts are provided via [`RangeProof`]s
23//!   and a high-level [`PublicKey` method](PublicKey::encrypt_range()).
24//! - Proof of equivalence between an ElGamal ciphertext and a Pedersen commitment
25//!   is available as [`CommitmentEquivalenceProof`].
26//! - [`sharing`] module exposes a threshold encryption scheme based
27//!   on [Feldman's verifiable secret sharing][feldman-vss], including verifiable distributed
28//!   decryption.
29//! - [`dkg`] module implements distributed key generation using [Pedersen's scheme][pedersen-dkg]
30//!   with hash commitments.
31//! - [`app`] module provides higher-level protocols utilizing zero-knowledge proofs
32//!   and ElGamal encryption, such as provable encryption of m-of-n choice and a simple version
33//!   of [quadratic voting].
34//!
35//! # Backends
36//!
37//! [`group`] module exposes a generic framework for plugging a [`Group`]
38//! implementation into crypto primitives. It also provides several implementations:
39//!
40//! - [`Ristretto`] and [`Curve25519Subgroup`] implementations based on Curve25519.
41//! - [`Generic`] implementation allowing to plug in any elliptic curve group conforming to
42//!   the traits specified by the [`elliptic-curve`] crate. For example,
43//!   the secp256k1 curve can be used via the [`k256`] crate.
44//!
45//! # Crate features
46//!
47//! ## `std`
48//!
49//! *(on by default)*
50//!
51//! Enables support of types from `std`, such as the `Error` trait and the `HashMap` collection.
52//!
53//! ## `hashbrown`
54//!
55//! *(off by default)*
56//!
57//! Imports hash maps and sets from the [eponymous crate][`hashbrown`]
58//! instead of using ones from the Rust std library. This feature is necessary
59//! if the `std` feature is disabled.
60//!
61//! ## `curve25519-dalek`
62//!
63//! *(on by default)*
64//!
65//! Implements [`Group`] for two prime groups based on Curve25519 using the [`curve25519-dalek`]
66//! crate: its prime subgroup, and the Ristretto transform of Curve25519 (aka ristretto255).
67//!
68//! ## `curve25519-dalek-ng`
69//!
70//! *(off by default)*
71//!
72//! Same in terms of functionality as `curve25519-dalek`, but uses the [`curve25519-dalek-ng`]
73//! crate instead of [`curve25519-dalek`]. This may be beneficial for applications that use
74//! [`bulletproofs`] or other libraries depending on `curve25519-dalek-ng`.
75//!
76//! The `curve25519-dalek-ng` crate does not compile unless some crypto backend is selected.
77//! You may select the backend by specifying `curve25519-dalek-ng` as a direct dependency as follows:
78//!
79//! ```toml
80//! [dependencies.elastic-elgamal]
81//! version = "..."
82//! default-features = false
83//! features = ["std", "curve25519-dalek-ng"]
84//!
85//! [dependencies.curve25519-dalek-ng]
86//! version = "4"
87//! features = ["u64_backend"] # or other backend
88//! ```
89//!
90//! This feature is mutually exclusive with `curve25519-dalek`.
91//!
92//! ## `serde`
93//!
94//! *(off by default)*
95//!
96//! Enables [`Serialize`](::serde::Serialize) / [`Deserialize`](::serde::Deserialize)
97//! implementations for most types in the crate.
98//! Group scalars, elements and wrapper key types are serialized to human-readable formats
99//! (JSON, YAML, TOML, etc.) as strings that represent corresponding byte buffers using
100//! base64-url encoding without padding. For binary formats, byte buffers are serialized directly.
101//!
102//! For complex types (e.g., participant states from the [`sharing`] module), self-consistency
103//! checks are **not** performed on deserialization. That is, deserialization of such types
104//! should only be performed from a trusted source or in the presence of additional integrity
105//! checks.
106//!
107//! # Crate naming
108//!
109//! "Elastic" refers to pluggable backends, configurable params for threshold encryption,
110//! and the construction of zero-knowledge [`RingProof`]s (a proof consists of
111//! a variable number of rings, each of which consists of a variable number of admissible values).
112//! `elastic_elgamal` is also one of [autogenerated Docker container names][docker-rng].
113//!
114//! [ElGamal encryption]: https://en.wikipedia.org/wiki/ElGamal_encryption
115//! [CCA]: https://en.wikipedia.org/wiki/Chosen-ciphertext_attack
116//! [feldman-vss]: https://www.cs.umd.edu/~gasarch/TOPICS/secretsharing/feldmanVSS.pdf
117//! [pedersen-dkg]: https://link.springer.com/content/pdf/10.1007/3-540-46416-6_47.pdf
118//! [`Group`]: group::Group
119//! [`Ristretto`]: group::Ristretto
120//! [`Curve25519Subgroup`]: group::Curve25519Subgroup
121//! [`curve25519-dalek`]: https://docs.rs/curve25519-dalek/
122//! [`curve25519-dalek-ng`]: https://docs.rs/curve25519-dalek-ng/
123//! [`bulletproofs`]: https://docs.rs/bulletproofs/
124//! [`Generic`]: group::Generic
125//! [`elliptic-curve`]: https://docs.rs/elliptic-curve/
126//! [`k256`]: https://docs.rs/k256/
127//! [`hashbrown`]: https://docs.rs/hashbrown/
128//! [docker-rng]: https://github.com/moby/moby/blob/master/pkg/namesgenerator/names-generator.go
129//! [quadratic voting]: https://en.wikipedia.org/wiki/Quadratic_voting
130
131#![cfg_attr(not(feature = "std"), no_std)]
132// Documentation settings.
133#![cfg_attr(docsrs, feature(doc_cfg))]
134#![doc(html_root_url = "https://docs.rs/elastic-elgamal/0.3.1")]
135// Linter settings.
136#![warn(missing_debug_implementations, missing_docs, bare_trait_objects)]
137#![warn(clippy::all, clippy::pedantic)]
138#![allow(
139    clippy::must_use_candidate,
140    clippy::module_name_repetitions,
141    clippy::doc_markdown
142)]
143
144pub mod app;
145mod decryption;
146pub mod dkg;
147mod encryption;
148pub mod group;
149mod keys;
150mod proofs;
151#[cfg(feature = "serde")]
152mod serde;
153pub mod sharing;
154
155// Polyfill for `alloc` types.
156mod alloc {
157    #[cfg(not(feature = "std"))]
158    extern crate alloc as std;
159
160    pub use std::{borrow::Cow, string::ToString, vec, vec::Vec};
161
162    #[cfg(all(not(feature = "std"), not(feature = "hashbrown")))]
163    compile_error!(
164        "One of `std` or `hashbrown` features must be enabled in order \
165         to get a hash map implementation"
166    );
167
168    #[cfg(not(feature = "hashbrown"))]
169    pub use std::collections::HashMap;
170
171    #[cfg(feature = "hashbrown")]
172    pub use hashbrown::HashMap;
173}
174
175// Polyfill for Curve25519 types.
176#[cfg(any(feature = "curve25519-dalek-ng", feature = "curve25519-dalek"))]
177mod curve25519 {
178    #[cfg(all(feature = "curve25519-dalek-ng", feature = "curve25519-dalek"))]
179    compile_error!("`curve25519-dalek-ng` and `curve25519-dalek` features are mutually exclusive");
180
181    #[cfg(feature = "curve25519-dalek")]
182    pub use curve25519_dalek::*;
183    #[cfg(feature = "curve25519-dalek-ng")]
184    pub use curve25519_dalek_ng::*;
185}
186
187mod sealed {
188    pub trait Sealed {}
189}
190
191pub use elliptic_curve;
192
193pub use crate::{
194    decryption::{CandidateDecryption, VerifiableDecryption},
195    encryption::{Ciphertext, CiphertextWithValue, DiscreteLogTable},
196    keys::{Keypair, PublicKey, PublicKeyConversionError, SecretKey},
197    proofs::{
198        CommitmentEquivalenceProof, LogEqualityProof, PreparedRange, ProofOfPossession,
199        RangeDecomposition, RangeProof, RingProof, RingProofBuilder, SumOfSquaresProof,
200        VerificationError,
201    },
202};
203
204#[cfg(doctest)]
205doc_comment::doctest!("../README.md");