cretrit/cipher.rs
1//! Where the `Cipher` lives.
2//!
3
4use core::fmt::Debug;
5use rand::{Rng, SeedableRng};
6use std::cell::RefCell;
7use std::marker::PhantomData;
8
9use crate::ciphersuite::CipherSuite;
10use crate::ciphertext::CipherText;
11use crate::cmp::Comparator;
12use crate::kbkdf::{KBKDFInit, KBKDF};
13use crate::plaintext::PlainText;
14use crate::prf::{PseudoRandomFunction, PseudoRandomFunctionInit};
15use crate::prp::{PseudoRandomPermutation, PseudoRandomPermutationInit};
16use crate::Error;
17
18/// Something capable of turning [`PlainText`s](crate::PlainText) into comparable
19/// [`CipherText`s](crate::CipherText) by means of encryption.
20///
21/// A Cipher consists of a key, a ciphersuite (which is, itself, a whole bunch of possibilities
22/// jammed into one neat little package), a comparator (which defines how ciphertexts can be
23/// compared while encrypted), as well as parameters for the number of blocks (`N`), the "width" of
24/// each block (the total number of values that each block can represent, `W`), and the number of
25/// values that the comparator is able to use to represent comparison values (`M`).
26///
27/// Since all of this is a heck of a lot to have to specify everytime you want to encrypt
28/// something, it's not recommended that you try and use this type directly. Instead, use the
29/// Cipher types provided by the comparison-specific modules defined by each available
30/// ciphersuites. At the moment, those are:
31///
32/// * [`aes128v1`](crate::aes128v1) -- ciphersuite using AES128 as the primary cryptographic
33/// primitive, which provides
34/// * [`ere::Cipher`](crate::aes128v1::ere::Cipher) for equality comparisons (`==`, `!=`), and
35/// * [`ore::Cipher`](crate::aes128v1::ore::Cipher) for ordering comparisons (`<`, `>`, `<=`,
36/// `>=`, `==`, `!=`).
37///
38///
39/// These more-contrained Cipher types only require you to specify the block count and width (`N`
40/// and `W`) and the key to use for encryption, which is far more tractable.
41///
42#[derive(Clone)]
43pub struct Cipher<
44 S: CipherSuite<W, M>,
45 CMP: Comparator<M>,
46 const N: usize,
47 const W: u16,
48 const M: u8,
49> {
50 /// The CSPRNG we're using for our random numbers
51 rng: RefCell<S::RNG>,
52
53 /// The instance of the PRF in use
54 prf: S::PRF,
55
56 /// The instance of the PRP in use
57 prp: S::PRP,
58
59 /// Bumf to keep the compiler happy
60 _ffs: PhantomData<CMP>,
61}
62
63impl<S: CipherSuite<W, M>, CMP: Comparator<M>, const N: usize, const W: u16, const M: u8> Debug
64 for Cipher<S, CMP, N, W, M>
65{
66 fn fmt(&self, _: &mut core::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
67 Ok(())
68 }
69}
70
71impl<S: CipherSuite<W, M>, CMP: Comparator<M>, const N: usize, const W: u16, const M: u8>
72 Cipher<S, CMP, N, W, M>
73{
74 /// Create a new Cipher.
75 ///
76 /// All ciphertexts produced with the same key (and all other parameters) can be compared
77 /// against each other. As such, it is just as important that the key used for these
78 /// encryptions is as secure and secret as any other cryptographic key.
79 ///
80 /// # Errors
81 ///
82 /// Can return an error if any of the underlying cryptographic operations can't complete, or if
83 /// there's a bug somewhere.
84 ///
85 pub fn new(key: &[u8; 32]) -> Result<Self, Error>
86 where
87 <S as CipherSuite<W, M>>::PRF: PseudoRandomFunctionInit,
88 <S as CipherSuite<W, M>>::PRP: PseudoRandomPermutationInit<W>,
89 <S as CipherSuite<W, M>>::KBKDF: 'static,
90 {
91 #![allow(clippy::similar_names)] // I think we can keep things clear in here, prf/prp is totes different
92 let kbkdf: Box<dyn KBKDF> = S::KBKDF::new(key)
93 .map_err(|e| Error::KeyError(format!("failed to create KBKDF instance: {e}")))?;
94
95 let prf: S::PRF = PseudoRandomFunctionInit::new(&*kbkdf)?;
96 let prp: S::PRP = PseudoRandomPermutationInit::new(&*kbkdf)?;
97 let rng: S::RNG = SeedableRng::from_entropy();
98
99 Ok(Cipher {
100 rng: RefCell::new(rng),
101 prf,
102 prp,
103 _ffs: PhantomData,
104 })
105 }
106
107 /// Encrypt a value and produce a ciphertext that contains both "left" and "right" parts
108 ///
109 /// For details on ciphertexts and their components, see the struct-level documentation for
110 /// [`CipherText`](crate::CipherText).
111 ///
112 /// # Errors
113 ///
114 /// Can return an error if any of the underlying cryptographic operations can't complete, or if
115 /// there's a bug somewhere.
116 ///
117 pub fn full_encrypt(
118 &self,
119 value: &PlainText<N, W>,
120 ) -> Result<CipherText<S, CMP, N, W, M>, Error> {
121 CipherText::<S, CMP, N, W, M>::new(self, value)
122 }
123
124 /// Encrypt a value and produce a ciphertext that contains only a "right" part
125 ///
126 /// For details on ciphertexts and their components, see the struct-level documentation for
127 /// [`CipherText`](crate::CipherText).
128 ///
129 /// # Errors
130 ///
131 /// Can return an error if any of the underlying cryptographic operations can't complete, or if
132 /// there's a bug somewhere.
133 ///
134 pub fn right_encrypt(
135 &self,
136 value: &PlainText<N, W>,
137 ) -> Result<CipherText<S, CMP, N, W, M>, Error> {
138 CipherText::<S, CMP, N, W, M>::new_right(self, value)
139 }
140
141 /// Write a random value into the given slice
142 ///
143 /// # Errors
144 ///
145 /// Can return an error if any of the underlying cryptographic operations can't complete, or if
146 /// there's a bug somewhere.
147 ///
148 pub(crate) fn fill_nonce(&self, nonce: &mut [u8]) -> Result<(), Error> {
149 self.rng
150 .borrow_mut()
151 .try_fill(nonce)
152 .map_err(|e| Error::CryptoError(format!("RNG failed to fill random bytes ({e})")))?;
153
154 Ok(())
155 }
156
157 /// Calculate the pseudo-random block corresponding to the given value
158 ///
159 /// Writes the result into the given block, rather than return by value, because the data can
160 /// be of non-trivial size, and the caller has already allocated the space anyway.
161 ///
162 pub(crate) fn pseudorandomise(
163 &self,
164 value: u16,
165 block: &mut <<S as CipherSuite<W, M>>::PRF as PseudoRandomFunction>::BlockType,
166 ) {
167 self.prf.randomise(value, block);
168 }
169
170 /// Return the value->permutation mapping for the given value
171 ///
172 /// # Errors
173 ///
174 /// Can return an error if any of the underlying cryptographic operations can't complete, or if
175 /// there's a bug somewhere.
176 ///
177 pub(crate) fn permuted_value(&self, value: u16) -> Result<u16, Error> {
178 if value >= W {
179 return Err(Error::RangeError(format!(
180 "permuted_value received value={value} greater than block width W={W}"
181 )));
182 }
183 self.prp.value(value)
184 }
185
186 /// Return the permutation->value mapping
187 ///
188 /// # Errors
189 ///
190 /// Can return an error if any of the underlying cryptographic operations can't complete, or if
191 /// there's a bug somewhere.
192 ///
193 pub(crate) fn inverse_permuted_value(&self, permutation: u16) -> Result<u16, Error> {
194 if permutation >= W {
195 return Err(Error::RangeError(format!("inverse_permuted_value received permutation={permutation} greater than block width W={W}")));
196 }
197 self.prp.inverse(permutation)
198 }
199}