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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
use crate::randomness::GeneralRng;
use crate::randomness::SecureRng;
use crate::security::BitsOfSecurity;
use std::fmt::Debug;

/// An asymmetric cryptosystem is a system of methods to encrypt plaintexts into ciphertexts, and
/// decrypt those ciphertexts back into plaintexts. Anyone who has access to the public key can
/// perform encryptions, but only those with the secret key can decrypt.
///
/// The struct that implements an `AsymmetricCryptosystem` will hold the general parameters of that
/// cryptosystem. Depending on the cryptosystem, those parameters could play an important role in
/// deciding the level of security. As such, each cryptosystem should clearly indicate these.
pub trait AsymmetricCryptosystem {
    /// The public key, used for encrypting plaintexts.
    type PublicKey: EncryptionKey;
    /// The secret key, used for decrypting ciphertexts.
    type SecretKey: DecryptionKey<Self::PublicKey>;

    /// Sets up an instance of this cryptosystem with parameters satisfying the security parameter.
    fn setup(security_parameter: &BitsOfSecurity) -> Self;

    /// Generate a public and private key pair using a cryptographic RNG. The level of security is
    /// determined by the computational `security_parameter`.
    fn generate_keys<R: SecureRng>(
        &self,
        rng: &mut GeneralRng<R>,
    ) -> (Self::PublicKey, Self::SecretKey);
}

/// The encryption key.
pub trait EncryptionKey: Sized + Debug + PartialEq {
    /// Input is the type used to multiply additive ciphertexts or exponentiate multiplicative ciphertexts.
    type Input;

    /// The type of the plaintext to be encrypted.
    type Plaintext;

    /// The type of an encrypted plaintext, i.e. a ciphertext.
    type Ciphertext: Associable<Self>;

    /// The type of the randomness used.
    type Randomness;

    /// Encrypt the plaintext using the public key and a cryptographic RNG and immediately associate it with the public key.
    fn encrypt<'pk, R: SecureRng>(
        &'pk self,
        plaintext: &Self::Plaintext,
        rng: &mut GeneralRng<R>,
    ) -> AssociatedCiphertext<'pk, Self::Ciphertext, Self> {
        self.encrypt_raw(plaintext, rng).associate(self)
    }

    /// Encrypt the plaintext using the public key and a cryptographic RNG.
    fn encrypt_raw<R: SecureRng>(
        &self,
        plaintext: &Self::Plaintext,
        rng: &mut GeneralRng<R>,
    ) -> Self::Ciphertext {
        let message = self.encrypt_without_randomness(plaintext);

        self.randomize(message, rng)
    }

    /// **WARNING: This is not a full encryption. The resulting ciphertext is completely insecure.** 'Encrypts' the plaintext using the public key deterministically, essentially creating a trivial ciphertext. The encryption is not secure until you call `randomize` or `randomize_with` with suitable randomness.
    fn encrypt_without_randomness(&self, plaintext: &Self::Plaintext) -> Self::Ciphertext;

    /// Randomizes the ciphertext with the supplied rng.
    fn randomize<R: SecureRng>(
        &self,
        ciphertext: Self::Ciphertext,
        rng: &mut GeneralRng<R>,
    ) -> Self::Ciphertext;

    /// Randomizes the ciphertext with the user supplied randomness.
    fn randomize_with(
        &self,
        ciphertext: Self::Ciphertext,
        randomness: &Self::Randomness,
    ) -> Self::Ciphertext;
}

/// The decryption key.
pub trait DecryptionKey<PK: EncryptionKey> {
    /// Decrypt the associated ciphertext using the secret key.
    fn decrypt<'pk>(
        &self,
        ciphertext: &AssociatedCiphertext<'pk, PK::Ciphertext, PK>,
    ) -> PK::Plaintext {
        self.decrypt_raw(ciphertext.public_key, &ciphertext.ciphertext)
    }

    /// Returns true if the associated ciphertext encrypts the identity. This is typically faster than a full decryption.
    fn decrypt_identity<'pk>(
        &self,
        ciphertext: &AssociatedCiphertext<'pk, PK::Ciphertext, PK>,
    ) -> bool {
        self.decrypt_identity_raw(ciphertext.public_key, &ciphertext.ciphertext)
    }

    /// Decrypt the ciphertext using the secret key and its related public key.
    fn decrypt_raw(&self, public_key: &PK, ciphertext: &PK::Ciphertext) -> PK::Plaintext;

    /// Returns true if the encrypted value equals the identity. This is typically faster than a full decryption.
    fn decrypt_identity_raw(&self, public_key: &PK, ciphertext: &PK::Ciphertext) -> bool;
}

#[derive(PartialEq, Eq, Debug)]
/// An AssociatedCiphertext associates a ciphertext with a reference to the corresponding public key to make homomorphic operations and decrypting more ergonomic.
pub struct AssociatedCiphertext<'pk, C: Associable<PK>, PK: EncryptionKey<Ciphertext = C>> {
    /// A potentially homomorphic ciphertext
    pub ciphertext: C,
    /// The related public key
    pub public_key: &'pk PK,
}

/// Functionality to easily turn a ciphertext into an associated ciphertext
pub trait Associable<PK: EncryptionKey<Ciphertext = Self>>: Sized {
    /// 'Enriches' a ciphertext by associating it with a corresponding public key. This allows to overlead operators for homomorphic operations.
    fn associate(self, public_key: &PK) -> AssociatedCiphertext<'_, Self, PK> {
        AssociatedCiphertext {
            ciphertext: self,
            public_key,
        }
    }
}

/// The Verification key.
pub trait VerificationKey {
    /// The type of the plaintext to be signed.
    type Plaintext;

    /// The type of a signature.
    type Signature;

    /// Verify the Signature on the plaintext message using the (public) Verification key.
    fn verify(&self, signature: &Self::Signature, plaintext: &Self::Plaintext) -> bool;
}

/// The Signing key.
pub trait SigningKey<VK: VerificationKey> {
    /// Sign the plaintext message using the (secret) Signing key.
    fn sign<R: SecureRng>(
        &self,
        plaintext: &VK::Plaintext,
        public_key: &VK,
        rng: &mut GeneralRng<R>,
    ) -> VK::Signature;
}