ore_rs/lib.rs
1//! ore-rs is a library to encrypt numeric types in a way that allows the numeric ordering
2//! of the unencrypted values to be "revealed" during a query enabling range queries to be performed
3//! on encrypted data.
4//!
5//! This is an implementation of the BlockORE Encryption scheme developed by
6//! [Lewi-Wu in 2016](https://eprint.iacr.org/2016/612.pdf). It is used extensively in the
7//! [CipherStash](https://cipherstash.com) searchable encryption platform.
8//!
9//!
10//! # Usage
11//! This crate is [on crates.io](https://crates.io/crates/ore-rs) and can be
12//! used by adding `ore-rs` to your dependencies in your project's `Cargo.toml`.
13//! ```toml
14//! [dependencies]
15//! ore-rs = "0.1"
16//! ```
17//!
18//! ## Example: Encrypt a number with ORE.
19//!
20//! To encrypt a number you need to initalize an [`OreCipher`] as well as `use` the [`OreEncrypt`] trait
21//! which comes with implementations for `u32` and `u64`.
22//!
23//! To initalize the Cipher, you must decide on the scheme you want to use. There is only one ORE
24//! Scheme right now so that's easy but in the future more schemes will become available.
25//!
26//! An `OreCipher` also requires 2 keys (16-bytes each) and an 8-byte seed.
27//!
28//! ```rust
29//! use ore_rs::{
30//! OreCipher, // Main ORE Cipher trait
31//! OreEncrypt, // Traits for encrypting primitive types (e.g. u64)
32//! scheme::bit2::OreAes128ChaCha20 // Specific scheme we want to use
33//! };
34//! use hex_literal::hex;
35//!
36//! // Initalize an ORE Cipher with the OreAes128ChaCha20 scheme
37//! let k1: [u8; 16] = hex!("00010203 04050607 08090a0b 0c0d0e0f");
38//! let k2: [u8; 16] = hex!("00010203 04050607 08090a0b 0c0d0e0f");
39//! let ore: OreAes128ChaCha20 = OreCipher::init(&k1, &k2).unwrap();
40//!
41//! // Encryption takes a mutable reference to the cipher and returns a `Result`
42//! let a = 456u64.encrypt(&ore).unwrap();
43//! ```
44//!
45//! *Note that a cipher must be mutable as it manages internal state*.
46//!
47//!
48//! ## Example: Comparing 2 CipherTexts
49//!
50//! The result of an encryption is called a CipherText and is represented by the type
51//! [`CipherText<S, N>`] where `S` is the scheme used and `N` is the number of blocks is the size
52//! of the input type (in bytes) divided by 8. (e.g. for `u64` N=8).
53//!
54//! Comparisons can only be performed between ciphertexts of the same size and underlying scheme.
55//!
56//! ```rust
57//! # use ore_rs::{
58//! # CipherText,
59//! # OreCipher, // Main ORE Cipher trait
60//! # OreEncrypt, // Traits for encrypting primitive types (e.g. u64)
61//! # scheme::bit2::OreAes128ChaCha20 // Specific scheme we want to use
62//! # };
63//! # use hex_literal::hex;
64//! # let k1: [u8; 16] = hex!("00010203 04050607 08090a0b 0c0d0e0f");
65//! # let k2: [u8; 16] = hex!("00010203 04050607 08090a0b 0c0d0e0f");
66//! # let ore: OreAes128ChaCha20 = OreCipher::init(&k1, &k2).unwrap();
67//! let a = 456u64.encrypt(&ore).unwrap();
68//! let b = 1024u64.encrypt(&ore).unwrap();
69//!
70//! // This is fine
71//! let result = a > b; // false because 456 < 1024
72//! ```
73//!
74//! ```compile_fail
75//! # use ore_rs::{
76//! # CipherText,
77//! # OreCipher, // Main ORE Cipher trait
78//! # OreEncrypt, // Traits for encrypting primitive types (e.g. u64)
79//! # scheme::bit2::OreAes128ChaCha20 // Specific scheme we want to use
80//! # };
81//! # use hex_literal::hex;
82//! # let k1: [u8; 16] = hex!("00010203 04050607 08090a0b 0c0d0e0f");
83//! # let k2: [u8; 16] = hex!("00010203 04050607 08090a0b 0c0d0e0f");
84//! # let ore: OreAes128ChaCha20 = OreCipher::init(&k1, &k2).unwrap();
85//! // This isn't
86//! let a = 456u64.encrypt(&ore).unwrap();
87//! let b = 1024u32.encrypt(&ore).unwrap(); // note the u32
88//!
89//! let result = a > b; // compilation error
90//! ```
91//!
92//! ## Serializing/Deserializing
93//!
94//! *Note: this library doesn't use [Serde](https://crates.io/crates/serde) due to some complexities
95//! with GenericArray used in the [AES](https://crates.io/crates/aes) library. This may change in the future.*
96//!
97//! To serialize a [`CipherText<S, N>`] to a vector of bytes:
98//!
99//! ```rust
100//! # use ore_rs::{
101//! # CipherText,
102//! # OreCipher, // Main ORE Cipher trait
103//! # OreEncrypt, // Traits for encrypting primitive types (e.g. u64)
104//! # OreOutput,
105//! # scheme::bit2::OreAes128ChaCha20 // Specific scheme we want to use
106//! # };
107//! # use hex_literal::hex;
108//! # let k1: [u8; 16] = hex!("00010203 04050607 08090a0b 0c0d0e0f");
109//! # let k2: [u8; 16] = hex!("00010203 04050607 08090a0b 0c0d0e0f");
110//! # let ore: OreAes128ChaCha20 = OreCipher::init(&k1, &k2).unwrap();
111//! let a = 456u64.encrypt(&ore).unwrap();
112//! let bytes: Vec<u8> = a.to_bytes();
113//! ```
114//!
115//! To deserialize, you must specify the CipherText type (including number of blocks) you
116//! are deserializing into:
117//!
118//! ```rust
119//! # use ore_rs::{
120//! # CipherText,
121//! # OreCipher, // Main ORE Cipher trait
122//! # OreEncrypt, // Traits for encrypting primitive types (e.g. u64)
123//! # OreOutput,
124//! # scheme::bit2::OreAes128ChaCha20 // Specific scheme we want to use
125//! # };
126//! # use hex_literal::hex;
127//! # let k1: [u8; 16] = hex!("00010203 04050607 08090a0b 0c0d0e0f");
128//! # let k2: [u8; 16] = hex!("00010203 04050607 08090a0b 0c0d0e0f");
129//! # let ore: OreAes128ChaCha20 = OreCipher::init(&k1, &k2).unwrap();
130//! # let a = 456u64.encrypt(&ore).unwrap();
131//! # let bytes: Vec<u8> = a.to_bytes();
132//!
133//! let ct = CipherText::<OreAes128ChaCha20, 8>::from_bytes(&bytes).unwrap();
134//! # assert!(ct == a);
135//! ```
136
137mod ciphertext;
138mod convert;
139mod encrypt;
140mod primitives;
141pub mod scheme;
142pub use crate::ciphertext::*;
143pub use crate::encrypt::OreEncrypt;
144use primitives::PrpError;
145use std::cmp::Ordering;
146use thiserror::Error;
147
148pub type PlainText<const N: usize> = [u8; N];
149
150#[derive(Debug, Error)]
151pub enum OreError {
152 #[error("Failed to initialize cipher")]
153 InitFailed,
154 #[error(transparent)]
155 PrpError(#[from] PrpError),
156 #[error("Randomness Error")]
157 RandError(#[from] rand::Error),
158}
159
160pub trait OreCipher: Sized {
161 type LeftBlockType: CipherTextBlock;
162 type RightBlockType: CipherTextBlock;
163
164 fn init(k1: &[u8; 16], k2: &[u8; 16]) -> Result<Self, OreError>;
165
166 fn encrypt_left<const N: usize>(&self, input: &PlainText<N>)
167 -> Result<Left<Self, N>, OreError>;
168
169 fn encrypt<const N: usize>(
170 &self,
171 input: &PlainText<N>,
172 ) -> Result<CipherText<Self, N>, OreError>;
173
174 fn compare_raw_slices(a: &[u8], b: &[u8]) -> Option<Ordering>;
175}
176
177#[cfg(test)]
178#[macro_use]
179extern crate quickcheck;