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 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
//! ore-rs is a library to encrypt numeric types in a way that allows the numeric ordering
//! of the unencrypted values to be "revealed" during a query enabling range queries to be performed
//! on encrypted data.
//!
//! This is an implementation of the BlockORE Encryption scheme developed by
//! [Lewi-Wu in 2016](https://eprint.iacr.org/2016/612.pdf). It is used extensively in the
//! [CipherStash](https://cipherstash.com) searchable encryption platform.
//!
//!
//! # Usage
//! This crate is [on crates.io](https://crates.io/crates/regex) and can be
//! used by adding `ore-rs` to your dependencies in your project's `Cargo.toml`.
//! ```toml
//! [dependencies]
//! ore-rs = "0.1"
//! ```
//!
//! ## Example: Encrypt a number with ORE.
//!
//! To encrypt a number you need to initalize an [`ORECipher`] as well as `use` the [`OREEncrypt`] trait
//! which comes with implementations for `u32` and `u64`.
//!
//! To initalize the Cipher, you must decide on the scheme you want to use. There is only one ORE
//! Scheme right now so that's easy but in the future more schemes will become available.
//!
//! An `ORECipher` also requires 2 keys (16-bytes each) and an 8-byte seed.
//!
//! ```rust
//! use ore_rs::{
//! ORECipher, // Main ORE Cipher trait
//! OREEncrypt, // Traits for encrypting primitive types (e.g. u64)
//! scheme::bit2::OREAES128 // Specific scheme we want to use
//! };
//! use hex_literal::hex;
//!
//! // Initalize an ORE Cipher with the OREAES128 scheme
//! let k1: [u8; 16] = hex!("00010203 04050607 08090a0b 0c0d0e0f");
//! let k2: [u8; 16] = hex!("00010203 04050607 08090a0b 0c0d0e0f");
//! let seed = hex!("00010203 04050607");
//! let mut ore: OREAES128 = ORECipher::init(k1, k2, &seed).unwrap();
//!
//! // Encryption takes a mutable reference to the cipher and returns a `Result`
//! let a = 456u64.encrypt(&mut ore).unwrap();
//! ```
//!
//! *Note that a cipher must be mutable as it manages internal state*.
//!
//!
//! ## Example: Comparing 2 CipherTexts
//!
//! The result of an encryption is called a CipherText and is represented by the type
//! [`CipherText<S, N>`] where `S` is the scheme used and `N` is the number of blocks is the size
//! of the input type (in bytes) divided by 8. (e.g. for `u64` N=8).
//!
//! Comparisons can only be performed between ciphertexts of the same size and underlying scheme.
//!
//! ```rust
//! # use ore_rs::{
//! # CipherText,
//! # ORECipher, // Main ORE Cipher trait
//! # OREEncrypt, // Traits for encrypting primitive types (e.g. u64)
//! # scheme::bit2::OREAES128 // Specific scheme we want to use
//! # };
//! # use hex_literal::hex;
//! # let k1: [u8; 16] = hex!("00010203 04050607 08090a0b 0c0d0e0f");
//! # let k2: [u8; 16] = hex!("00010203 04050607 08090a0b 0c0d0e0f");
//! # let seed = hex!("00010203 04050607");
//! # let mut ore: OREAES128 = ORECipher::init(k1, k2, &seed).unwrap();
//! let a = 456u64.encrypt(&mut ore).unwrap();
//! let b = 1024u64.encrypt(&mut ore).unwrap();
//!
//! // This is fine
//! let result = a > b; // false because 456 < 1024
//! ```
//!
//! ```compile_fail
//! # use ore_rs::{
//! # CipherText,
//! # ORECipher, // Main ORE Cipher trait
//! # OREEncrypt, // Traits for encrypting primitive types (e.g. u64)
//! # scheme::bit2::OREAES128 // Specific scheme we want to use
//! # };
//! # use hex_literal::hex;
//! # let k1: [u8; 16] = hex!("00010203 04050607 08090a0b 0c0d0e0f");
//! # let k2: [u8; 16] = hex!("00010203 04050607 08090a0b 0c0d0e0f");
//! # let seed = hex!("00010203 04050607");
//! # let mut ore: OREAES128 = ORECipher::init(k1, k2, &seed).unwrap();
//! // This isn't
//! let a = 456u64.encrypt(&mut ore).unwrap();
//! let b = 1024u32.encrypt(&mut ore).unwrap(); // note the u32
//!
//! let result = a > b; // compilation error
//! ```
//!
//! ## Serializing/Deserializing
//!
//! *Note: this library doesn't use [Serde](https://crates.io/crates/serde) due to some complexities
//! with GenericArray used in the [AES](https://crates.io/crates/aes) library. This may change in the future.*
//!
//! To serialize a [`CipherText<S, N>`] to a vector of bytes:
//!
//! ```rust
//! # use ore_rs::{
//! # CipherText,
//! # ORECipher, // Main ORE Cipher trait
//! # OREEncrypt, // Traits for encrypting primitive types (e.g. u64)
//! # scheme::bit2::OREAES128 // Specific scheme we want to use
//! # };
//! # use hex_literal::hex;
//! # let k1: [u8; 16] = hex!("00010203 04050607 08090a0b 0c0d0e0f");
//! # let k2: [u8; 16] = hex!("00010203 04050607 08090a0b 0c0d0e0f");
//! # let seed = hex!("00010203 04050607");
//! # let mut ore: OREAES128 = ORECipher::init(k1, k2, &seed).unwrap();
//! let a = 456u64.encrypt(&mut ore).unwrap();
//! let bytes: Vec<u8> = a.to_bytes();
//! ```
//!
//! To deserialize, you must specify the CipherText type (including number of blocks) you
//! are deserializing into:
//!
//! ```rust
//! # use ore_rs::{
//! # CipherText,
//! # ORECipher, // Main ORE Cipher trait
//! # OREEncrypt, // Traits for encrypting primitive types (e.g. u64)
//! # scheme::bit2::OREAES128 // Specific scheme we want to use
//! # };
//! # use hex_literal::hex;
//! # let k1: [u8; 16] = hex!("00010203 04050607 08090a0b 0c0d0e0f");
//! # let k2: [u8; 16] = hex!("00010203 04050607 08090a0b 0c0d0e0f");
//! # let seed = hex!("00010203 04050607");
//! # let mut ore: OREAES128 = ORECipher::init(k1, k2, &seed).unwrap();
//! # let a = 456u64.encrypt(&mut ore).unwrap();
//! # let bytes: Vec<u8> = a.to_bytes();
//!
//! let ct = CipherText::<OREAES128, 8>::from_bytes(&bytes).unwrap();
//! # assert!(ct == a);
//! ```
mod encrypt;
mod ciphertext;
mod primitives;
pub mod scheme;
pub use crate::encrypt::OREEncrypt;
pub use crate::ciphertext::*;
use crate::primitives::SEED64;
pub type PlainText<const N: usize> = [u8; N];
#[derive(Debug, Clone)]
pub struct OREError;
pub trait ORECipher: Sized {
type LeftBlockType;
type RightBlockType;
fn init(k1: [u8; 16], k2: [u8; 16], seed: &SEED64) -> Result<Self, OREError>;
fn encrypt_left<const N: usize>(
&mut self, input: &PlainText<N>
) -> Result<Left<Self, N>, OREError>
where <Self as ORECipher>::LeftBlockType: CipherTextBlock;
fn encrypt<const N: usize>(
&mut self, input: &PlainText<N>
) -> Result<CipherText<Self, N>, OREError>
where <Self as ORECipher>::RightBlockType: CipherTextBlock,
<Self as ORECipher>::LeftBlockType: ciphertext::CipherTextBlock;
}
#[cfg(test)]
#[macro_use]
extern crate quickcheck;