1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#![deny(rustdoc::broken_intra_doc_links)]
//! Welcome the the `concrete-boolean` documentation!
//!
//! # Description
//! This library makes it possible to execute boolean gates over encrypted bits.
//! It allows to execute a boolean circuit on an untrusted server because both circuit inputs and
//! outputs are kept private.
//! Data are indeed encrypted on the client side, before being sent to the server.
//! On the server side every computation is performed on ciphertexts.
//! The server however has to know the boolean circuit to be evaluated.
//! At the end of the computation, the server returns the encryption of the result to the user.
//!
//!
//!
//! # Quick Example
//!
//! The following piece of code shows how to generate keys and run a small Boolean circuit
//! homomorphically.
//!
//! ```rust
//! # #[cfg(not(feature = "cuda"))]
//! # fn main() {
//!
//! //! use concrete_boolean::gen_keys;
//! use concrete_boolean::prelude::*;
//!
//! // We generate a set of client/server keys, using the default parameters:
//! let (mut client_key, mut server_key) = gen_keys();
//!
//! // We use the client secret key to encrypt two messages:
//! let ct_1 = client_key.encrypt(true);
//! let ct_2 = client_key.encrypt(false);
//!
//! // We use the server public key to execute a boolean circuit:
//! // if ((NOT ct_2) NAND (ct_1 AND ct_2)) then (NOT ct_2) else (ct_1 AND ct_2)
//! let ct_3 = server_key.not(&ct_2);
//! let ct_4 = server_key.and(&ct_1, &ct_2);
//! let ct_5 = server_key.nand(&ct_3, &ct_4);
//! let ct_6 = server_key.mux(&ct_5, &ct_3, &ct_4);
//!
//! // We use the client key to decrypt the output of the circuit:
//! let output_1 = client_key.decrypt(&ct_6);
//! assert_eq!(output_1, true);
//!
//! // It is possible to compute gates with one input unencrypted
//! let ct_7 = server_key.and(&ct_6, true);
//! let output_2 = client_key.decrypt(&ct_7);
//! assert_eq!(output_2, true);
//!
//! // It is possible to trivially encrypt on the server side
//! // i.e. to not encrypt but still generate a compatible Ciphertext
//! let ct_8 = server_key.trivial_encrypt(false);
//! let ct_9 = server_key.mux(&ct_7, &ct_3, &ct_8);
//! let output_3 = client_key.decrypt(&ct_9);
//! assert_eq!(output_3, true);
//! # }
//!
//! # #[cfg(feature = "cuda")]
//! # fn main() {}
//! ```

use crate::client_key::ClientKey;
use crate::parameters::DEFAULT_PARAMETERS;
use crate::server_key::ServerKey;
#[cfg(test)]
use rand::Rng;

pub mod ciphertext;
pub mod client_key;
pub mod engine;
pub mod parameters;
pub mod prelude;
pub mod server_key;

/// The scaling factor used for the plaintext
pub(crate) const PLAINTEXT_LOG_SCALING_FACTOR: usize = 3;

/// The plaintext associated with true: 1/8
pub(crate) const PLAINTEXT_TRUE: u32 = 1 << (32 - PLAINTEXT_LOG_SCALING_FACTOR);

/// The plaintext associated with false: -1/8
pub(crate) const PLAINTEXT_FALSE: u32 = 7 << (32 - PLAINTEXT_LOG_SCALING_FACTOR);

/// tool to generate random booleans
#[cfg(test)]
pub(crate) fn random_boolean() -> bool {
    // create a random generator
    let mut rng = rand::thread_rng();

    // generate a random bit
    let n: u32 = (rng.gen::<u32>()) % 2;

    // convert it to boolean and return
    n != 0
}

/// tool to generate random integers
#[cfg(test)]
pub(crate) fn random_integer() -> u32 {
    // create a random generator
    let mut rng = rand::thread_rng();

    // generate a random u32
    rng.gen::<u32>()
}

/// Generate a couple of client and server keys with the default cryptographic parameters:
/// `DEFAULT_PARAMETERS`.
/// The client is the one generating both keys.
/// * the client key is used to encrypt and decrypt and has to be kept secret;
/// * the server key is used to perform homomorphic operations on the server side and it is
/// meant to be published (the client sends it to the server).
///
/// ```rust
/// # #[cfg(not(feature = "cuda"))]
/// # fn main() {
/// use concrete_boolean::gen_keys;
/// use concrete_boolean::prelude::*;
/// // generate the client key and the server key:
/// let (cks, sks) = gen_keys();
/// # }
/// # #[cfg(feature = "cuda")]
/// # fn main() {}
/// ```
pub fn gen_keys() -> (ClientKey, ServerKey) {
    // generate the client key
    let cks = ClientKey::new(&DEFAULT_PARAMETERS);

    // generate the server key
    let sks = ServerKey::new(&cks);

    // return
    (cks, sks)
}