crypt: Switch to using large unsigned integers
- The crate now uses crypto_bigint U128 ints instead of i32. - OsRng instead of thread_rng(), (cryptographically more secure?). - Modular arithmetic methods from crypto_bigint, no more overflows. - Error code for invalid parameters. - Simpler naming.
This commit is contained in:
parent
b10874e5d6
commit
7ad15fce76
|
@ -1 +1,2 @@
|
||||||
/target
|
/target
|
||||||
|
Cargo.lock
|
||||||
|
|
|
@ -1,109 +0,0 @@
|
||||||
# This file is automatically @generated by Cargo.
|
|
||||||
# It is not intended for manual editing.
|
|
||||||
version = 3
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "autocfg"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "cfg-if"
|
|
||||||
version = "1.0.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "false-bottom"
|
|
||||||
version = "0.1.0"
|
|
||||||
dependencies = [
|
|
||||||
"modinverse",
|
|
||||||
"rand",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "getrandom"
|
|
||||||
version = "0.2.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"libc",
|
|
||||||
"wasi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "libc"
|
|
||||||
version = "0.2.153"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "modinverse"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "2f62f577f148cc1a9466e7065a22e59466a7d537cceba5e77e57181d0f706633"
|
|
||||||
dependencies = [
|
|
||||||
"num-integer",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-integer"
|
|
||||||
version = "0.1.46"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
|
|
||||||
dependencies = [
|
|
||||||
"num-traits",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "num-traits"
|
|
||||||
version = "0.2.18"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
|
|
||||||
dependencies = [
|
|
||||||
"autocfg",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "ppv-lite86"
|
|
||||||
version = "0.2.17"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand"
|
|
||||||
version = "0.8.5"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"rand_chacha",
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_chacha"
|
|
||||||
version = "0.3.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
|
||||||
dependencies = [
|
|
||||||
"ppv-lite86",
|
|
||||||
"rand_core",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "rand_core"
|
|
||||||
version = "0.6.4"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
|
||||||
dependencies = [
|
|
||||||
"getrandom",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "wasi"
|
|
||||||
version = "0.11.0+wasi-snapshot-preview1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
|
|
@ -6,5 +6,5 @@ edition = "2021"
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rand = "^0.8.5"
|
rand = "0.8.5"
|
||||||
modinverse = "0.1.1"
|
crypto-bigint = "0.5.5"
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum FalseBottomError {
|
pub enum FBError {
|
||||||
IntegerTooLarge,
|
IntegerTooLarge,
|
||||||
NoModInverse,
|
NoModInverse,
|
||||||
InvalidKey,
|
InvalidKey,
|
||||||
|
InvalidParams,
|
||||||
}
|
}
|
||||||
|
|
135
src/lib.rs
135
src/lib.rs
|
@ -1,80 +1,85 @@
|
||||||
pub mod errors;
|
pub mod errors;
|
||||||
|
|
||||||
use rand::Rng;
|
use rand::{Rng, seq::IteratorRandom};
|
||||||
use rand::seq::IteratorRandom;
|
use crate::errors::FBError;
|
||||||
use crate::errors::FalseBottomError;
|
use crypto_bigint::{U128, RandomMod, NonZero, rand_core::OsRng, Limb};
|
||||||
use modinverse::modinverse;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FalseBottom {
|
pub struct FBCrypt {
|
||||||
pub k: i32,
|
k: usize,
|
||||||
pub r: Vec<i32>,
|
r: Vec<U128>,
|
||||||
pub c: Vec<i32>,
|
c: Vec<U128>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FalseBottomKey {
|
pub struct FBKey {
|
||||||
pub key_indices: Vec<i32>,
|
r_i: Vec<usize>,
|
||||||
pub cipher_indices: Vec<i32>,
|
c_i: Vec<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
const P: i32 = 9973;
|
// Prime number value
|
||||||
|
const P: U128 = U128::MAX.wrapping_sub(&U128::from_u32(159 - 1));
|
||||||
|
// Our prime is at 159th position to the left of 2^128
|
||||||
|
const P_POS: Limb = Limb::from_u32(159);
|
||||||
|
|
||||||
impl FalseBottom {
|
impl FBCrypt {
|
||||||
pub fn init(k: i32) -> FalseBottom {
|
|
||||||
let mut rng = rand::thread_rng();
|
pub fn init(n: usize, k: usize) -> Result<FBCrypt, FBError> {
|
||||||
let mut r: Vec<i32> = Vec::new();
|
if n < k || k < 2 {
|
||||||
let mut c: Vec<i32> = Vec::new();
|
return Err(FBError::InvalidParams)
|
||||||
for _ in 0..k {
|
|
||||||
r.push(rng.gen_range(1..k));
|
|
||||||
c.push(rng.gen_range(1..P));
|
|
||||||
}
|
}
|
||||||
FalseBottom {k, r, c}
|
const MODULUS: NonZero<U128> = NonZero::<U128>::const_new(P).0;
|
||||||
|
let r: Vec<U128> = (0..k)
|
||||||
|
.map(|_| U128::random_mod(&mut OsRng, &MODULUS))
|
||||||
|
.collect();
|
||||||
|
let c: Vec<U128> = (0..n)
|
||||||
|
.map(|_| U128::random_mod(&mut OsRng, &MODULUS))
|
||||||
|
.collect();
|
||||||
|
Ok(FBCrypt {k, r, c})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add(&mut self, m: i32) ->
|
pub fn add(&mut self, m: &U128) -> Result<FBKey, FBError> {
|
||||||
Result<FalseBottomKey, FalseBottomError>
|
if m.ge(&P) {
|
||||||
{
|
return Err(FBError::IntegerTooLarge);
|
||||||
if m > P as i32 {
|
|
||||||
return Err(FalseBottomError::IntegerTooLarge)
|
|
||||||
}
|
}
|
||||||
let mut rng = rand::thread_rng();
|
let (r, c) = (&mut self.r, &mut self.c);
|
||||||
let n = rng.gen_range(2..=self.k);
|
let n = OsRng.gen_range(2..=self.k);
|
||||||
|
let mut c_i: Vec<usize> = (0..c.len())
|
||||||
|
.choose_multiple(&mut OsRng, n-1);
|
||||||
|
let r_i: Vec<usize> = (0..self.k)
|
||||||
|
.choose_multiple(&mut OsRng, n);
|
||||||
|
|
||||||
let mut cipher_indices: Vec<i32> = (0..self.c.len() as i32)
|
let mut sum: U128 = U128::ZERO;
|
||||||
.choose_multiple(&mut rng, n as usize - 1);
|
for (&ci, &ri) in c_i.iter()
|
||||||
|
.zip(r_i.iter())
|
||||||
let key_indices: Vec<i32> = (0..self.k)
|
|
||||||
.choose_multiple(&mut rng, n as usize);
|
|
||||||
|
|
||||||
let mut sum = 0;
|
|
||||||
for (j, rho) in cipher_indices.iter()
|
|
||||||
.zip(key_indices.iter())
|
|
||||||
{
|
{
|
||||||
sum += self.c[*j as usize] * self.r[*rho as usize];
|
sum = sum.add_mod(
|
||||||
sum %= P;
|
&c[ci].mul_mod_special(&r[ri], P_POS),
|
||||||
|
&P);
|
||||||
}
|
}
|
||||||
|
let r_last = *r_i.last().unwrap();
|
||||||
let key_last_el = *key_indices.last().unwrap() as usize;
|
let (mod_inv, inv_exists) = r[r_last].inv_mod(&P);
|
||||||
let mod_inv = modinverse(self.r[key_last_el], P)
|
let inv_exists: bool = inv_exists.into();
|
||||||
.ok_or(FalseBottomError::NoModInverse)?;
|
if !inv_exists {
|
||||||
let cipher_new_element = ((m - sum) * mod_inv)
|
return Err(FBError::NoModInverse);
|
||||||
.rem_euclid(P);
|
}
|
||||||
self.c.push(cipher_new_element);
|
let c_new = m.sub_mod(&sum, &P)
|
||||||
cipher_indices.push(self.c.len() as i32 - 1);
|
.mul_mod_special(&mod_inv, P_POS);
|
||||||
Ok(FalseBottomKey {key_indices, cipher_indices})
|
c.push(c_new);
|
||||||
|
c_i.push(c.len()-1);
|
||||||
|
Ok(FBKey {r_i, c_i})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decrypt(&self, indices: &FalseBottomKey) -> Result<i32, FalseBottomError> {
|
pub fn decrypt(&self, indices: &FBKey) -> Result<U128, FBError> {
|
||||||
let keyi = &indices.key_indices;
|
let (r_i, c_i) = (&indices.r_i, &indices.c_i);
|
||||||
let cipheri = &indices.cipher_indices;
|
if r_i.len() > self.r.len() || c_i.len() > self.c.len() {
|
||||||
if keyi.len() > self.r.len() || cipheri.len() > self.c.len() {
|
return Err(FBError::InvalidKey)
|
||||||
return Err(FalseBottomError::InvalidKey)
|
|
||||||
}
|
}
|
||||||
let mut m: i32 = 0;
|
let mut m: U128 = U128::ZERO;
|
||||||
for (ki, ci) in keyi.iter().zip(cipheri.iter()) {
|
for (&ri, &ci) in r_i.iter().zip(c_i.iter()) {
|
||||||
m += self.c[*ci as usize] * self.r[*ki as usize];
|
m = m.add_mod(
|
||||||
m %= P;
|
&self.c[ci].mul_mod_special(&self.r[ri], P_POS),
|
||||||
|
&P);
|
||||||
}
|
}
|
||||||
Ok(m)
|
Ok(m)
|
||||||
}
|
}
|
||||||
|
@ -83,12 +88,20 @@ impl FalseBottom {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn encrypt_decrypt_100() {
|
fn encrypt_decrypt_100() {
|
||||||
let msg = 100;
|
let msg: U128 = U128::from_u32(100);
|
||||||
let mut fb = FalseBottom::init(9);
|
let mut fb = FBCrypt::init(20, 12).unwrap();
|
||||||
let key = fb.add(msg).unwrap();
|
let key = fb.add(&msg).unwrap();
|
||||||
let decrypted = fb.decrypt(&key).unwrap();
|
let decrypted = fb.decrypt(&key).unwrap();
|
||||||
assert_eq!(decrypted, msg);
|
assert_eq!(msg, decrypted);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn many_runs() {
|
||||||
|
for _ in 0..1000 {
|
||||||
|
encrypt_decrypt_100();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue