rust_elgamal/
lib.rs

1// Library definitions for rust-elgamal.
2// Copyright 2021 Eleanor McMurtry
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16#![no_std]
17#![cfg_attr(feature = "nightly", feature(external_doc))]
18#![cfg_attr(feature = "nightly", doc(include = "../README.md"))]
19
20mod ciphertext;
21mod decrypt;
22mod encrypt;
23
24use curve25519_dalek::constants::{RISTRETTO_BASEPOINT_POINT, RISTRETTO_BASEPOINT_TABLE, RISTRETTO_BASEPOINT_COMPRESSED};
25use curve25519_dalek::ristretto::RistrettoBasepointTable;
26
27pub use curve25519_dalek::scalar::Scalar;
28pub use curve25519_dalek::ristretto::RistrettoPoint;
29pub use curve25519_dalek::ristretto::CompressedRistretto;
30
31pub use curve25519_dalek::traits::Identity;
32pub use curve25519_dalek::traits::IsIdentity;
33pub use curve25519_dalek::traits::MultiscalarMul;
34
35pub use ciphertext::Ciphertext;
36pub use decrypt::DecryptionKey;
37pub use encrypt::EncryptionKey;
38
39/// The group generator as a single point.
40/// If you're trying to create a scalar multiple of the generator, you probably want
41/// [GENERATOR_TABLE](crate::GENERATOR_TABLE) instead.
42pub const GENERATOR_POINT: RistrettoPoint = RISTRETTO_BASEPOINT_POINT;
43
44/// The group generator as a single point, compressed for transit.
45/// If you're trying to create a scalar multiple of the generator, you probably want
46/// [GENERATOR_TABLE](crate::GENERATOR_TABLE) instead.
47pub const GENERATOR_POINT_COMPRESSED: CompressedRistretto = RISTRETTO_BASEPOINT_COMPRESSED;
48
49/// The group generator as a table of precomputed multiples. This is the most efficient way to
50/// produce a scalar multiple of the generator.
51pub const GENERATOR_TABLE: RistrettoBasepointTable = RISTRETTO_BASEPOINT_TABLE;
52
53#[cfg(test)]
54mod tests {
55    use rand::prelude::StdRng;
56    use rand_core::SeedableRng;
57
58    use crate::{DecryptionKey, RistrettoPoint};
59
60    // Test that encrypting a point and decrypting the result does not change a point.
61    #[test]
62    fn encrypt_decrypt() {
63        const N: usize = 100;
64
65        let mut rng = StdRng::from_entropy();
66        let dk = DecryptionKey::new(&mut rng);
67        let ek = dk.encryption_key();
68
69        for _ in 0..N {
70            let m = RistrettoPoint::random(&mut rng);
71            let ct = ek.encrypt(m, &mut rng);
72            let decrypted = dk.decrypt(ct);
73            assert_eq!(m, decrypted);
74        }
75    }
76
77    // Test that re-randomising an encrypted point does not change the decrypted result.
78    #[test]
79    fn rerandomisation() {
80        const N: usize = 100;
81
82        let mut rng = StdRng::from_entropy();
83        let dk = DecryptionKey::new(&mut rng);
84        let ek = dk.encryption_key();
85        let m = RistrettoPoint::random(&mut rng);
86        let ct = ek.encrypt(m, &mut rng);
87
88        for _ in 0..N {
89            let ct = ek.rerandomise(ct, &mut rng);
90            let decrypted = dk.decrypt(ct);
91            assert_eq!(m, decrypted);
92        }
93    }
94
95    // Test that the decrypted sum of two ciphertexts is equal to the sum of the original points.
96    #[test]
97    fn homomorphism() {
98        const N: usize = 100;
99
100        let mut rng = StdRng::from_entropy();
101        let dk = DecryptionKey::new(&mut rng);
102        let ek = dk.encryption_key();
103
104        for _ in 0..N {
105            let m1 = RistrettoPoint::random(&mut rng);
106            let m2 = RistrettoPoint::random(&mut rng);
107            let sum = m1 + m2;
108            let ct1 = ek.encrypt(m1, &mut rng);
109            let ct2 = ek.encrypt(m2, &mut rng);
110            let ct_sum = ct1 + ct2;
111            let decrypted = dk.decrypt(ct_sum);
112            assert_eq!(sum, decrypted);
113        }
114    }
115}