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;