mirror of
https://github.com/zama-ai/tfhe-rs.git
synced 2026-01-08 22:28:01 -05:00
feat(apps): add Trivium application of TFHE
This commit is contained in:
committed by
Thibault Balenbois
parent
7426e441ba
commit
5f635e97fa
@@ -1,6 +1,6 @@
|
||||
[workspace]
|
||||
resolver = "2"
|
||||
members = ["tfhe", "tasks"]
|
||||
members = ["tfhe", "tasks", "apps/trivium"]
|
||||
|
||||
[profile.bench]
|
||||
lto = "fat"
|
||||
|
||||
12
Makefile
12
Makefile
@@ -313,6 +313,18 @@ test_sha256_bool: install_rs_build_toolchain
|
||||
.PHONY: test_examples # Run tests for examples
|
||||
test_examples: test_sha256_bool test_regex_engine
|
||||
|
||||
.PHONY: test_trivium # Run tests for trivium
|
||||
test_trivium: install_rs_build_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
|
||||
trivium --features=$(TARGET_ARCH_FEATURE),boolean,shortint,integer \
|
||||
-- --test-threads=1
|
||||
|
||||
.PHONY: test_kreyvium # Run tests for kreyvium
|
||||
test_kreyvium: install_rs_build_toolchain
|
||||
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \
|
||||
kreyvium --features=$(TARGET_ARCH_FEATURE),boolean,shortint,integer \
|
||||
-- --test-threads=1
|
||||
|
||||
.PHONY: doc # Build rust doc
|
||||
doc: install_rs_check_toolchain
|
||||
RUSTDOCFLAGS="--html-in-header katex-header.html -Dwarnings" \
|
||||
|
||||
24
apps/trivium/Cargo.toml
Normal file
24
apps/trivium/Cargo.toml
Normal file
@@ -0,0 +1,24 @@
|
||||
[package]
|
||||
name = "tfhe-trivium"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
rayon = { version = "1.7.0"}
|
||||
|
||||
[target.'cfg(target_arch = "x86_64")'.dependencies.tfhe]
|
||||
path = "../../tfhe"
|
||||
features = [ "boolean", "shortint", "integer", "x86_64" ]
|
||||
|
||||
[target.'cfg(target_arch = "aarch64")'.dependencies.tfhe]
|
||||
path = "../../tfhe"
|
||||
features = [ "boolean", "shortint", "integer", "aarch64-unix" ]
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = { version = "0.4", features = [ "html_reports" ]}
|
||||
|
||||
[[bench]]
|
||||
name = "trivium"
|
||||
harness = false
|
||||
204
apps/trivium/README.md
Normal file
204
apps/trivium/README.md
Normal file
@@ -0,0 +1,204 @@
|
||||
# FHE boolean Trivium implementation using TFHE-rs
|
||||
|
||||
The cleartext boolean Trivium is available to be built using the function `TriviumStream::<bool>::new`.
|
||||
This takes as input 2 arrays of 80 bool: the Trivium key and the IV. After initialization, it returns a TriviumStream on
|
||||
which the user can call `next`, getting the next bit of the cipher stream, or `next_64`, which will compute 64 values at once,
|
||||
using multithreading to accelerate the computation.
|
||||
|
||||
|
||||
Quite similarly, the function `TriviumStream::<FheBool>::new` will return a very similar object running in FHE space. Its arguments are
|
||||
2 arrays of 80 FheBool representing the encrypted Trivium key, and the encrypted IV. It also requires a reference to the the server key of the
|
||||
current scheme. This means that any user of this feature must also have the `tfhe-rs` crate as a dependency.
|
||||
|
||||
|
||||
Example of a Rust main below:
|
||||
```rust
|
||||
use tfhe::{ConfigBuilder, generate_keys, FheBool};
|
||||
use tfhe::prelude::*;
|
||||
|
||||
use tfhe_trivium::TriviumStream;
|
||||
|
||||
fn get_hexadecimal_string_from_lsb_first_stream(a: Vec<bool>) -> String {
|
||||
assert!(a.len() % 8 == 0);
|
||||
let mut hexadecimal: String = "".to_string();
|
||||
for test in a.chunks(8) {
|
||||
// Encoding is bytes in LSB order
|
||||
match test[4..8] {
|
||||
[false, false, false, false] => hexadecimal.push('0'),
|
||||
[true, false, false, false] => hexadecimal.push('1'),
|
||||
[false, true, false, false] => hexadecimal.push('2'),
|
||||
[true, true, false, false] => hexadecimal.push('3'),
|
||||
|
||||
[false, false, true, false] => hexadecimal.push('4'),
|
||||
[true, false, true, false] => hexadecimal.push('5'),
|
||||
[false, true, true, false] => hexadecimal.push('6'),
|
||||
[true, true, true, false] => hexadecimal.push('7'),
|
||||
|
||||
[false, false, false, true] => hexadecimal.push('8'),
|
||||
[true, false, false, true] => hexadecimal.push('9'),
|
||||
[false, true, false, true] => hexadecimal.push('A'),
|
||||
[true, true, false, true] => hexadecimal.push('B'),
|
||||
|
||||
[false, false, true, true] => hexadecimal.push('C'),
|
||||
[true, false, true, true] => hexadecimal.push('D'),
|
||||
[false, true, true, true] => hexadecimal.push('E'),
|
||||
[true, true, true, true] => hexadecimal.push('F'),
|
||||
_ => ()
|
||||
};
|
||||
match test[0..4] {
|
||||
[false, false, false, false] => hexadecimal.push('0'),
|
||||
[true, false, false, false] => hexadecimal.push('1'),
|
||||
[false, true, false, false] => hexadecimal.push('2'),
|
||||
[true, true, false, false] => hexadecimal.push('3'),
|
||||
|
||||
[false, false, true, false] => hexadecimal.push('4'),
|
||||
[true, false, true, false] => hexadecimal.push('5'),
|
||||
[false, true, true, false] => hexadecimal.push('6'),
|
||||
[true, true, true, false] => hexadecimal.push('7'),
|
||||
|
||||
[false, false, false, true] => hexadecimal.push('8'),
|
||||
[true, false, false, true] => hexadecimal.push('9'),
|
||||
[false, true, false, true] => hexadecimal.push('A'),
|
||||
[true, true, false, true] => hexadecimal.push('B'),
|
||||
|
||||
[false, false, true, true] => hexadecimal.push('C'),
|
||||
[true, false, true, true] => hexadecimal.push('D'),
|
||||
[false, true, true, true] => hexadecimal.push('E'),
|
||||
[true, true, true, true] => hexadecimal.push('F'),
|
||||
_ => ()
|
||||
};
|
||||
}
|
||||
return hexadecimal;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let config = ConfigBuilder::all_disabled().enable_default_bool().build();
|
||||
let (client_key, server_key) = generate_keys(config);
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB".to_string();
|
||||
let mut key = [false; 80];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
let mut val: u8 = u8::from_str_radix(&key_string[i..i+2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
key[8*(i>>1) + j] = val % 2 == 1;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC".to_string();
|
||||
let mut iv = [false; 80];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
let mut val: u8 = u8::from_str_radix(&iv_string[i..i+2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
iv[8*(i>>1) + j] = val % 2 == 1;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let output_0_63 = "F4CD954A717F26A7D6930830C4E7CF0819F80E03F25F342C64ADC66ABA7F8A8E6EAA49F23632AE3CD41A7BD290A0132F81C6D4043B6E397D7388F3A03B5FE358".to_string();
|
||||
|
||||
let cipher_key = key.map(|x| FheBool::encrypt(x, &client_key));
|
||||
let cipher_iv = iv.map(|x| FheBool::encrypt(x, &client_key));
|
||||
|
||||
|
||||
let mut trivium = TriviumStream::<FheBool>::new(cipher_key, cipher_iv, &server_key);
|
||||
|
||||
let mut vec = Vec::<bool>::with_capacity(64*8);
|
||||
while vec.len() < 64*8 {
|
||||
let cipher_outputs = trivium.next_64();
|
||||
for c in cipher_outputs {
|
||||
vec.push(c.decrypt(&client_key))
|
||||
}
|
||||
}
|
||||
|
||||
let hexadecimal = get_hexadecimal_string_from_lsb_first_stream(vec);
|
||||
assert_eq!(output_0_63, hexadecimal[0..64*2]);
|
||||
}
|
||||
```
|
||||
|
||||
# FHE byte Trivium implementation
|
||||
|
||||
The same objects have also been implemented to stream bytes insead of booleans. They can be constructed and used in the same way via the functions `TriviumStreamByte::<u8>::new` and
|
||||
`TriviumStreamByte::<FheUint8>::new` with the same arguments as before. The `FheUint8` version is significantly slower than the `FheBool` version, because not running
|
||||
with the same cryptographic parameters. Its interest lie in its trans-ciphering capabilities: `TriviumStreamByte<FheUint8>` implements the trait `TransCiphering`,
|
||||
meaning it implements the functions `trans_encrypt_64`. This function takes as input a `FheUint64` and outputs a `FheUint64`, the output being
|
||||
encrypted via tfhe and trivium. For convenience we also provide `trans_decrypt_64`, but this is of course the exact same function.
|
||||
|
||||
Other sizes than 64 bit are expected to be available in the future.
|
||||
|
||||
# FHE shortint Trivium implementation
|
||||
|
||||
The same implementation is also available for generic Ciphertexts representing bits (meant to be used with parameters `PARAM_MESSAGE_1_CARRY_1`). It uses a lower level API
|
||||
of tfhe-rs, so the syntax is a little bit different. It also implements the `TransCiphering` trait. For optimization purposes, it does not internally run on the same
|
||||
cryptographic parameters as the high level API of tfhe-rs. As such, it requires the usage of a casting key, to switch from one parameter space to another, which makes
|
||||
its setup a little more intricate.
|
||||
|
||||
Example code:
|
||||
```rust
|
||||
use tfhe::shortint::prelude::*;
|
||||
use tfhe::shortint::CastingKey;
|
||||
|
||||
use tfhe::{ConfigBuilder, generate_keys, FheUint64};
|
||||
use tfhe::prelude::*;
|
||||
|
||||
use tfhe_trivium::TriviumStreamShortint;
|
||||
|
||||
fn test_shortint() {
|
||||
let config = ConfigBuilder::all_disabled().enable_default_integers().build();
|
||||
let (hl_client_key, hl_server_key) = generate_keys(config);
|
||||
let (client_key, server_key): (ClientKey, ServerKey) = gen_keys(PARAM_MESSAGE_1_CARRY_1);
|
||||
let ksk = CastingKey::new((&client_key, &server_key), (&hl_client_key, &hl_server_key));
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB".to_string();
|
||||
let mut key = [0; 80];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
let mut val = u64::from_str_radix(&key_string[i..i+2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
key[8*(i>>1) + j] = val % 2;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC".to_string();
|
||||
let mut iv = [0; 80];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
let mut val = u64::from_str_radix(&iv_string[i..i+2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
iv[8*(i>>1) + j] = val % 2;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
let output_0_63 = "F4CD954A717F26A7D6930830C4E7CF0819F80E03F25F342C64ADC66ABA7F8A8E6EAA49F23632AE3CD41A7BD290A0132F81C6D4043B6E397D7388F3A03B5FE358".to_string();
|
||||
|
||||
let cipher_key = key.map(|x| client_key.encrypt(x));
|
||||
let cipher_iv = iv.map(|x| client_key.encrypt(x));
|
||||
|
||||
let mut ciphered_message = vec![FheUint64::try_encrypt(0u64, &hl_client_key).unwrap(); 9];
|
||||
|
||||
let mut trivium = TriviumStreamShortint::new(cipher_key, cipher_iv, &server_key, &ksk);
|
||||
|
||||
let mut vec = Vec::<u64>::with_capacity(8);
|
||||
while vec.len() < 8 {
|
||||
let trans_ciphered_message = trivium.trans_encrypt_64(ciphered_message.pop().unwrap(), &hl_server_key);
|
||||
vec.push(trans_ciphered_message.decrypt(&hl_client_key));
|
||||
}
|
||||
|
||||
let hexadecimal = get_hexagonal_string_from_u64(vec);
|
||||
assert_eq!(output_0_63, hexadecimal[0..64*2]);
|
||||
}
|
||||
```
|
||||
|
||||
# FHE Kreyvium implementation using tfhe-rs crate
|
||||
|
||||
This will work in exactly the same way as the Trivium implementation, except that the key and iv need to be 128 bits now. Available for the same internal types as Trivium, with similar syntax.
|
||||
|
||||
`KreyviumStreamByte<FheUint8>` and `KreyviumStreamShortint` also implement the `TransCiphering` trait.
|
||||
|
||||
# Testing
|
||||
|
||||
If you wish to run tests on this app, please run `cargo test -r trivium -- --test-threads=1` as multithreading provokes interferences between several running
|
||||
Triviums at the same time.
|
||||
75
apps/trivium/benches/kreyvium_bool.rs
Normal file
75
apps/trivium/benches/kreyvium_bool.rs
Normal file
@@ -0,0 +1,75 @@
|
||||
use tfhe::prelude::*;
|
||||
use tfhe::{generate_keys, ConfigBuilder, FheBool};
|
||||
|
||||
use tfhe_trivium::KreyviumStream;
|
||||
|
||||
use criterion::Criterion;
|
||||
|
||||
pub fn kreyvium_bool_gen(c: &mut Criterion) {
|
||||
let config = ConfigBuilder::all_disabled().enable_default_bool().build();
|
||||
let (client_key, server_key) = generate_keys(config);
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB000000000000".to_string();
|
||||
let mut key = [false; 128];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
let mut val: u8 = u8::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
key[8 * (i >> 1) + j] = val % 2 == 1;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC000000000000".to_string();
|
||||
let mut iv = [false; 128];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
let mut val: u8 = u8::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
iv[8 * (i >> 1) + j] = val % 2 == 1;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let cipher_key = key.map(|x| FheBool::encrypt(x, &client_key));
|
||||
|
||||
let mut kreyvium = KreyviumStream::<FheBool>::new(cipher_key, iv, &server_key);
|
||||
|
||||
c.bench_function("kreyvium bool generate 64 bits", |b| {
|
||||
b.iter(|| kreyvium.next_64())
|
||||
});
|
||||
}
|
||||
|
||||
pub fn kreyvium_bool_warmup(c: &mut Criterion) {
|
||||
let config = ConfigBuilder::all_disabled().enable_default_bool().build();
|
||||
let (client_key, server_key) = generate_keys(config);
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB000000000000".to_string();
|
||||
let mut key = [false; 128];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
let mut val: u8 = u8::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
key[8 * (i >> 1) + j] = val % 2 == 1;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC000000000000".to_string();
|
||||
let mut iv = [false; 128];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
let mut val: u8 = u8::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
iv[8 * (i >> 1) + j] = val % 2 == 1;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
c.bench_function("kreyvium bool warmup", |b| {
|
||||
b.iter(|| {
|
||||
let cipher_key = key.map(|x| FheBool::encrypt(x, &client_key));
|
||||
let _kreyvium = KreyviumStream::<FheBool>::new(cipher_key, iv, &server_key);
|
||||
})
|
||||
});
|
||||
}
|
||||
96
apps/trivium/benches/kreyvium_byte.rs
Normal file
96
apps/trivium/benches/kreyvium_byte.rs
Normal file
@@ -0,0 +1,96 @@
|
||||
use tfhe::prelude::*;
|
||||
use tfhe::{generate_keys, ConfigBuilder, FheUint64, FheUint8};
|
||||
|
||||
use tfhe_trivium::{KreyviumStreamByte, TransCiphering};
|
||||
|
||||
use criterion::Criterion;
|
||||
|
||||
pub fn kreyvium_byte_gen(c: &mut Criterion) {
|
||||
let config = ConfigBuilder::all_disabled()
|
||||
.enable_default_integers()
|
||||
.enable_function_evaluation_integers()
|
||||
.build();
|
||||
let (client_key, server_key) = generate_keys(config);
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB000000000000".to_string();
|
||||
let mut key = [0u8; 16];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
key[i >> 1] = u8::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC000000000000".to_string();
|
||||
let mut iv = [0u8; 16];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
iv[i >> 1] = u8::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
}
|
||||
|
||||
let cipher_key = key.map(|x| FheUint8::encrypt(x, &client_key));
|
||||
|
||||
let mut kreyvium = KreyviumStreamByte::<FheUint8>::new(cipher_key, iv, &server_key);
|
||||
|
||||
c.bench_function("kreyvium byte generate 64 bits", |b| {
|
||||
b.iter(|| kreyvium.next_64())
|
||||
});
|
||||
}
|
||||
|
||||
pub fn kreyvium_byte_trans(c: &mut Criterion) {
|
||||
let config = ConfigBuilder::all_disabled()
|
||||
.enable_default_integers()
|
||||
.enable_function_evaluation_integers()
|
||||
.build();
|
||||
let (client_key, server_key) = generate_keys(config);
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB000000000000".to_string();
|
||||
let mut key = [0u8; 16];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
key[i >> 1] = u8::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC000000000000".to_string();
|
||||
let mut iv = [0u8; 16];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
iv[i >> 1] = u8::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
}
|
||||
|
||||
let cipher_key = key.map(|x| FheUint8::encrypt(x, &client_key));
|
||||
|
||||
let ciphered_message = FheUint64::try_encrypt(0u64, &client_key).unwrap();
|
||||
let mut kreyvium = KreyviumStreamByte::<FheUint8>::new(cipher_key, iv, &server_key);
|
||||
|
||||
c.bench_function("kreyvium byte transencrypt 64 bits", |b| {
|
||||
b.iter(|| kreyvium.trans_encrypt_64(ciphered_message.clone()))
|
||||
});
|
||||
}
|
||||
|
||||
pub fn kreyvium_byte_warmup(c: &mut Criterion) {
|
||||
let config = ConfigBuilder::all_disabled()
|
||||
.enable_default_integers()
|
||||
.enable_function_evaluation_integers()
|
||||
.build();
|
||||
let (client_key, server_key) = generate_keys(config);
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB000000000000".to_string();
|
||||
let mut key = [0u8; 16];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
key[i >> 1] = u8::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC000000000000".to_string();
|
||||
let mut iv = [0u8; 16];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
iv[i >> 1] = u8::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
}
|
||||
|
||||
c.bench_function("kreyvium byte warmup", |b| {
|
||||
b.iter(|| {
|
||||
let cipher_key = key.map(|x| FheUint8::encrypt(x, &client_key));
|
||||
let _kreyvium = KreyviumStreamByte::<FheUint8>::new(cipher_key, iv, &server_key);
|
||||
})
|
||||
});
|
||||
}
|
||||
128
apps/trivium/benches/kreyvium_shortint.rs
Normal file
128
apps/trivium/benches/kreyvium_shortint.rs
Normal file
@@ -0,0 +1,128 @@
|
||||
use tfhe::prelude::*;
|
||||
use tfhe::shortint::prelude::*;
|
||||
use tfhe::shortint::CastingKey;
|
||||
use tfhe::{generate_keys, ConfigBuilder, FheUint64};
|
||||
|
||||
use tfhe_trivium::{KreyviumStreamShortint, TransCiphering};
|
||||
|
||||
use criterion::Criterion;
|
||||
|
||||
pub fn kreyvium_shortint_warmup(c: &mut Criterion) {
|
||||
let config = ConfigBuilder::all_disabled()
|
||||
.enable_default_integers()
|
||||
.build();
|
||||
let (hl_client_key, hl_server_key) = generate_keys(config);
|
||||
let (client_key, server_key): (ClientKey, ServerKey) = gen_keys(PARAM_MESSAGE_1_CARRY_1);
|
||||
let ksk = CastingKey::new((&client_key, &server_key), (&hl_client_key, &hl_server_key));
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB000000000000".to_string();
|
||||
let mut key = [0; 128];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
let mut val = u64::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
key[8 * (i >> 1) + j] = val % 2;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC000000000000".to_string();
|
||||
let mut iv = [0; 128];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
let mut val = u64::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
iv[8 * (i >> 1) + j] = val % 2;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
c.bench_function("kreyvium 1_1 warmup", |b| {
|
||||
b.iter(|| {
|
||||
let cipher_key = key.map(|x| client_key.encrypt(x));
|
||||
let _kreyvium =
|
||||
KreyviumStreamShortint::new(cipher_key, iv, &server_key, &ksk, &hl_server_key);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
pub fn kreyvium_shortint_gen(c: &mut Criterion) {
|
||||
let config = ConfigBuilder::all_disabled()
|
||||
.enable_default_integers()
|
||||
.build();
|
||||
let (hl_client_key, hl_server_key) = generate_keys(config);
|
||||
let (client_key, server_key): (ClientKey, ServerKey) = gen_keys(PARAM_MESSAGE_1_CARRY_1);
|
||||
let ksk = CastingKey::new((&client_key, &server_key), (&hl_client_key, &hl_server_key));
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB000000000000".to_string();
|
||||
let mut key = [0; 128];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
let mut val = u64::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
key[8 * (i >> 1) + j] = val % 2;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC000000000000".to_string();
|
||||
let mut iv = [0; 128];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
let mut val = u64::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
iv[8 * (i >> 1) + j] = val % 2;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let cipher_key = key.map(|x| client_key.encrypt(x));
|
||||
|
||||
let mut kreyvium =
|
||||
KreyviumStreamShortint::new(cipher_key, iv, &server_key, &ksk, &hl_server_key);
|
||||
|
||||
c.bench_function("kreyvium 1_1 generate 64 bits", |b| {
|
||||
b.iter(|| kreyvium.next_64())
|
||||
});
|
||||
}
|
||||
|
||||
pub fn kreyvium_shortint_trans(c: &mut Criterion) {
|
||||
let config = ConfigBuilder::all_disabled()
|
||||
.enable_default_integers()
|
||||
.build();
|
||||
let (hl_client_key, hl_server_key) = generate_keys(config);
|
||||
let (client_key, server_key): (ClientKey, ServerKey) = gen_keys(PARAM_MESSAGE_1_CARRY_1);
|
||||
let ksk = CastingKey::new((&client_key, &server_key), (&hl_client_key, &hl_server_key));
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB000000000000".to_string();
|
||||
let mut key = [0; 128];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
let mut val = u64::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
key[8 * (i >> 1) + j] = val % 2;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC000000000000".to_string();
|
||||
let mut iv = [0; 128];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
let mut val = u64::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
iv[8 * (i >> 1) + j] = val % 2;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let cipher_key = key.map(|x| client_key.encrypt(x));
|
||||
|
||||
let ciphered_message = FheUint64::try_encrypt(0u64, &hl_client_key).unwrap();
|
||||
let mut kreyvium =
|
||||
KreyviumStreamShortint::new(cipher_key, iv, &server_key, &ksk, &hl_server_key);
|
||||
|
||||
c.bench_function("kreyvium 1_1 transencrypt 64 bits", |b| {
|
||||
b.iter(|| kreyvium.trans_encrypt_64(ciphered_message.clone()))
|
||||
});
|
||||
}
|
||||
53
apps/trivium/benches/trivium.rs
Normal file
53
apps/trivium/benches/trivium.rs
Normal file
@@ -0,0 +1,53 @@
|
||||
use criterion::{criterion_group, criterion_main};
|
||||
|
||||
mod trivium_bool;
|
||||
criterion_group!(
|
||||
trivium_bool,
|
||||
trivium_bool::trivium_bool_gen,
|
||||
trivium_bool::trivium_bool_warmup
|
||||
);
|
||||
mod kreyvium_bool;
|
||||
criterion_group!(
|
||||
kreyvium_bool,
|
||||
kreyvium_bool::kreyvium_bool_gen,
|
||||
kreyvium_bool::kreyvium_bool_warmup
|
||||
);
|
||||
|
||||
mod trivium_shortint;
|
||||
criterion_group!(
|
||||
trivium_shortint,
|
||||
trivium_shortint::trivium_shortint_gen,
|
||||
trivium_shortint::trivium_shortint_warmup,
|
||||
trivium_shortint::trivium_shortint_trans
|
||||
);
|
||||
mod kreyvium_shortint;
|
||||
criterion_group!(
|
||||
kreyvium_shortint,
|
||||
kreyvium_shortint::kreyvium_shortint_gen,
|
||||
kreyvium_shortint::kreyvium_shortint_warmup,
|
||||
kreyvium_shortint::kreyvium_shortint_trans
|
||||
);
|
||||
|
||||
mod trivium_byte;
|
||||
criterion_group!(
|
||||
trivium_byte,
|
||||
trivium_byte::trivium_byte_gen,
|
||||
trivium_byte::trivium_byte_trans,
|
||||
trivium_byte::trivium_byte_warmup
|
||||
);
|
||||
mod kreyvium_byte;
|
||||
criterion_group!(
|
||||
kreyvium_byte,
|
||||
kreyvium_byte::kreyvium_byte_gen,
|
||||
kreyvium_byte::kreyvium_byte_trans,
|
||||
kreyvium_byte::kreyvium_byte_warmup
|
||||
);
|
||||
|
||||
criterion_main!(
|
||||
trivium_bool,
|
||||
trivium_shortint,
|
||||
trivium_byte,
|
||||
kreyvium_bool,
|
||||
kreyvium_shortint,
|
||||
kreyvium_byte,
|
||||
);
|
||||
75
apps/trivium/benches/trivium_bool.rs
Normal file
75
apps/trivium/benches/trivium_bool.rs
Normal file
@@ -0,0 +1,75 @@
|
||||
use tfhe::prelude::*;
|
||||
use tfhe::{generate_keys, ConfigBuilder, FheBool};
|
||||
|
||||
use tfhe_trivium::TriviumStream;
|
||||
|
||||
use criterion::Criterion;
|
||||
|
||||
pub fn trivium_bool_gen(c: &mut Criterion) {
|
||||
let config = ConfigBuilder::all_disabled().enable_default_bool().build();
|
||||
let (client_key, server_key) = generate_keys(config);
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB".to_string();
|
||||
let mut key = [false; 80];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
let mut val: u8 = u8::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
key[8 * (i >> 1) + j] = val % 2 == 1;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC".to_string();
|
||||
let mut iv = [false; 80];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
let mut val: u8 = u8::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
iv[8 * (i >> 1) + j] = val % 2 == 1;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let cipher_key = key.map(|x| FheBool::encrypt(x, &client_key));
|
||||
|
||||
let mut trivium = TriviumStream::<FheBool>::new(cipher_key, iv, &server_key);
|
||||
|
||||
c.bench_function("trivium bool generate 64 bits", |b| {
|
||||
b.iter(|| trivium.next_64())
|
||||
});
|
||||
}
|
||||
|
||||
pub fn trivium_bool_warmup(c: &mut Criterion) {
|
||||
let config = ConfigBuilder::all_disabled().enable_default_bool().build();
|
||||
let (client_key, server_key) = generate_keys(config);
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB".to_string();
|
||||
let mut key = [false; 80];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
let mut val: u8 = u8::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
key[8 * (i >> 1) + j] = val % 2 == 1;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC".to_string();
|
||||
let mut iv = [false; 80];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
let mut val: u8 = u8::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
iv[8 * (i >> 1) + j] = val % 2 == 1;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
c.bench_function("trivium bool warmup", |b| {
|
||||
b.iter(|| {
|
||||
let cipher_key = key.map(|x| FheBool::encrypt(x, &client_key));
|
||||
let _trivium = TriviumStream::<FheBool>::new(cipher_key, iv, &server_key);
|
||||
})
|
||||
});
|
||||
}
|
||||
93
apps/trivium/benches/trivium_byte.rs
Normal file
93
apps/trivium/benches/trivium_byte.rs
Normal file
@@ -0,0 +1,93 @@
|
||||
use tfhe::prelude::*;
|
||||
use tfhe::{generate_keys, ConfigBuilder, FheUint64, FheUint8};
|
||||
|
||||
use tfhe_trivium::{TransCiphering, TriviumStreamByte};
|
||||
|
||||
use criterion::Criterion;
|
||||
|
||||
pub fn trivium_byte_gen(c: &mut Criterion) {
|
||||
let config = ConfigBuilder::all_disabled()
|
||||
.enable_default_integers()
|
||||
.build();
|
||||
let (client_key, server_key) = generate_keys(config);
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB".to_string();
|
||||
let mut key = [0u8; 10];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
key[i >> 1] = u8::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC".to_string();
|
||||
let mut iv = [0u8; 10];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
iv[i >> 1] = u8::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
}
|
||||
|
||||
let cipher_key = key.map(|x| FheUint8::encrypt(x, &client_key));
|
||||
|
||||
let mut trivium = TriviumStreamByte::<FheUint8>::new(cipher_key, iv, &server_key);
|
||||
|
||||
c.bench_function("trivium byte generate 64 bits", |b| {
|
||||
b.iter(|| trivium.next_64())
|
||||
});
|
||||
}
|
||||
|
||||
pub fn trivium_byte_trans(c: &mut Criterion) {
|
||||
let config = ConfigBuilder::all_disabled()
|
||||
.enable_default_integers()
|
||||
.build();
|
||||
let (client_key, server_key) = generate_keys(config);
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB".to_string();
|
||||
let mut key = [0u8; 10];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
key[i >> 1] = u8::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC".to_string();
|
||||
let mut iv = [0u8; 10];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
iv[i >> 1] = u8::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
}
|
||||
|
||||
let cipher_key = key.map(|x| FheUint8::encrypt(x, &client_key));
|
||||
|
||||
let ciphered_message = FheUint64::try_encrypt(0u64, &client_key).unwrap();
|
||||
let mut trivium = TriviumStreamByte::<FheUint8>::new(cipher_key, iv, &server_key);
|
||||
|
||||
c.bench_function("trivium byte transencrypt 64 bits", |b| {
|
||||
b.iter(|| trivium.trans_encrypt_64(ciphered_message.clone()))
|
||||
});
|
||||
}
|
||||
|
||||
pub fn trivium_byte_warmup(c: &mut Criterion) {
|
||||
let config = ConfigBuilder::all_disabled()
|
||||
.enable_default_integers()
|
||||
.build();
|
||||
let (client_key, server_key) = generate_keys(config);
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB".to_string();
|
||||
let mut key = [0u8; 10];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
key[i >> 1] = u8::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC".to_string();
|
||||
let mut iv = [0u8; 10];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
iv[i >> 1] = u8::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
}
|
||||
|
||||
c.bench_function("trivium byte warmup", |b| {
|
||||
b.iter(|| {
|
||||
let cipher_key = key.map(|x| FheUint8::encrypt(x, &client_key));
|
||||
let _trivium = TriviumStreamByte::<FheUint8>::new(cipher_key, iv, &server_key);
|
||||
})
|
||||
});
|
||||
}
|
||||
126
apps/trivium/benches/trivium_shortint.rs
Normal file
126
apps/trivium/benches/trivium_shortint.rs
Normal file
@@ -0,0 +1,126 @@
|
||||
use tfhe::prelude::*;
|
||||
use tfhe::shortint::prelude::*;
|
||||
use tfhe::shortint::CastingKey;
|
||||
use tfhe::{generate_keys, ConfigBuilder, FheUint64};
|
||||
|
||||
use tfhe_trivium::{TransCiphering, TriviumStreamShortint};
|
||||
|
||||
use criterion::Criterion;
|
||||
|
||||
pub fn trivium_shortint_warmup(c: &mut Criterion) {
|
||||
let config = ConfigBuilder::all_disabled()
|
||||
.enable_default_integers()
|
||||
.build();
|
||||
let (hl_client_key, hl_server_key) = generate_keys(config);
|
||||
let (client_key, server_key): (ClientKey, ServerKey) = gen_keys(PARAM_MESSAGE_1_CARRY_1);
|
||||
let ksk = CastingKey::new((&client_key, &server_key), (&hl_client_key, &hl_server_key));
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB".to_string();
|
||||
let mut key = [0; 80];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
let mut val = u64::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
key[8 * (i >> 1) + j] = val % 2;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC".to_string();
|
||||
let mut iv = [0; 80];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
let mut val = u64::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
iv[8 * (i >> 1) + j] = val % 2;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
c.bench_function("trivium 1_1 warmup", |b| {
|
||||
b.iter(|| {
|
||||
let cipher_key = key.map(|x| client_key.encrypt(x));
|
||||
let _trivium =
|
||||
TriviumStreamShortint::new(cipher_key, iv, &server_key, &ksk, &hl_server_key);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
pub fn trivium_shortint_gen(c: &mut Criterion) {
|
||||
let config = ConfigBuilder::all_disabled()
|
||||
.enable_default_integers()
|
||||
.build();
|
||||
let (hl_client_key, hl_server_key) = generate_keys(config);
|
||||
let (client_key, server_key): (ClientKey, ServerKey) = gen_keys(PARAM_MESSAGE_1_CARRY_1);
|
||||
let ksk = CastingKey::new((&client_key, &server_key), (&hl_client_key, &hl_server_key));
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB".to_string();
|
||||
let mut key = [0; 80];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
let mut val = u64::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
key[8 * (i >> 1) + j] = val % 2;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC".to_string();
|
||||
let mut iv = [0; 80];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
let mut val = u64::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
iv[8 * (i >> 1) + j] = val % 2;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let cipher_key = key.map(|x| client_key.encrypt(x));
|
||||
|
||||
let mut trivium = TriviumStreamShortint::new(cipher_key, iv, &server_key, &ksk, &hl_server_key);
|
||||
|
||||
c.bench_function("trivium 1_1 generate 64 bits", |b| {
|
||||
b.iter(|| trivium.next_64())
|
||||
});
|
||||
}
|
||||
|
||||
pub fn trivium_shortint_trans(c: &mut Criterion) {
|
||||
let config = ConfigBuilder::all_disabled()
|
||||
.enable_default_integers()
|
||||
.build();
|
||||
let (hl_client_key, hl_server_key) = generate_keys(config);
|
||||
let (client_key, server_key): (ClientKey, ServerKey) = gen_keys(PARAM_MESSAGE_1_CARRY_1);
|
||||
let ksk = CastingKey::new((&client_key, &server_key), (&hl_client_key, &hl_server_key));
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB".to_string();
|
||||
let mut key = [0; 80];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
let mut val = u64::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
key[8 * (i >> 1) + j] = val % 2;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC".to_string();
|
||||
let mut iv = [0; 80];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
let mut val = u64::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
iv[8 * (i >> 1) + j] = val % 2;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let cipher_key = key.map(|x| client_key.encrypt(x));
|
||||
|
||||
let ciphered_message = FheUint64::try_encrypt(0u64, &hl_client_key).unwrap();
|
||||
let mut trivium = TriviumStreamShortint::new(cipher_key, iv, &server_key, &ksk, &hl_server_key);
|
||||
|
||||
c.bench_function("trivium 1_1 transencrypt 64 bits", |b| {
|
||||
b.iter(|| trivium.trans_encrypt_64(ciphered_message.clone()))
|
||||
});
|
||||
}
|
||||
257
apps/trivium/src/kreyvium/kreyvium.rs
Normal file
257
apps/trivium/src/kreyvium/kreyvium.rs
Normal file
@@ -0,0 +1,257 @@
|
||||
//! This module implements the Kreyvium stream cipher, using booleans or FheBool
|
||||
//! for the representaion of the inner bits.
|
||||
|
||||
use crate::static_deque::StaticDeque;
|
||||
|
||||
use tfhe::prelude::*;
|
||||
use tfhe::{set_server_key, unset_server_key, FheBool, ServerKey};
|
||||
|
||||
use rayon::prelude::*;
|
||||
|
||||
/// Internal trait specifying which operations are necessary for KreyviumStream generic type
|
||||
pub trait KreyviumBoolInput<OpOutput>:
|
||||
Sized
|
||||
+ Clone
|
||||
+ std::ops::BitXor<Output = OpOutput>
|
||||
+ std::ops::BitAnd<Output = OpOutput>
|
||||
+ std::ops::Not<Output = OpOutput>
|
||||
{
|
||||
}
|
||||
impl KreyviumBoolInput<bool> for bool {}
|
||||
impl KreyviumBoolInput<bool> for &bool {}
|
||||
impl KreyviumBoolInput<FheBool> for FheBool {}
|
||||
impl KreyviumBoolInput<FheBool> for &FheBool {}
|
||||
|
||||
/// KreyviumStream: a struct implementing the Kreyvium stream cipher, using T for the internal
|
||||
/// representation of bits (bool or FheBool). To be able to compute FHE operations, it also owns
|
||||
/// an Option for a ServerKey.
|
||||
pub struct KreyviumStream<T> {
|
||||
a: StaticDeque<93, T>,
|
||||
b: StaticDeque<84, T>,
|
||||
c: StaticDeque<111, T>,
|
||||
k: StaticDeque<128, T>,
|
||||
iv: StaticDeque<128, T>,
|
||||
fhe_key: Option<ServerKey>,
|
||||
}
|
||||
|
||||
impl KreyviumStream<bool> {
|
||||
/// Contructor for `KreyviumStream<bool>`: arguments are the secret key and the input vector.
|
||||
/// Outputs a KreyviumStream object already initialized (1152 steps have been run before
|
||||
/// returning)
|
||||
pub fn new(mut key: [bool; 128], mut iv: [bool; 128]) -> KreyviumStream<bool> {
|
||||
// Initialization of Kreyvium registers: a has the secret key, b the input vector,
|
||||
// and c a few ones.
|
||||
let mut a_register = [false; 93];
|
||||
let mut b_register = [false; 84];
|
||||
let mut c_register = [false; 111];
|
||||
|
||||
for i in 0..93 {
|
||||
a_register[i] = key[128 - 93 + i];
|
||||
}
|
||||
for i in 0..84 {
|
||||
b_register[i] = iv[128 - 84 + i];
|
||||
}
|
||||
for i in 0..44 {
|
||||
c_register[111 - 44 + i] = iv[i];
|
||||
}
|
||||
for i in 0..66 {
|
||||
c_register[i + 1] = true;
|
||||
}
|
||||
|
||||
key.reverse();
|
||||
iv.reverse();
|
||||
KreyviumStream::<bool>::new_from_registers(
|
||||
a_register, b_register, c_register, key, iv, None,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl KreyviumStream<FheBool> {
|
||||
/// Constructor for `KreyviumStream<FheBool>`: arguments are the encrypted secret key and input
|
||||
/// vector, and the FHE server key.
|
||||
/// Outputs a KreyviumStream object already initialized (1152 steps have been run before
|
||||
/// returning)
|
||||
pub fn new(
|
||||
mut key: [FheBool; 128],
|
||||
mut iv: [bool; 128],
|
||||
sk: &ServerKey,
|
||||
) -> KreyviumStream<FheBool> {
|
||||
set_server_key(sk.clone());
|
||||
|
||||
// Initialization of Kreyvium registers: a has the secret key, b the input vector,
|
||||
// and c a few ones.
|
||||
let mut a_register = [false; 93].map(|x| FheBool::encrypt_trivial(x));
|
||||
let mut b_register = [false; 84].map(|x| FheBool::encrypt_trivial(x));
|
||||
let mut c_register = [false; 111].map(|x| FheBool::encrypt_trivial(x));
|
||||
|
||||
for i in 0..93 {
|
||||
a_register[i] = key[128 - 93 + i].clone();
|
||||
}
|
||||
for i in 0..84 {
|
||||
b_register[i] = FheBool::encrypt_trivial(iv[128 - 84 + i]);
|
||||
}
|
||||
for i in 0..44 {
|
||||
c_register[111 - 44 + i] = FheBool::encrypt_trivial(iv[i]);
|
||||
}
|
||||
for i in 0..66 {
|
||||
c_register[i + 1] = FheBool::encrypt_trivial(true);
|
||||
}
|
||||
|
||||
key.reverse();
|
||||
iv.reverse();
|
||||
let iv = iv.map(|x| FheBool::encrypt_trivial(x));
|
||||
|
||||
unset_server_key();
|
||||
KreyviumStream::<FheBool>::new_from_registers(
|
||||
a_register,
|
||||
b_register,
|
||||
c_register,
|
||||
key,
|
||||
iv,
|
||||
Some(sk.clone()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> KreyviumStream<T>
|
||||
where
|
||||
T: KreyviumBoolInput<T> + std::marker::Send + std::marker::Sync,
|
||||
for<'a> &'a T: KreyviumBoolInput<T>,
|
||||
{
|
||||
/// Internal generic contructor: arguments are already prepared registers, and an optional FHE
|
||||
/// server key
|
||||
fn new_from_registers(
|
||||
a_register: [T; 93],
|
||||
b_register: [T; 84],
|
||||
c_register: [T; 111],
|
||||
k_register: [T; 128],
|
||||
iv_register: [T; 128],
|
||||
key: Option<ServerKey>,
|
||||
) -> Self {
|
||||
let mut ret = Self {
|
||||
a: StaticDeque::<93, T>::new(a_register),
|
||||
b: StaticDeque::<84, T>::new(b_register),
|
||||
c: StaticDeque::<111, T>::new(c_register),
|
||||
k: StaticDeque::<128, T>::new(k_register),
|
||||
iv: StaticDeque::<128, T>::new(iv_register),
|
||||
fhe_key: key,
|
||||
};
|
||||
ret.init();
|
||||
ret
|
||||
}
|
||||
|
||||
/// The specification of Kreyvium includes running 1152 (= 18*64) unused steps to mix up the
|
||||
/// registers, before starting the proper stream
|
||||
fn init(&mut self) {
|
||||
for _ in 0..18 {
|
||||
self.next_64();
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes one turn of the stream, updating registers and outputting the new bit.
|
||||
pub fn next(&mut self) -> T {
|
||||
match &self.fhe_key {
|
||||
Some(sk) => set_server_key(sk.clone()),
|
||||
None => (),
|
||||
};
|
||||
|
||||
let [o, a, b, c] = self.get_output_and_values(0);
|
||||
|
||||
self.a.push(a);
|
||||
self.b.push(b);
|
||||
self.c.push(c);
|
||||
self.k.shift();
|
||||
self.iv.shift();
|
||||
|
||||
o
|
||||
}
|
||||
|
||||
/// Computes a potential future step of Kreyvium, n terms in the future. This does not update
|
||||
/// registers, but rather returns with the output, the three values that will be used to
|
||||
/// update the registers, when the time is right. This function is meant to be used in
|
||||
/// parallel.
|
||||
fn get_output_and_values(&self, n: usize) -> [T; 4] {
|
||||
assert!(n < 65);
|
||||
|
||||
let (((temp_a, temp_b), (temp_c, a_and)), (b_and, c_and)) = rayon::join(
|
||||
|| {
|
||||
rayon::join(
|
||||
|| {
|
||||
rayon::join(
|
||||
|| &self.a[65 - n] ^ &self.a[92 - n],
|
||||
|| &self.b[68 - n] ^ &self.b[83 - n],
|
||||
)
|
||||
},
|
||||
|| {
|
||||
rayon::join(
|
||||
|| &(&self.c[65 - n] ^ &self.c[110 - n]) ^ &self.k[127 - n],
|
||||
|| &(&self.a[91 - n] & &self.a[90 - n]) ^ &self.iv[127 - n],
|
||||
)
|
||||
},
|
||||
)
|
||||
},
|
||||
|| {
|
||||
rayon::join(
|
||||
|| &self.b[82 - n] & &self.b[81 - n],
|
||||
|| &self.c[109 - n] & &self.c[108 - n],
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
let ((o, a), (b, c)) = rayon::join(
|
||||
|| {
|
||||
rayon::join(
|
||||
|| &(&temp_a ^ &temp_b) ^ &temp_c,
|
||||
|| &temp_c ^ &(&c_and ^ &self.a[68 - n]),
|
||||
)
|
||||
},
|
||||
|| {
|
||||
rayon::join(
|
||||
|| &temp_a ^ &(&a_and ^ &self.b[77 - n]),
|
||||
|| &temp_b ^ &(&b_and ^ &self.c[86 - n]),
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
[o, a, b, c]
|
||||
}
|
||||
|
||||
/// This calls `get_output_and_values` in parallel 64 times, and stores all results in a Vec.
|
||||
fn get_64_output_and_values(&self) -> Vec<[T; 4]> {
|
||||
(0..64)
|
||||
.into_par_iter()
|
||||
.map(|x| self.get_output_and_values(x))
|
||||
.rev()
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Computes 64 turns of the stream, outputting the 64 bits all at once in a
|
||||
/// Vec (first value is oldest, last is newest)
|
||||
pub fn next_64(&mut self) -> Vec<T> {
|
||||
match &self.fhe_key {
|
||||
Some(sk) => {
|
||||
rayon::broadcast(|_| set_server_key(sk.clone()));
|
||||
}
|
||||
None => (),
|
||||
}
|
||||
let mut values = self.get_64_output_and_values();
|
||||
match &self.fhe_key {
|
||||
Some(_) => {
|
||||
rayon::broadcast(|_| unset_server_key());
|
||||
}
|
||||
None => (),
|
||||
}
|
||||
|
||||
let mut ret = Vec::<T>::with_capacity(64);
|
||||
|
||||
while let Some([o, a, b, c]) = values.pop() {
|
||||
ret.push(o);
|
||||
self.a.push(a);
|
||||
self.b.push(b);
|
||||
self.c.push(c);
|
||||
}
|
||||
self.k.n_shifts(64);
|
||||
self.iv.n_shifts(64);
|
||||
ret
|
||||
}
|
||||
}
|
||||
297
apps/trivium/src/kreyvium/kreyvium_byte.rs
Normal file
297
apps/trivium/src/kreyvium/kreyvium_byte.rs
Normal file
@@ -0,0 +1,297 @@
|
||||
//! This module implements the Kreyvium stream cipher, using u8 or FheUint8
|
||||
//! for the representaion of the inner bits.
|
||||
|
||||
use crate::static_deque::{StaticByteDeque, StaticByteDequeInput};
|
||||
|
||||
use tfhe::prelude::*;
|
||||
use tfhe::{set_server_key, unset_server_key, FheUint8, ServerKey};
|
||||
|
||||
use rayon::prelude::*;
|
||||
|
||||
/// Internal trait specifying which operations are necessary for KreyviumStreamByte generic type
|
||||
pub trait KreyviumByteInput<OpOutput>:
|
||||
Sized
|
||||
+ Send
|
||||
+ Sync
|
||||
+ Clone
|
||||
+ StaticByteDequeInput<OpOutput>
|
||||
+ std::ops::BitXor<Output = OpOutput>
|
||||
+ std::ops::BitAnd<Output = OpOutput>
|
||||
+ std::ops::Shr<u8, Output = OpOutput>
|
||||
+ std::ops::Shl<u8, Output = OpOutput>
|
||||
+ std::ops::Add<Output = OpOutput>
|
||||
{
|
||||
}
|
||||
impl KreyviumByteInput<u8> for u8 {}
|
||||
impl KreyviumByteInput<u8> for &u8 {}
|
||||
impl KreyviumByteInput<FheUint8> for FheUint8 {}
|
||||
impl KreyviumByteInput<FheUint8> for &FheUint8 {}
|
||||
|
||||
/// KreyviumStreamByte: a struct implementing the Kreyvium stream cipher, using T for the internal
|
||||
/// representation of bits (u8 or FheUint8). To be able to compute FHE operations, it also owns
|
||||
/// an Option for a ServerKey.
|
||||
/// Since the original Kreyvium registers' sizes are not a multiple of 8, these registers (which
|
||||
/// store byte-like objects) have a size that is the eigth of the closest multiple of 8 above the
|
||||
/// originals' sizes.
|
||||
pub struct KreyviumStreamByte<T> {
|
||||
a_byte: StaticByteDeque<12, T>,
|
||||
b_byte: StaticByteDeque<11, T>,
|
||||
c_byte: StaticByteDeque<14, T>,
|
||||
k_byte: StaticByteDeque<16, T>,
|
||||
iv_byte: StaticByteDeque<16, T>,
|
||||
fhe_key: Option<ServerKey>,
|
||||
}
|
||||
|
||||
impl KreyviumStreamByte<u8> {
|
||||
/// Contructor for `KreyviumStreamByte<u8>`: arguments are the secret key and the input vector.
|
||||
/// Outputs a KreyviumStream object already initialized (1152 steps have been run before
|
||||
/// returning)
|
||||
pub fn new(key_bytes: [u8; 16], iv_bytes: [u8; 16]) -> KreyviumStreamByte<u8> {
|
||||
// Initialization of Kreyvium registers: a has the secret key, b the input vector,
|
||||
// and c a few ones.
|
||||
let mut a_byte_reg = [0u8; 12];
|
||||
let mut b_byte_reg = [0u8; 11];
|
||||
let mut c_byte_reg = [0u8; 14];
|
||||
|
||||
// Copy key bits into a register
|
||||
for b in 0..12 {
|
||||
a_byte_reg[b] = key_bytes[b + 4];
|
||||
}
|
||||
// Copy iv bits into a register
|
||||
for b in 0..11 {
|
||||
b_byte_reg[b] = iv_bytes[b + 5];
|
||||
}
|
||||
// Copy a lot of ones in the c register
|
||||
c_byte_reg[0] = 252;
|
||||
for b in 1..8 {
|
||||
c_byte_reg[b] = 255;
|
||||
}
|
||||
// Copy iv bits in the c register
|
||||
c_byte_reg[8] = (iv_bytes[0] << 4) | 31;
|
||||
for b in 9..14 {
|
||||
c_byte_reg[b] = (iv_bytes[b - 9] >> 4) | (iv_bytes[b - 8] << 4);
|
||||
}
|
||||
|
||||
// Key and iv are stored in reverse in their shift registers
|
||||
let mut key = key_bytes.map(|b| b.reverse_bits());
|
||||
let mut iv = iv_bytes.map(|b| b.reverse_bits());
|
||||
key.reverse();
|
||||
iv.reverse();
|
||||
|
||||
let mut ret = KreyviumStreamByte::<u8>::new_from_registers(
|
||||
a_byte_reg, b_byte_reg, c_byte_reg, key, iv, None,
|
||||
);
|
||||
ret.init();
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl KreyviumStreamByte<FheUint8> {
|
||||
/// Constructor for `KreyviumStream<FheUint8>`: arguments are the encrypted secret key and input
|
||||
/// vector, and the FHE server key.
|
||||
/// Outputs a KreyviumStream object already initialized (1152 steps have been run before
|
||||
/// returning)
|
||||
pub fn new(
|
||||
key_bytes: [FheUint8; 16],
|
||||
iv_bytes: [u8; 16],
|
||||
server_key: &ServerKey,
|
||||
) -> KreyviumStreamByte<FheUint8> {
|
||||
set_server_key(server_key.clone());
|
||||
|
||||
// Initialization of Kreyvium registers: a has the secret key, b the input vector,
|
||||
// and c a few ones.
|
||||
let mut a_byte_reg = [0u8; 12].map(|x| FheUint8::encrypt_trivial(x));
|
||||
let mut b_byte_reg = [0u8; 11].map(|x| FheUint8::encrypt_trivial(x));
|
||||
let mut c_byte_reg = [0u8; 14].map(|x| FheUint8::encrypt_trivial(x));
|
||||
|
||||
// Copy key bits into a register
|
||||
for b in 0..12 {
|
||||
a_byte_reg[b] = key_bytes[b + 4].clone();
|
||||
}
|
||||
// Copy iv bits into a register
|
||||
for b in 0..11 {
|
||||
b_byte_reg[b] = FheUint8::encrypt_trivial(iv_bytes[b + 5]);
|
||||
}
|
||||
// Copy a lot of ones in the c register
|
||||
c_byte_reg[0] = FheUint8::encrypt_trivial(252u8);
|
||||
for b in 1..8 {
|
||||
c_byte_reg[b] = FheUint8::encrypt_trivial(255u8);
|
||||
}
|
||||
// Copy iv bits in the c register
|
||||
c_byte_reg[8] = FheUint8::encrypt_trivial((&iv_bytes[0] << 4u8) | 31u8);
|
||||
for b in 9..14 {
|
||||
c_byte_reg[b] =
|
||||
FheUint8::encrypt_trivial((&iv_bytes[b - 9] >> 4u8) | (&iv_bytes[b - 8] << 4u8));
|
||||
}
|
||||
|
||||
// Key and iv are stored in reverse in their shift registers
|
||||
let mut key = key_bytes.map(|b| b.map(|x| (x as u8).reverse_bits() as u64));
|
||||
let mut iv = iv_bytes.map(|x| FheUint8::encrypt_trivial(x.reverse_bits()));
|
||||
key.reverse();
|
||||
iv.reverse();
|
||||
|
||||
unset_server_key();
|
||||
|
||||
let mut ret = KreyviumStreamByte::<FheUint8>::new_from_registers(
|
||||
a_byte_reg,
|
||||
b_byte_reg,
|
||||
c_byte_reg,
|
||||
key,
|
||||
iv,
|
||||
Some(server_key.clone()),
|
||||
);
|
||||
ret.init();
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> KreyviumStreamByte<T>
|
||||
where
|
||||
T: KreyviumByteInput<T> + Send,
|
||||
for<'a> &'a T: KreyviumByteInput<T>,
|
||||
{
|
||||
/// Internal generic contructor: arguments are already prepared registers, and an optional FHE
|
||||
/// server key
|
||||
fn new_from_registers(
|
||||
a_register: [T; 12],
|
||||
b_register: [T; 11],
|
||||
c_register: [T; 14],
|
||||
k_register: [T; 16],
|
||||
iv_register: [T; 16],
|
||||
sk: Option<ServerKey>,
|
||||
) -> Self {
|
||||
Self {
|
||||
a_byte: StaticByteDeque::<12, T>::new(a_register),
|
||||
b_byte: StaticByteDeque::<11, T>::new(b_register),
|
||||
c_byte: StaticByteDeque::<14, T>::new(c_register),
|
||||
k_byte: StaticByteDeque::<16, T>::new(k_register),
|
||||
iv_byte: StaticByteDeque::<16, T>::new(iv_register),
|
||||
fhe_key: sk,
|
||||
}
|
||||
}
|
||||
|
||||
/// The specification of Kreyvium includes running 1152 (= 18*64) unused steps to mix up the
|
||||
/// registers, before starting the proper stream
|
||||
fn init(&mut self) {
|
||||
for _ in 0..18 {
|
||||
self.next_64();
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes 8 potential future step of Kreyvium, b*8 terms in the future. This does not update
|
||||
/// registers, but rather returns with the output, the three values that will be used to
|
||||
/// update the registers, when the time is right. This function is meant to be used in
|
||||
/// parallel.
|
||||
fn get_output_and_values(&self, b: usize) -> [T; 4] {
|
||||
let n = b * 8 + 7;
|
||||
assert!(n < 65);
|
||||
|
||||
let (((k, iv), (a1, a2, a3, a4, a5)), ((b1, b2, b3, b4, b5), (c1, c2, c3, c4, c5))) =
|
||||
rayon::join(
|
||||
|| {
|
||||
rayon::join(
|
||||
|| (self.k_byte.byte(127 - n), self.iv_byte.byte(127 - n)),
|
||||
|| Self::get_bytes(&self.a_byte, [91 - n, 90 - n, 68 - n, 65 - n, 92 - n]),
|
||||
)
|
||||
},
|
||||
|| {
|
||||
rayon::join(
|
||||
|| Self::get_bytes(&self.b_byte, [82 - n, 81 - n, 77 - n, 68 - n, 83 - n]),
|
||||
|| {
|
||||
Self::get_bytes(
|
||||
&self.c_byte,
|
||||
[109 - n, 108 - n, 86 - n, 65 - n, 110 - n],
|
||||
)
|
||||
},
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
let (((temp_a, temp_b), (temp_c, a_and)), (b_and, c_and)) = rayon::join(
|
||||
|| {
|
||||
rayon::join(
|
||||
|| rayon::join(|| a4 ^ a5, || b4 ^ b5),
|
||||
|| rayon::join(|| c4 ^ c5 ^ k, || a1 & a2 ^ iv),
|
||||
)
|
||||
},
|
||||
|| rayon::join(|| b1 & b2, || c1 & c2),
|
||||
);
|
||||
|
||||
let (temp_a_2, temp_b_2, temp_c_2) = (temp_a.clone(), temp_b.clone(), temp_c.clone());
|
||||
|
||||
let ((o, a), (b, c)) = rayon::join(
|
||||
|| {
|
||||
rayon::join(
|
||||
|| (temp_a_2 ^ temp_b_2) ^ temp_c_2,
|
||||
|| temp_c ^ ((c_and) ^ a3),
|
||||
)
|
||||
},
|
||||
|| rayon::join(|| temp_a ^ (a_and ^ b3), || temp_b ^ (b_and ^ c3)),
|
||||
);
|
||||
|
||||
[o, a, b, c]
|
||||
}
|
||||
|
||||
/// This calls `get_output_and_values` in parallel 8 times, and stores all results in a Vec.
|
||||
fn get_64_output_and_values(&self) -> Vec<[T; 4]> {
|
||||
(0..8)
|
||||
.into_par_iter()
|
||||
.map(|i| self.get_output_and_values(i))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Computes 64 turns of the stream, outputting the 64 bits (in 8 bytes) all at once in a
|
||||
/// Vec (first value is oldest, last is newest)
|
||||
pub fn next_64(&mut self) -> Vec<T> {
|
||||
match &self.fhe_key {
|
||||
Some(sk) => {
|
||||
rayon::broadcast(|_| set_server_key(sk.clone()));
|
||||
}
|
||||
None => (),
|
||||
}
|
||||
let values = self.get_64_output_and_values();
|
||||
match &self.fhe_key {
|
||||
Some(_) => {
|
||||
rayon::broadcast(|_| unset_server_key());
|
||||
}
|
||||
None => (),
|
||||
}
|
||||
|
||||
let mut bytes = Vec::<T>::with_capacity(8);
|
||||
for [o, a, b, c] in values {
|
||||
self.a_byte.push(a);
|
||||
self.b_byte.push(b);
|
||||
self.c_byte.push(c);
|
||||
bytes.push(o);
|
||||
}
|
||||
self.k_byte.n_shifts(8);
|
||||
self.iv_byte.n_shifts(8);
|
||||
|
||||
bytes
|
||||
}
|
||||
|
||||
/// Reconstructs a bunch of 5 bytes in a parallel fashion.
|
||||
fn get_bytes<const N: usize>(
|
||||
reg: &StaticByteDeque<N, T>,
|
||||
offsets: [usize; 5],
|
||||
) -> (T, T, T, T, T) {
|
||||
let mut ret = offsets
|
||||
.par_iter()
|
||||
.rev()
|
||||
.map(|&i| reg.byte(i))
|
||||
.collect::<Vec<_>>();
|
||||
(
|
||||
ret.pop().unwrap(),
|
||||
ret.pop().unwrap(),
|
||||
ret.pop().unwrap(),
|
||||
ret.pop().unwrap(),
|
||||
ret.pop().unwrap(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl KreyviumStreamByte<FheUint8> {
|
||||
pub fn get_server_key(&self) -> &ServerKey {
|
||||
&self.fhe_key.as_ref().unwrap()
|
||||
}
|
||||
}
|
||||
205
apps/trivium/src/kreyvium/kreyvium_shortint.rs
Normal file
205
apps/trivium/src/kreyvium/kreyvium_shortint.rs
Normal file
@@ -0,0 +1,205 @@
|
||||
use crate::static_deque::StaticDeque;
|
||||
|
||||
use tfhe::shortint::prelude::*;
|
||||
|
||||
use rayon::prelude::*;
|
||||
|
||||
/// KreyviumStreamShortint: a struct implementing the Kreyvium stream cipher, using a generic
|
||||
/// Ciphertext for the internal representation of bits (intended to represent a single bit). To be
|
||||
/// able to compute FHE operations, it also owns a ServerKey.
|
||||
pub struct KreyviumStreamShortint {
|
||||
a: StaticDeque<93, Ciphertext>,
|
||||
b: StaticDeque<84, Ciphertext>,
|
||||
c: StaticDeque<111, Ciphertext>,
|
||||
k: StaticDeque<128, Ciphertext>,
|
||||
iv: StaticDeque<128, Ciphertext>,
|
||||
internal_server_key: ServerKey,
|
||||
transciphering_casting_key: KeySwitchingKey,
|
||||
hl_server_key: tfhe::ServerKey,
|
||||
}
|
||||
|
||||
impl KreyviumStreamShortint {
|
||||
/// Contructor for KreyviumStreamShortint: arguments are the secret key and the input vector,
|
||||
/// and a ServerKey reference. Outputs a KreyviumStream object already initialized (1152
|
||||
/// steps have been run before returning)
|
||||
pub fn new(
|
||||
mut key: [Ciphertext; 128],
|
||||
mut iv: [u64; 128],
|
||||
sk: ServerKey,
|
||||
ksk: KeySwitchingKey,
|
||||
hl_sk: tfhe::ServerKey,
|
||||
) -> Self {
|
||||
// Initialization of Kreyvium registers: a has the secret key, b the input vector,
|
||||
// and c a few ones.
|
||||
let mut a_register: [Ciphertext; 93] = [0; 93].map(|x| sk.create_trivial(x));
|
||||
let mut b_register: [Ciphertext; 84] = [0; 84].map(|x| sk.create_trivial(x));
|
||||
let mut c_register: [Ciphertext; 111] = [0; 111].map(|x| sk.create_trivial(x));
|
||||
|
||||
for i in 0..93 {
|
||||
a_register[i] = key[128 - 93 + i].clone();
|
||||
}
|
||||
for i in 0..84 {
|
||||
b_register[i] = sk.create_trivial(iv[128 - 84 + i]);
|
||||
}
|
||||
for i in 0..44 {
|
||||
c_register[111 - 44 + i] = sk.create_trivial(iv[i]);
|
||||
}
|
||||
for i in 0..66 {
|
||||
c_register[i + 1] = sk.create_trivial(1);
|
||||
}
|
||||
|
||||
key.reverse();
|
||||
iv.reverse();
|
||||
let iv = iv.map(|x| sk.create_trivial(x));
|
||||
|
||||
let mut ret = Self {
|
||||
a: StaticDeque::<93, Ciphertext>::new(a_register),
|
||||
b: StaticDeque::<84, Ciphertext>::new(b_register),
|
||||
c: StaticDeque::<111, Ciphertext>::new(c_register),
|
||||
k: StaticDeque::<128, Ciphertext>::new(key),
|
||||
iv: StaticDeque::<128, Ciphertext>::new(iv),
|
||||
internal_server_key: sk,
|
||||
transciphering_casting_key: ksk,
|
||||
hl_server_key: hl_sk,
|
||||
};
|
||||
ret.init();
|
||||
ret
|
||||
}
|
||||
|
||||
/// The specification of Kreyvium includes running 1152 (= 18*64) unused steps to mix up the
|
||||
/// registers, before starting the proper stream
|
||||
fn init(&mut self) {
|
||||
for _ in 0..18 {
|
||||
self.next_64();
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes one turn of the stream, updating registers and outputting the new bit.
|
||||
pub fn next(&mut self) -> Ciphertext {
|
||||
let [o, a, b, c] = self.get_output_and_values(0);
|
||||
|
||||
self.a.push(a);
|
||||
self.b.push(b);
|
||||
self.c.push(c);
|
||||
|
||||
o
|
||||
}
|
||||
|
||||
/// Computes a potential future step of Kreyvium, n terms in the future. This does not update
|
||||
/// registers, but rather returns with the output, the three values that will be used to
|
||||
/// update the registers, when the time is right. This function is meant to be used in
|
||||
/// parallel.
|
||||
fn get_output_and_values(&self, n: usize) -> [Ciphertext; 4] {
|
||||
let (k, iv) = (&self.k[127 - n], &self.iv[127 - n]);
|
||||
|
||||
let (a1, a2, a3, a4, a5) = (
|
||||
&self.a[65 - n],
|
||||
&self.a[92 - n],
|
||||
&self.a[91 - n],
|
||||
&self.a[90 - n],
|
||||
&self.a[68 - n],
|
||||
);
|
||||
let (b1, b2, b3, b4, b5) = (
|
||||
&self.b[68 - n],
|
||||
&self.b[83 - n],
|
||||
&self.b[82 - n],
|
||||
&self.b[81 - n],
|
||||
&self.b[77 - n],
|
||||
);
|
||||
let (c1, c2, c3, c4, c5) = (
|
||||
&self.c[65 - n],
|
||||
&self.c[110 - n],
|
||||
&self.c[109 - n],
|
||||
&self.c[108 - n],
|
||||
&self.c[86 - n],
|
||||
);
|
||||
|
||||
let temp_a = self.internal_server_key.unchecked_add(a1, a2);
|
||||
let temp_b = self.internal_server_key.unchecked_add(b1, b2);
|
||||
let mut temp_c = self.internal_server_key.unchecked_add(c1, c2);
|
||||
self.internal_server_key
|
||||
.unchecked_add_assign(&mut temp_c, k);
|
||||
|
||||
let ((new_a, new_b), (new_c, o)) = rayon::join(
|
||||
|| {
|
||||
rayon::join(
|
||||
|| {
|
||||
let mut new_a = self.internal_server_key.unchecked_bitand(c3, c4);
|
||||
self.internal_server_key
|
||||
.unchecked_add_assign(&mut new_a, a5);
|
||||
self.internal_server_key.add_assign(&mut new_a, &temp_c);
|
||||
new_a
|
||||
},
|
||||
|| {
|
||||
let mut new_b = self.internal_server_key.unchecked_bitand(a3, a4);
|
||||
self.internal_server_key
|
||||
.unchecked_add_assign(&mut new_b, b5);
|
||||
self.internal_server_key
|
||||
.unchecked_add_assign(&mut new_b, &temp_a);
|
||||
self.internal_server_key.add_assign(&mut new_b, iv);
|
||||
new_b
|
||||
},
|
||||
)
|
||||
},
|
||||
|| {
|
||||
rayon::join(
|
||||
|| {
|
||||
let mut new_c = self.internal_server_key.unchecked_bitand(b3, b4);
|
||||
self.internal_server_key
|
||||
.unchecked_add_assign(&mut new_c, c5);
|
||||
self.internal_server_key
|
||||
.unchecked_add_assign(&mut new_c, &temp_b);
|
||||
self.internal_server_key.clear_carry_assign(&mut new_c);
|
||||
new_c
|
||||
},
|
||||
|| {
|
||||
self.internal_server_key.bitxor(
|
||||
&self.internal_server_key.unchecked_add(&temp_a, &temp_b),
|
||||
&temp_c,
|
||||
)
|
||||
},
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
[o, new_a, new_b, new_c]
|
||||
}
|
||||
|
||||
/// This calls `get_output_and_values` in parallel 64 times, and stores all results in a Vec.
|
||||
fn get_64_output_and_values(&self) -> Vec<[Ciphertext; 4]> {
|
||||
(0..64)
|
||||
.into_par_iter()
|
||||
.map(|x| self.get_output_and_values(x))
|
||||
.rev()
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Computes 64 turns of the stream, outputting the 64 bits all at once in a
|
||||
/// Vec (first value is oldest, last is newest)
|
||||
pub fn next_64(&mut self) -> Vec<Ciphertext> {
|
||||
let mut values = self.get_64_output_and_values();
|
||||
|
||||
let mut ret = Vec::<Ciphertext>::with_capacity(64);
|
||||
while let Some([o, a, b, c]) = values.pop() {
|
||||
ret.push(o);
|
||||
self.a.push(a);
|
||||
self.b.push(b);
|
||||
self.c.push(c);
|
||||
}
|
||||
self.k.n_shifts(64);
|
||||
self.iv.n_shifts(64);
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn get_internal_server_key(&self) -> &ServerKey {
|
||||
&self.internal_server_key
|
||||
}
|
||||
|
||||
pub fn get_casting_key(&self) -> &KeySwitchingKey {
|
||||
&self.transciphering_casting_key
|
||||
}
|
||||
|
||||
pub fn get_hl_server_key(&self) -> &tfhe::ServerKey {
|
||||
&self.hl_server_key
|
||||
}
|
||||
}
|
||||
11
apps/trivium/src/kreyvium/mod.rs
Normal file
11
apps/trivium/src/kreyvium/mod.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
mod kreyvium;
|
||||
pub use kreyvium::KreyviumStream;
|
||||
|
||||
mod kreyvium_byte;
|
||||
pub use kreyvium_byte::KreyviumStreamByte;
|
||||
|
||||
mod kreyvium_shortint;
|
||||
pub use kreyvium_shortint::KreyviumStreamShortint;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
378
apps/trivium/src/kreyvium/test.rs
Normal file
378
apps/trivium/src/kreyvium/test.rs
Normal file
@@ -0,0 +1,378 @@
|
||||
use tfhe::prelude::*;
|
||||
use tfhe::{generate_keys, ConfigBuilder, FheBool, FheUint64, FheUint8};
|
||||
|
||||
use crate::{KreyviumStream, KreyviumStreamByte, KreyviumStreamShortint, TransCiphering};
|
||||
|
||||
// Values for these tests come from the github repo renaud1239/Kreyvium,
|
||||
// commit fd6828f68711276c25f55e605935028f5e843f43
|
||||
|
||||
fn get_hexadecimal_string_from_lsb_first_stream(a: Vec<bool>) -> String {
|
||||
assert!(a.len() % 8 == 0);
|
||||
let mut hexadecimal: String = "".to_string();
|
||||
for test in a.chunks(8) {
|
||||
// Encoding is bytes in LSB order
|
||||
match test[4..8] {
|
||||
[false, false, false, false] => hexadecimal.push('0'),
|
||||
[true, false, false, false] => hexadecimal.push('1'),
|
||||
[false, true, false, false] => hexadecimal.push('2'),
|
||||
[true, true, false, false] => hexadecimal.push('3'),
|
||||
|
||||
[false, false, true, false] => hexadecimal.push('4'),
|
||||
[true, false, true, false] => hexadecimal.push('5'),
|
||||
[false, true, true, false] => hexadecimal.push('6'),
|
||||
[true, true, true, false] => hexadecimal.push('7'),
|
||||
|
||||
[false, false, false, true] => hexadecimal.push('8'),
|
||||
[true, false, false, true] => hexadecimal.push('9'),
|
||||
[false, true, false, true] => hexadecimal.push('A'),
|
||||
[true, true, false, true] => hexadecimal.push('B'),
|
||||
|
||||
[false, false, true, true] => hexadecimal.push('C'),
|
||||
[true, false, true, true] => hexadecimal.push('D'),
|
||||
[false, true, true, true] => hexadecimal.push('E'),
|
||||
[true, true, true, true] => hexadecimal.push('F'),
|
||||
_ => (),
|
||||
};
|
||||
match test[0..4] {
|
||||
[false, false, false, false] => hexadecimal.push('0'),
|
||||
[true, false, false, false] => hexadecimal.push('1'),
|
||||
[false, true, false, false] => hexadecimal.push('2'),
|
||||
[true, true, false, false] => hexadecimal.push('3'),
|
||||
|
||||
[false, false, true, false] => hexadecimal.push('4'),
|
||||
[true, false, true, false] => hexadecimal.push('5'),
|
||||
[false, true, true, false] => hexadecimal.push('6'),
|
||||
[true, true, true, false] => hexadecimal.push('7'),
|
||||
|
||||
[false, false, false, true] => hexadecimal.push('8'),
|
||||
[true, false, false, true] => hexadecimal.push('9'),
|
||||
[false, true, false, true] => hexadecimal.push('A'),
|
||||
[true, true, false, true] => hexadecimal.push('B'),
|
||||
|
||||
[false, false, true, true] => hexadecimal.push('C'),
|
||||
[true, false, true, true] => hexadecimal.push('D'),
|
||||
[false, true, true, true] => hexadecimal.push('E'),
|
||||
[true, true, true, true] => hexadecimal.push('F'),
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
return hexadecimal;
|
||||
}
|
||||
|
||||
fn get_hexagonal_string_from_bytes(a: Vec<u8>) -> String {
|
||||
assert!(a.len() % 8 == 0);
|
||||
let mut hexadecimal: String = "".to_string();
|
||||
for test in a {
|
||||
hexadecimal.push_str(&format!("{:02X?}", test));
|
||||
}
|
||||
return hexadecimal;
|
||||
}
|
||||
|
||||
fn get_hexagonal_string_from_u64(a: Vec<u64>) -> String {
|
||||
let mut hexadecimal: String = "".to_string();
|
||||
for test in a {
|
||||
hexadecimal.push_str(&format!("{:016X?}", test));
|
||||
}
|
||||
return hexadecimal;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kreyvium_test_1() {
|
||||
let key = [false; 128];
|
||||
let iv = [false; 128];
|
||||
let output = "26DCF1F4BC0F1922";
|
||||
|
||||
let mut kreyvium = KreyviumStream::<bool>::new(key, iv);
|
||||
|
||||
let mut vec = Vec::<bool>::with_capacity(64);
|
||||
while vec.len() < 64 {
|
||||
vec.push(kreyvium.next());
|
||||
}
|
||||
|
||||
let hexadecimal = get_hexadecimal_string_from_lsb_first_stream(vec);
|
||||
assert_eq!(output, hexadecimal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kreyvium_test_2() {
|
||||
let mut key = [false; 128];
|
||||
let iv = [false; 128];
|
||||
key[0] = true;
|
||||
|
||||
let output = "4FD421D4DA3D2C8A";
|
||||
|
||||
let mut kreyvium = KreyviumStream::<bool>::new(key, iv);
|
||||
|
||||
let mut vec = Vec::<bool>::with_capacity(64);
|
||||
while vec.len() < 64 {
|
||||
vec.push(kreyvium.next());
|
||||
}
|
||||
|
||||
let hexadecimal = get_hexadecimal_string_from_lsb_first_stream(vec);
|
||||
assert_eq!(output, hexadecimal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kreyvium_test_3() {
|
||||
let key = [false; 128];
|
||||
let mut iv = [false; 128];
|
||||
iv[0] = true;
|
||||
|
||||
let output = "C9217BA0D762ACA1";
|
||||
|
||||
let mut kreyvium = KreyviumStream::<bool>::new(key, iv);
|
||||
|
||||
let mut vec = Vec::<bool>::with_capacity(64);
|
||||
while vec.len() < 64 {
|
||||
vec.push(kreyvium.next());
|
||||
}
|
||||
|
||||
let hexadecimal = get_hexadecimal_string_from_lsb_first_stream(vec);
|
||||
assert_eq!(output, hexadecimal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kreyvium_test_4() {
|
||||
let key_string = "0053A6F94C9FF24598EB000000000000".to_string();
|
||||
let mut key = [false; 128];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
let mut val: u8 = u8::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
key[8 * (i >> 1) + j] = val % 2 == 1;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC000000000000".to_string();
|
||||
let mut iv = [false; 128];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
let mut val: u8 = u8::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
iv[8 * (i >> 1) + j] = val % 2 == 1;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let output = "D1F0303482061111";
|
||||
|
||||
let mut kreyvium = KreyviumStream::<bool>::new(key, iv);
|
||||
|
||||
let mut vec = Vec::<bool>::with_capacity(64);
|
||||
while vec.len() < 64 {
|
||||
vec.push(kreyvium.next());
|
||||
}
|
||||
|
||||
let hexadecimal = get_hexadecimal_string_from_lsb_first_stream(vec);
|
||||
assert_eq!(hexadecimal, output);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kreyvium_test_fhe_long() {
|
||||
let config = ConfigBuilder::all_disabled().enable_default_bool().build();
|
||||
let (client_key, server_key) = generate_keys(config);
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB000000000000".to_string();
|
||||
let mut key = [false; 128];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
let mut val: u8 = u8::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
key[8 * (i >> 1) + j] = val % 2 == 1;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC000000000000".to_string();
|
||||
let mut iv = [false; 128];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
let mut val: u8 = u8::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
iv[8 * (i >> 1) + j] = val % 2 == 1;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let output = "D1F0303482061111";
|
||||
|
||||
let cipher_key = key.map(|x| FheBool::encrypt(x, &client_key));
|
||||
|
||||
let mut kreyvium = KreyviumStream::<FheBool>::new(cipher_key, iv, &server_key);
|
||||
|
||||
let mut vec = Vec::<bool>::with_capacity(64);
|
||||
while vec.len() < 64 {
|
||||
let cipher_outputs = kreyvium.next_64();
|
||||
for c in cipher_outputs {
|
||||
vec.push(c.decrypt(&client_key))
|
||||
}
|
||||
}
|
||||
|
||||
let hexadecimal = get_hexadecimal_string_from_lsb_first_stream(vec);
|
||||
assert_eq!(output, hexadecimal);
|
||||
}
|
||||
|
||||
use tfhe::shortint::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn kreyvium_test_shortint_long() {
|
||||
let config = ConfigBuilder::all_disabled()
|
||||
.enable_default_integers()
|
||||
.build();
|
||||
let (hl_client_key, hl_server_key) = generate_keys(config);
|
||||
let underlying_ck: tfhe::shortint::ClientKey = (*hl_client_key.as_ref()).clone().into();
|
||||
let underlying_sk: tfhe::shortint::ServerKey = (*hl_server_key.as_ref()).clone().into();
|
||||
|
||||
let (client_key, server_key): (ClientKey, ServerKey) = gen_keys(PARAM_MESSAGE_1_CARRY_1);
|
||||
|
||||
let ksk = KeySwitchingKey::new(
|
||||
(&client_key, &server_key),
|
||||
(&underlying_ck, &underlying_sk),
|
||||
PARAM_KEYSWITCH_1_1_TO_2_2,
|
||||
);
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB000000000000".to_string();
|
||||
let mut key = [0; 128];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
let mut val = u64::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
key[8 * (i >> 1) + j] = val % 2;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC000000000000".to_string();
|
||||
let mut iv = [0; 128];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
let mut val = u64::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
iv[8 * (i >> 1) + j] = val % 2;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
let output = "D1F0303482061111".to_string();
|
||||
|
||||
let cipher_key = key.map(|x| client_key.encrypt(x));
|
||||
|
||||
let ciphered_message = FheUint64::try_encrypt(0u64, &hl_client_key).unwrap();
|
||||
|
||||
let mut kreyvium = KreyviumStreamShortint::new(cipher_key, iv, server_key, ksk, hl_server_key);
|
||||
|
||||
let trans_ciphered_message = kreyvium.trans_encrypt_64(ciphered_message);
|
||||
let ciphered_message = trans_ciphered_message.decrypt(&hl_client_key);
|
||||
|
||||
let hexadecimal = get_hexagonal_string_from_u64(vec![ciphered_message]);
|
||||
assert_eq!(output, hexadecimal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kreyvium_test_clear_byte() {
|
||||
let key_string = "0053A6F94C9FF24598EB000000000000".to_string();
|
||||
let mut key_bytes = [0u8; 16];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
key_bytes[i >> 1] = u8::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC000000000000".to_string();
|
||||
let mut iv_bytes = [0u8; 16];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
iv_bytes[i >> 1] = u8::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
}
|
||||
|
||||
let output = "D1F0303482061111".to_string();
|
||||
|
||||
let mut kreyvium = KreyviumStreamByte::<u8>::new(key_bytes, iv_bytes);
|
||||
|
||||
let mut vec = Vec::<u8>::with_capacity(8);
|
||||
while vec.len() < 8 {
|
||||
let outputs = kreyvium.next_64();
|
||||
for c in outputs {
|
||||
vec.push(c)
|
||||
}
|
||||
}
|
||||
|
||||
let hexadecimal = get_hexagonal_string_from_bytes(vec);
|
||||
assert_eq!(output, hexadecimal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kreyvium_test_byte_long() {
|
||||
let config = ConfigBuilder::all_disabled()
|
||||
.enable_default_integers()
|
||||
.enable_function_evaluation_integers()
|
||||
.build();
|
||||
let (client_key, server_key) = generate_keys(config);
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB000000000000".to_string();
|
||||
let mut key_bytes = [0u8; 16];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
key_bytes[i >> 1] = u8::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC000000000000".to_string();
|
||||
let mut iv_bytes = [0u8; 16];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
iv_bytes[i >> 1] = u8::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
}
|
||||
|
||||
let cipher_key = key_bytes.map(|x| FheUint8::encrypt(x, &client_key));
|
||||
|
||||
let output = "D1F0303482061111".to_string();
|
||||
|
||||
let mut kreyvium = KreyviumStreamByte::<FheUint8>::new(cipher_key, iv_bytes, &server_key);
|
||||
|
||||
let mut vec = Vec::<u8>::with_capacity(8);
|
||||
while vec.len() < 8 {
|
||||
let cipher_outputs = kreyvium.next_64();
|
||||
for c in cipher_outputs {
|
||||
vec.push(c.decrypt(&client_key))
|
||||
}
|
||||
}
|
||||
|
||||
let hexadecimal = get_hexagonal_string_from_bytes(vec);
|
||||
assert_eq!(output, hexadecimal);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn kreyvium_test_fhe_byte_transciphering_long() {
|
||||
let config = ConfigBuilder::all_disabled()
|
||||
.enable_default_integers()
|
||||
.enable_function_evaluation_integers()
|
||||
.build();
|
||||
let (client_key, server_key) = generate_keys(config);
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB000000000000".to_string();
|
||||
let mut key = [0u8; 16];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
key[i >> 1] = u8::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC000000000000".to_string();
|
||||
let mut iv = [0u8; 16];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
iv[i >> 1] = u8::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
}
|
||||
|
||||
let output = "D1F0303482061111".to_string();
|
||||
|
||||
let cipher_key = key.map(|x| FheUint8::encrypt(x, &client_key));
|
||||
|
||||
let ciphered_message = FheUint64::try_encrypt(0u64, &client_key).unwrap();
|
||||
|
||||
let mut kreyvium = KreyviumStreamByte::<FheUint8>::new(cipher_key, iv, &server_key);
|
||||
|
||||
let trans_ciphered_message = kreyvium.trans_encrypt_64(ciphered_message);
|
||||
let ciphered_message = trans_ciphered_message.decrypt(&client_key);
|
||||
|
||||
let hexadecimal = get_hexagonal_string_from_u64(vec![ciphered_message]);
|
||||
assert_eq!(output, hexadecimal);
|
||||
}
|
||||
10
apps/trivium/src/lib.rs
Normal file
10
apps/trivium/src/lib.rs
Normal file
@@ -0,0 +1,10 @@
|
||||
mod static_deque;
|
||||
|
||||
mod kreyvium;
|
||||
pub use kreyvium::{KreyviumStream, KreyviumStreamByte, KreyviumStreamShortint};
|
||||
|
||||
mod trivium;
|
||||
pub use trivium::{TriviumStream, TriviumStreamByte, TriviumStreamShortint};
|
||||
|
||||
mod trans_ciphering;
|
||||
pub use trans_ciphering::TransCiphering;
|
||||
4
apps/trivium/src/static_deque/mod.rs
Normal file
4
apps/trivium/src/static_deque/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
mod static_deque;
|
||||
pub use static_deque::StaticDeque;
|
||||
mod static_byte_deque;
|
||||
pub use static_byte_deque::{StaticByteDeque, StaticByteDequeInput};
|
||||
141
apps/trivium/src/static_deque/static_byte_deque.rs
Normal file
141
apps/trivium/src/static_deque/static_byte_deque.rs
Normal file
@@ -0,0 +1,141 @@
|
||||
//! This module implements the StaticByteDeque struct: a deque of bytes. The idea
|
||||
//! is that this is a wrapper around StaticDeque, but StaticByteDeque has an additional
|
||||
//! functionnality: it can construct the "intermediate" bytes, made of parts of other bytes.
|
||||
//! This is pretending to store bits, and allows accessing bits in chunks of 8 consecutive.
|
||||
|
||||
use crate::static_deque::StaticDeque;
|
||||
|
||||
use tfhe::FheUint8;
|
||||
|
||||
/// Internal trait specifying which operations are needed by StaticByteDeque
|
||||
pub trait StaticByteDequeInput<OpOutput>:
|
||||
Clone
|
||||
+ std::ops::Shr<u8, Output = OpOutput>
|
||||
+ std::ops::Shl<u8, Output = OpOutput>
|
||||
+ std::ops::BitOr<Output = OpOutput>
|
||||
{
|
||||
}
|
||||
impl StaticByteDequeInput<u8> for u8 {}
|
||||
impl StaticByteDequeInput<u8> for &u8 {}
|
||||
impl StaticByteDequeInput<FheUint8> for FheUint8 {}
|
||||
impl StaticByteDequeInput<FheUint8> for &FheUint8 {}
|
||||
|
||||
/// Here T must represent a type covering a byte, like u8 or FheUint8.
|
||||
#[derive(Clone)]
|
||||
pub struct StaticByteDeque<const N: usize, T> {
|
||||
deque: StaticDeque<N, T>,
|
||||
}
|
||||
|
||||
impl<const N: usize, T> StaticByteDeque<N, T>
|
||||
where
|
||||
T: StaticByteDequeInput<T>,
|
||||
for<'a> &'a T: StaticByteDequeInput<T>,
|
||||
{
|
||||
/// Constructor always uses a fully initialized array, the first element of
|
||||
/// which is oldest, the last is newest
|
||||
pub fn new(_arr: [T; N]) -> Self {
|
||||
Self {
|
||||
deque: StaticDeque::<N, T>::new(_arr),
|
||||
}
|
||||
}
|
||||
|
||||
/// Elements are pushed via a byte element (covering 8 underlying bits)
|
||||
pub fn push(&mut self, val: T) {
|
||||
self.deque.push(val)
|
||||
}
|
||||
|
||||
/// computes n shift in a row
|
||||
pub fn n_shifts(&mut self, n: usize) {
|
||||
self.deque.n_shifts(n);
|
||||
}
|
||||
|
||||
/// Getter for the internal memory
|
||||
#[allow(dead_code)]
|
||||
fn get_arr(&self) -> &[T; N] {
|
||||
self.deque.get_arr()
|
||||
}
|
||||
|
||||
/// This returns a byte full of zeros, except maybe a one
|
||||
/// at the specified location, if it is present in the deque
|
||||
#[allow(dead_code)]
|
||||
fn bit(&self, i: usize) -> T
|
||||
where
|
||||
for<'a> &'a T: std::ops::BitAnd<u8, Output = T>,
|
||||
{
|
||||
let byte: &T = &self.deque[i / 8];
|
||||
let bit_selector: u8 = 1u8 << (i % 8);
|
||||
byte & bit_selector
|
||||
}
|
||||
|
||||
/// This function reconstructs an intermediate byte if necessary
|
||||
pub fn byte(&self, i: usize) -> T {
|
||||
let byte: &T = &self.deque[i / 8];
|
||||
let bit_idx: u8 = (i % 8) as u8;
|
||||
|
||||
if bit_idx == 0 {
|
||||
return byte.clone();
|
||||
}
|
||||
|
||||
let byte_next: &T = &self.deque[i / 8 + 1];
|
||||
return (byte << bit_idx) | (byte_next >> (8 - bit_idx as u8));
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::static_deque::StaticByteDeque;
|
||||
|
||||
#[test]
|
||||
fn byte_deque_test() {
|
||||
let mut deque = StaticByteDeque::<3, u8>::new([2, 64, 128]);
|
||||
deque.push(4);
|
||||
|
||||
// Youngest: 4
|
||||
assert!(deque.bit(0) == 0);
|
||||
assert!(deque.bit(1) == 0);
|
||||
assert!(deque.bit(2) > 0);
|
||||
assert!(deque.bit(3) == 0);
|
||||
assert!(deque.bit(4) == 0);
|
||||
assert!(deque.bit(5) == 0);
|
||||
assert!(deque.bit(6) == 0);
|
||||
assert!(deque.bit(7) == 0);
|
||||
|
||||
// second youngest: 128
|
||||
assert!(deque.bit(8 + 0) == 0);
|
||||
assert!(deque.bit(8 + 1) == 0);
|
||||
assert!(deque.bit(8 + 2) == 0);
|
||||
assert!(deque.bit(8 + 3) == 0);
|
||||
assert!(deque.bit(8 + 4) == 0);
|
||||
assert!(deque.bit(8 + 5) == 0);
|
||||
assert!(deque.bit(8 + 6) == 0);
|
||||
assert!(deque.bit(8 + 7) > 0);
|
||||
|
||||
// oldest: 64
|
||||
assert!(deque.bit(16 + 0) == 0);
|
||||
assert!(deque.bit(16 + 1) == 0);
|
||||
assert!(deque.bit(16 + 2) == 0);
|
||||
assert!(deque.bit(16 + 3) == 0);
|
||||
assert!(deque.bit(16 + 4) == 0);
|
||||
assert!(deque.bit(16 + 5) == 0);
|
||||
assert!(deque.bit(16 + 6) > 0);
|
||||
assert!(deque.bit(16 + 7) == 0);
|
||||
|
||||
assert_eq!(deque.byte(0), 4u8);
|
||||
assert_eq!(deque.byte(1), 9u8);
|
||||
assert_eq!(deque.byte(2), 18u8);
|
||||
assert_eq!(deque.byte(3), 36u8);
|
||||
assert_eq!(deque.byte(4), 72u8);
|
||||
assert_eq!(deque.byte(5), 144u8);
|
||||
assert_eq!(deque.byte(6), 32u8);
|
||||
assert_eq!(deque.byte(7), 64u8);
|
||||
assert_eq!(deque.byte(8), 128u8);
|
||||
assert_eq!(deque.byte(9), 0u8);
|
||||
assert_eq!(deque.byte(10), 1u8);
|
||||
assert_eq!(deque.byte(11), 2u8);
|
||||
assert_eq!(deque.byte(12), 4u8);
|
||||
assert_eq!(deque.byte(13), 8u8);
|
||||
assert_eq!(deque.byte(14), 16u8);
|
||||
assert_eq!(deque.byte(15), 32u8);
|
||||
assert_eq!(deque.byte(16), 64u8);
|
||||
}
|
||||
}
|
||||
135
apps/trivium/src/static_deque/static_deque.rs
Normal file
135
apps/trivium/src/static_deque/static_deque.rs
Normal file
@@ -0,0 +1,135 @@
|
||||
//! This module implements the StaticDeque struct: a deque utility whose size
|
||||
//! is known at compile time. Construction, push, and indexing are publicly
|
||||
//! available.
|
||||
|
||||
use core::ops::{Index, IndexMut};
|
||||
|
||||
/// StaticDeque: a struct implementing a deque whose size is known at compile time.
|
||||
/// It has 2 members: the static array conatining the data (never empty), and a cursor
|
||||
/// equal to the index of the oldest element (and the next one to be overwritten).
|
||||
#[derive(Clone)]
|
||||
pub struct StaticDeque<const N: usize, T> {
|
||||
arr: [T; N],
|
||||
cursor: usize,
|
||||
}
|
||||
|
||||
impl<const N: usize, T> StaticDeque<N, T> {
|
||||
/// Constructor always uses a fully initialized array, the first element of
|
||||
/// which is oldest, the last is newest
|
||||
pub fn new(_arr: [T; N]) -> Self {
|
||||
Self {
|
||||
arr: _arr,
|
||||
cursor: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Push a new element to the deque, overwriting the oldest at the same time.
|
||||
pub fn push(&mut self, val: T) {
|
||||
self.arr[self.cursor] = val;
|
||||
self.shift();
|
||||
}
|
||||
|
||||
/// Shift: equivalent to pushing the oldest element
|
||||
pub fn shift(&mut self) {
|
||||
self.n_shifts(1);
|
||||
}
|
||||
|
||||
/// computes n shift in a row
|
||||
pub fn n_shifts(&mut self, n: usize) {
|
||||
self.cursor += n;
|
||||
self.cursor %= N;
|
||||
}
|
||||
|
||||
/// Getter for the internal memory
|
||||
#[allow(dead_code)]
|
||||
pub fn get_arr(&self) -> &[T; N] {
|
||||
&self.arr
|
||||
}
|
||||
}
|
||||
|
||||
/// Index trait for the StaticDeque: 0 is the youngest element, N-1 is the oldest,
|
||||
/// and above N will panic.
|
||||
impl<const N: usize, T> Index<usize> for StaticDeque<N, T> {
|
||||
type Output = T;
|
||||
|
||||
/// 0 is youngest
|
||||
fn index(&self, i: usize) -> &T {
|
||||
if i >= N {
|
||||
panic!("Index {:?} too high for size {:?}", i, N);
|
||||
}
|
||||
&self.arr[(N + self.cursor - i - 1) % N]
|
||||
}
|
||||
}
|
||||
/// IndexMut trait for the StaticDeque: 0 is the youngest element, N-1 is the oldest,
|
||||
/// and above N will panic.
|
||||
impl<const N: usize, T> IndexMut<usize> for StaticDeque<N, T> {
|
||||
/// 0 is youngest
|
||||
fn index_mut(&mut self, i: usize) -> &mut T {
|
||||
if i >= N {
|
||||
panic!("Index {:?} too high for size {:?}", i, N);
|
||||
}
|
||||
&mut self.arr[(N + self.cursor - i - 1) % N]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::static_deque::StaticDeque;
|
||||
|
||||
#[test]
|
||||
fn test_static_deque() {
|
||||
let a = [1, 2, 3, 4, 5, 6];
|
||||
|
||||
let mut static_deque = StaticDeque::new(a);
|
||||
for i in 7..11 {
|
||||
static_deque.push(i);
|
||||
}
|
||||
assert_eq!(*static_deque.get_arr(), [7, 8, 9, 10, 5, 6]);
|
||||
|
||||
for i in 11..15 {
|
||||
static_deque.push(i);
|
||||
}
|
||||
assert_eq!(*static_deque.get_arr(), [13, 14, 9, 10, 11, 12]);
|
||||
|
||||
assert_eq!(static_deque[0], 14);
|
||||
assert_eq!(static_deque[1], 13);
|
||||
assert_eq!(static_deque[2], 12);
|
||||
assert_eq!(static_deque[3], 11);
|
||||
assert_eq!(static_deque[4], 10);
|
||||
assert_eq!(static_deque[5], 9);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_static_deque_indexmut() {
|
||||
let a = [1, 2, 3, 4, 5, 6];
|
||||
|
||||
let mut static_deque = StaticDeque::new(a);
|
||||
for i in 7..11 {
|
||||
static_deque.push(i);
|
||||
}
|
||||
assert_eq!(*static_deque.get_arr(), [7, 8, 9, 10, 5, 6]);
|
||||
|
||||
for i in 11..15 {
|
||||
static_deque.push(i);
|
||||
}
|
||||
assert_eq!(*static_deque.get_arr(), [13, 14, 9, 10, 11, 12]);
|
||||
|
||||
static_deque[1] = 100;
|
||||
|
||||
assert_eq!(static_deque[0], 14);
|
||||
assert_eq!(static_deque[1], 100);
|
||||
assert_eq!(static_deque[2], 12);
|
||||
assert_eq!(static_deque[3], 11);
|
||||
assert_eq!(static_deque[4], 10);
|
||||
assert_eq!(static_deque[5], 9);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_static_deque_index_fail() {
|
||||
let a = [1, 2, 3, 4, 5, 6];
|
||||
|
||||
let static_deque = StaticDeque::new(a);
|
||||
let _ = static_deque[6];
|
||||
}
|
||||
}
|
||||
118
apps/trivium/src/trans_ciphering/mod.rs
Normal file
118
apps/trivium/src/trans_ciphering/mod.rs
Normal file
@@ -0,0 +1,118 @@
|
||||
//! This module will contain extensions of some TriviumStream of KreyviumStream objects,
|
||||
//! when trans ciphering is available to them.
|
||||
|
||||
use crate::{KreyviumStreamByte, KreyviumStreamShortint, TriviumStreamByte, TriviumStreamShortint};
|
||||
use tfhe::shortint::Ciphertext;
|
||||
|
||||
use tfhe::{set_server_key, unset_server_key, FheUint64, FheUint8, ServerKey};
|
||||
|
||||
use rayon::prelude::*;
|
||||
|
||||
/// Triat specifying the interface for trans ciphering a FheUint64 object. Since it is meant
|
||||
/// to be used with stream ciphers, encryption and decryption are by default the same.
|
||||
pub trait TransCiphering {
|
||||
fn trans_encrypt_64(&mut self, cipher: FheUint64) -> FheUint64;
|
||||
fn trans_decrypt_64(&mut self, cipher: FheUint64) -> FheUint64 {
|
||||
self.trans_encrypt_64(cipher)
|
||||
}
|
||||
}
|
||||
|
||||
fn transcipher_from_fheu8_stream(
|
||||
stream: Vec<FheUint8>,
|
||||
cipher: FheUint64,
|
||||
fhe_server_key: &ServerKey,
|
||||
) -> FheUint64 {
|
||||
assert_eq!(stream.len(), 8);
|
||||
|
||||
set_server_key(fhe_server_key.clone());
|
||||
rayon::broadcast(|_| set_server_key(fhe_server_key.clone()));
|
||||
|
||||
let ret: FheUint64 = stream
|
||||
.into_par_iter()
|
||||
.enumerate()
|
||||
.map(|(i, x)| &cipher ^ &(FheUint64::cast_from(x) << (8 * (7 - i) as u8)))
|
||||
.reduce_with(|a, b| a | b)
|
||||
.unwrap();
|
||||
|
||||
unset_server_key();
|
||||
rayon::broadcast(|_| unset_server_key());
|
||||
|
||||
ret
|
||||
}
|
||||
|
||||
fn transcipher_from_1_1_stream(
|
||||
stream: Vec<Ciphertext>,
|
||||
cipher: FheUint64,
|
||||
hl_server_key: &ServerKey,
|
||||
internal_server_key: &tfhe::shortint::ServerKey,
|
||||
casting_key: &tfhe::shortint::KeySwitchingKey,
|
||||
) -> FheUint64 {
|
||||
assert_eq!(stream.len(), 64);
|
||||
|
||||
let pairs = (0..32)
|
||||
.into_par_iter()
|
||||
.map(|i| {
|
||||
let byte_idx = 7 - i / 4;
|
||||
let pair_idx = i % 4;
|
||||
|
||||
let b0 = &stream[8 * byte_idx + 2 * pair_idx];
|
||||
let b1 = &stream[8 * byte_idx + 2 * pair_idx + 1];
|
||||
|
||||
casting_key.cast(
|
||||
&internal_server_key
|
||||
.unchecked_add(b0, &internal_server_key.unchecked_scalar_mul(b1, 2)),
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
set_server_key(hl_server_key.clone());
|
||||
let ret = &cipher ^ &FheUint64::try_from(pairs).unwrap();
|
||||
unset_server_key();
|
||||
ret
|
||||
}
|
||||
|
||||
impl TransCiphering for TriviumStreamByte<FheUint8> {
|
||||
/// `TriviumStreamByte<FheUint8>`: since a full step outputs 8 bytes, these bytes
|
||||
/// are each shifted by a number in [0, 8), and XORed with the input cipher
|
||||
fn trans_encrypt_64(&mut self, cipher: FheUint64) -> FheUint64 {
|
||||
transcipher_from_fheu8_stream(self.next_64(), cipher, self.get_server_key())
|
||||
}
|
||||
}
|
||||
|
||||
impl TransCiphering for KreyviumStreamByte<FheUint8> {
|
||||
/// `KreyviumStreamByte<FheUint8>`: since a full step outputs 8 bytes, these bytes
|
||||
/// are each shifted by a number in [0, 8), and XORed with the input cipher
|
||||
fn trans_encrypt_64(&mut self, cipher: FheUint64) -> FheUint64 {
|
||||
transcipher_from_fheu8_stream(self.next_64(), cipher, self.get_server_key())
|
||||
}
|
||||
}
|
||||
|
||||
impl TransCiphering for TriviumStreamShortint {
|
||||
/// TriviumStreamShortint: since a full step outputs 64 shortints, these bits
|
||||
/// are paired 2 by 2 in the HL parameter space and packed in a full word,
|
||||
/// and XORed with the input cipher
|
||||
fn trans_encrypt_64(&mut self, cipher: FheUint64) -> FheUint64 {
|
||||
transcipher_from_1_1_stream(
|
||||
self.next_64(),
|
||||
cipher,
|
||||
self.get_hl_server_key(),
|
||||
self.get_internal_server_key(),
|
||||
self.get_casting_key(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl TransCiphering for KreyviumStreamShortint {
|
||||
/// KreyviumStreamShortint: since a full step outputs 64 shortints, these bits
|
||||
/// are paired 2 by 2 in the HL parameter space and packed in a full word,
|
||||
/// and XORed with the input cipher
|
||||
fn trans_encrypt_64(&mut self, cipher: FheUint64) -> FheUint64 {
|
||||
transcipher_from_1_1_stream(
|
||||
self.next_64(),
|
||||
cipher,
|
||||
self.get_hl_server_key(),
|
||||
self.get_internal_server_key(),
|
||||
self.get_casting_key(),
|
||||
)
|
||||
}
|
||||
}
|
||||
11
apps/trivium/src/trivium/mod.rs
Normal file
11
apps/trivium/src/trivium/mod.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
mod trivium;
|
||||
pub use trivium::TriviumStream;
|
||||
|
||||
mod trivium_byte;
|
||||
pub use trivium_byte::TriviumStreamByte;
|
||||
|
||||
mod trivium_shortint;
|
||||
pub use trivium_shortint::TriviumStreamShortint;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
412
apps/trivium/src/trivium/test.rs
Normal file
412
apps/trivium/src/trivium/test.rs
Normal file
@@ -0,0 +1,412 @@
|
||||
use tfhe::prelude::*;
|
||||
use tfhe::{generate_keys, ConfigBuilder, FheBool, FheUint64, FheUint8};
|
||||
|
||||
use crate::{TransCiphering, TriviumStream, TriviumStreamByte, TriviumStreamShortint};
|
||||
|
||||
// Values for these tests come from the github repo cantora/avr-crypto-lib, commit 2a5b018,
|
||||
// file testvectors/trivium-80.80.test-vectors
|
||||
|
||||
fn get_hexadecimal_string_from_lsb_first_stream(a: Vec<bool>) -> String {
|
||||
assert!(a.len() % 8 == 0);
|
||||
let mut hexadecimal: String = "".to_string();
|
||||
for test in a.chunks(8) {
|
||||
// Encoding is bytes in LSB order
|
||||
match test[4..8] {
|
||||
[false, false, false, false] => hexadecimal.push('0'),
|
||||
[true, false, false, false] => hexadecimal.push('1'),
|
||||
[false, true, false, false] => hexadecimal.push('2'),
|
||||
[true, true, false, false] => hexadecimal.push('3'),
|
||||
|
||||
[false, false, true, false] => hexadecimal.push('4'),
|
||||
[true, false, true, false] => hexadecimal.push('5'),
|
||||
[false, true, true, false] => hexadecimal.push('6'),
|
||||
[true, true, true, false] => hexadecimal.push('7'),
|
||||
|
||||
[false, false, false, true] => hexadecimal.push('8'),
|
||||
[true, false, false, true] => hexadecimal.push('9'),
|
||||
[false, true, false, true] => hexadecimal.push('A'),
|
||||
[true, true, false, true] => hexadecimal.push('B'),
|
||||
|
||||
[false, false, true, true] => hexadecimal.push('C'),
|
||||
[true, false, true, true] => hexadecimal.push('D'),
|
||||
[false, true, true, true] => hexadecimal.push('E'),
|
||||
[true, true, true, true] => hexadecimal.push('F'),
|
||||
_ => (),
|
||||
};
|
||||
match test[0..4] {
|
||||
[false, false, false, false] => hexadecimal.push('0'),
|
||||
[true, false, false, false] => hexadecimal.push('1'),
|
||||
[false, true, false, false] => hexadecimal.push('2'),
|
||||
[true, true, false, false] => hexadecimal.push('3'),
|
||||
|
||||
[false, false, true, false] => hexadecimal.push('4'),
|
||||
[true, false, true, false] => hexadecimal.push('5'),
|
||||
[false, true, true, false] => hexadecimal.push('6'),
|
||||
[true, true, true, false] => hexadecimal.push('7'),
|
||||
|
||||
[false, false, false, true] => hexadecimal.push('8'),
|
||||
[true, false, false, true] => hexadecimal.push('9'),
|
||||
[false, true, false, true] => hexadecimal.push('A'),
|
||||
[true, true, false, true] => hexadecimal.push('B'),
|
||||
|
||||
[false, false, true, true] => hexadecimal.push('C'),
|
||||
[true, false, true, true] => hexadecimal.push('D'),
|
||||
[false, true, true, true] => hexadecimal.push('E'),
|
||||
[true, true, true, true] => hexadecimal.push('F'),
|
||||
_ => (),
|
||||
};
|
||||
}
|
||||
return hexadecimal;
|
||||
}
|
||||
|
||||
fn get_hexagonal_string_from_bytes(a: Vec<u8>) -> String {
|
||||
assert!(a.len() % 8 == 0);
|
||||
let mut hexadecimal: String = "".to_string();
|
||||
for test in a {
|
||||
hexadecimal.push_str(&format!("{:02X?}", test));
|
||||
}
|
||||
return hexadecimal;
|
||||
}
|
||||
|
||||
fn get_hexagonal_string_from_u64(a: Vec<u64>) -> String {
|
||||
let mut hexadecimal: String = "".to_string();
|
||||
for test in a {
|
||||
hexadecimal.push_str(&format!("{:016X?}", test));
|
||||
}
|
||||
return hexadecimal;
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trivium_test_1() {
|
||||
let key = [false; 80];
|
||||
let iv = [false; 80];
|
||||
let output_0_63 = "FBE0BF265859051B517A2E4E239FC97F563203161907CF2DE7A8790FA1B2E9CDF75292030268B7382B4C1A759AA2599A285549986E74805903801A4CB5A5D4F2".to_string();
|
||||
let output_192_255 = "0F1BE95091B8EA857B062AD52BADF47784AC6D9B2E3F85A9D79995043302F0FDF8B76E5BC8B7B4F0AA46CD20DDA04FDD197BC5E1635496828F2DBFB23F6BD5D0".to_string();
|
||||
let output_256_319 = "80F9075437BAC73F696D0ABE3972F5FCE2192E5FCC13C0CB77D0ABA09126838D31A2D38A2087C46304C8A63B54109F679B0B1BC71E72A58D6DD3E0A3FF890D4A".to_string();
|
||||
let output_448_511 = "68450EB0910A98EF1853E0FC1BED8AB6BB08DF5F167D34008C2A85284D4B886DD56883EE92BF18E69121670B4C81A5689C9B0538373D22EB923A28A2DB44C0EB".to_string();
|
||||
|
||||
let mut trivium = TriviumStream::<bool>::new(key, iv);
|
||||
|
||||
let mut vec = Vec::<bool>::with_capacity(512 * 8);
|
||||
while vec.len() < 512 * 8 {
|
||||
vec.push(trivium.next());
|
||||
}
|
||||
|
||||
let hexadecimal = get_hexadecimal_string_from_lsb_first_stream(vec);
|
||||
assert_eq!(output_0_63, hexadecimal[0..64 * 2]);
|
||||
assert_eq!(output_192_255, hexadecimal[192 * 2..256 * 2]);
|
||||
assert_eq!(output_256_319, hexadecimal[256 * 2..320 * 2]);
|
||||
assert_eq!(output_448_511, hexadecimal[448 * 2..512 * 2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trivium_test_2() {
|
||||
let mut key = [false; 80];
|
||||
let iv = [false; 80];
|
||||
key[7] = true;
|
||||
|
||||
let output_0_63 = "38EB86FF730D7A9CAF8DF13A4420540DBB7B651464C87501552041C249F29A64D2FBF515610921EBE06C8F92CECF7F8098FF20CCCC6A62B97BE8EF7454FC80F9".to_string();
|
||||
let output_192_255 = "EAF2625D411F61E41F6BAEEDDD5FE202600BD472F6C9CD1E9134A745D900EF6C023E4486538F09930CFD37157C0EB57C3EF6C954C42E707D52B743AD83CFF297".to_string();
|
||||
let output_256_319 = "9A203CF7B2F3F09C43D188AA13A5A2021EE998C42F777E9B67C3FA221A0AA1B041AA9E86BC2F5C52AFF11F7D9EE480CB1187B20EB46D582743A52D7CD080A24A".to_string();
|
||||
let output_448_511 = "EBF14772061C210843C18CEA2D2A275AE02FCB18E5D7942455FF77524E8A4CA51E369A847D1AEEFB9002FCD02342983CEAFA9D487CC2032B10192CD416310FA4".to_string();
|
||||
|
||||
let mut trivium = TriviumStream::<bool>::new(key, iv);
|
||||
|
||||
let mut vec = Vec::<bool>::with_capacity(512 * 8);
|
||||
while vec.len() < 512 * 8 {
|
||||
vec.push(trivium.next());
|
||||
}
|
||||
|
||||
let hexadecimal = get_hexadecimal_string_from_lsb_first_stream(vec);
|
||||
assert_eq!(output_0_63, hexadecimal[0..64 * 2]);
|
||||
assert_eq!(output_192_255, hexadecimal[192 * 2..256 * 2]);
|
||||
assert_eq!(output_256_319, hexadecimal[256 * 2..320 * 2]);
|
||||
assert_eq!(output_448_511, hexadecimal[448 * 2..512 * 2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trivium_test_3() {
|
||||
let key = [false; 80];
|
||||
let mut iv = [false; 80];
|
||||
iv[7] = true;
|
||||
|
||||
let output_0_63 = "F8901736640549E3BA7D42EA2D07B9F49233C18D773008BD755585B1A8CBAB86C1E9A9B91F1AD33483FD6EE3696D659C9374260456A36AAE11F033A519CBD5D7".to_string();
|
||||
let output_192_255 = "87423582AF64475C3A9C092E32A53C5FE07D35B4C9CA288A89A43DEF3913EA9237CA43342F3F8E83AD3A5C38D463516F94E3724455656A36279E3E924D442F06".to_string();
|
||||
let output_256_319 = "D94389A90E6F3BF2BB4C8B057339AAD8AA2FEA238C29FCAC0D1FF1CB2535A07058BA995DD44CFC54CCEC54A5405B944C532D74E50EA370CDF1BA1CBAE93FC0B5".to_string();
|
||||
let output_448_511 = "4844151714E56A3A2BBFBA426A1D60F9A4F265210A91EC29259AE2035234091C49FFB1893FA102D425C57C39EB4916F6D148DC83EBF7DE51EEB9ABFE045FB282".to_string();
|
||||
|
||||
let mut trivium = TriviumStream::<bool>::new(key, iv);
|
||||
|
||||
let mut vec = Vec::<bool>::with_capacity(512 * 8);
|
||||
while vec.len() < 512 * 8 {
|
||||
vec.push(trivium.next());
|
||||
}
|
||||
|
||||
let hexadecimal = get_hexadecimal_string_from_lsb_first_stream(vec);
|
||||
assert_eq!(output_0_63, hexadecimal[0..64 * 2]);
|
||||
assert_eq!(output_192_255, hexadecimal[192 * 2..256 * 2]);
|
||||
assert_eq!(output_256_319, hexadecimal[256 * 2..320 * 2]);
|
||||
assert_eq!(output_448_511, hexadecimal[448 * 2..512 * 2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trivium_test_4() {
|
||||
let key_string = "0053A6F94C9FF24598EB".to_string();
|
||||
let mut key = [false; 80];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
let mut val: u8 = u8::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
key[8 * (i >> 1) + j] = val % 2 == 1;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC".to_string();
|
||||
let mut iv = [false; 80];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
let mut val: u8 = u8::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
iv[8 * (i >> 1) + j] = val % 2 == 1;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let output_0_63 = "F4CD954A717F26A7D6930830C4E7CF0819F80E03F25F342C64ADC66ABA7F8A8E6EAA49F23632AE3CD41A7BD290A0132F81C6D4043B6E397D7388F3A03B5FE358".to_string();
|
||||
let output_65472_65535 = "C04C24A6938C8AF8A491D5E481271E0E601338F01067A86A795CA493AA4FF265619B8D448B706B7C88EE8395FC79E5B51AB40245BBF7773AE67DF86FCFB71F30".to_string();
|
||||
let output_65536_65599 = "011A0D7EC32FA102C66C164CFCB189AED9F6982E8C7370A6A37414781192CEB155C534C1C8C9E53FDEADF2D3D0577DAD3A8EB2F6E5265F1E831C86844670BC69".to_string();
|
||||
let output_131008_131071 = "48107374A9CE3AAF78221AE77789247CF6896A249ED75DCE0CF2D30EB9D889A0C61C9F480E5C07381DED9FAB2AD54333E82C89BA92E6E47FD828F1A66A8656E0".to_string();
|
||||
|
||||
let mut trivium = TriviumStream::<bool>::new(key, iv);
|
||||
|
||||
let mut vec = Vec::<bool>::with_capacity(131072 * 8);
|
||||
while vec.len() < 131072 * 8 {
|
||||
vec.push(trivium.next());
|
||||
}
|
||||
|
||||
let hexadecimal = get_hexadecimal_string_from_lsb_first_stream(vec);
|
||||
assert_eq!(output_0_63, hexadecimal[0..64 * 2]);
|
||||
assert_eq!(output_65472_65535, hexadecimal[65472 * 2..65536 * 2]);
|
||||
assert_eq!(output_65536_65599, hexadecimal[65536 * 2..65600 * 2]);
|
||||
assert_eq!(output_131008_131071, hexadecimal[131008 * 2..131072 * 2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trivium_test_clear_byte() {
|
||||
let key_string = "0053A6F94C9FF24598EB".to_string();
|
||||
let mut key = [0u8; 10];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
key[i >> 1] = u8::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC".to_string();
|
||||
let mut iv = [0u8; 10];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
iv[i >> 1] = u8::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
}
|
||||
|
||||
let output_0_63 = "F4CD954A717F26A7D6930830C4E7CF0819F80E03F25F342C64ADC66ABA7F8A8E6EAA49F23632AE3CD41A7BD290A0132F81C6D4043B6E397D7388F3A03B5FE358".to_string();
|
||||
let output_65472_65535 = "C04C24A6938C8AF8A491D5E481271E0E601338F01067A86A795CA493AA4FF265619B8D448B706B7C88EE8395FC79E5B51AB40245BBF7773AE67DF86FCFB71F30".to_string();
|
||||
let output_65536_65599 = "011A0D7EC32FA102C66C164CFCB189AED9F6982E8C7370A6A37414781192CEB155C534C1C8C9E53FDEADF2D3D0577DAD3A8EB2F6E5265F1E831C86844670BC69".to_string();
|
||||
let output_131008_131071 = "48107374A9CE3AAF78221AE77789247CF6896A249ED75DCE0CF2D30EB9D889A0C61C9F480E5C07381DED9FAB2AD54333E82C89BA92E6E47FD828F1A66A8656E0".to_string();
|
||||
|
||||
let mut trivium = TriviumStreamByte::<u8>::new(key, iv);
|
||||
|
||||
let mut vec = Vec::<u8>::with_capacity(131072);
|
||||
while vec.len() < 131072 {
|
||||
let outputs = trivium.next_64();
|
||||
for c in outputs {
|
||||
vec.push(c)
|
||||
}
|
||||
}
|
||||
|
||||
let hexadecimal = get_hexagonal_string_from_bytes(vec);
|
||||
assert_eq!(output_0_63, hexadecimal[0..64 * 2]);
|
||||
assert_eq!(output_65472_65535, hexadecimal[65472 * 2..65536 * 2]);
|
||||
assert_eq!(output_65536_65599, hexadecimal[65536 * 2..65600 * 2]);
|
||||
assert_eq!(output_131008_131071, hexadecimal[131008 * 2..131072 * 2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trivium_test_fhe_long() {
|
||||
let config = ConfigBuilder::all_disabled().enable_default_bool().build();
|
||||
let (client_key, server_key) = generate_keys(config);
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB".to_string();
|
||||
let mut key = [false; 80];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
let mut val: u8 = u8::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
key[8 * (i >> 1) + j] = val % 2 == 1;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC".to_string();
|
||||
let mut iv = [false; 80];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
let mut val: u8 = u8::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
iv[8 * (i >> 1) + j] = val % 2 == 1;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let output_0_63 = "F4CD954A717F26A7D6930830C4E7CF0819F80E03F25F342C64ADC66ABA7F8A8E6EAA49F23632AE3CD41A7BD290A0132F81C6D4043B6E397D7388F3A03B5FE358".to_string();
|
||||
|
||||
let cipher_key = key.map(|x| FheBool::encrypt(x, &client_key));
|
||||
|
||||
let mut trivium = TriviumStream::<FheBool>::new(cipher_key, iv, &server_key);
|
||||
|
||||
let mut vec = Vec::<bool>::with_capacity(64 * 8);
|
||||
while vec.len() < 64 * 8 {
|
||||
let cipher_outputs = trivium.next_64();
|
||||
for c in cipher_outputs {
|
||||
vec.push(c.decrypt(&client_key))
|
||||
}
|
||||
}
|
||||
|
||||
let hexadecimal = get_hexadecimal_string_from_lsb_first_stream(vec);
|
||||
assert_eq!(output_0_63, hexadecimal[0..64 * 2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trivium_test_fhe_byte_long() {
|
||||
let config = ConfigBuilder::all_disabled()
|
||||
.enable_default_integers()
|
||||
.build();
|
||||
let (client_key, server_key) = generate_keys(config);
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB".to_string();
|
||||
let mut key = [0u8; 10];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
key[i >> 1] = u8::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC".to_string();
|
||||
let mut iv = [0u8; 10];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
iv[i >> 1] = u8::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
}
|
||||
|
||||
let output_0_63 = "F4CD954A717F26A7D6930830C4E7CF0819F80E03F25F342C64ADC66ABA7F8A8E6EAA49F23632AE3CD41A7BD290A0132F81C6D4043B6E397D7388F3A03B5FE358".to_string();
|
||||
|
||||
let cipher_key = key.map(|x| FheUint8::encrypt(x, &client_key));
|
||||
|
||||
let mut trivium = TriviumStreamByte::<FheUint8>::new(cipher_key, iv, &server_key);
|
||||
|
||||
let mut vec = Vec::<u8>::with_capacity(64);
|
||||
while vec.len() < 64 {
|
||||
let cipher_outputs = trivium.next_64();
|
||||
for c in cipher_outputs {
|
||||
vec.push(c.decrypt(&client_key))
|
||||
}
|
||||
}
|
||||
|
||||
let hexadecimal = get_hexagonal_string_from_bytes(vec);
|
||||
assert_eq!(output_0_63, hexadecimal[0..64 * 2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trivium_test_fhe_byte_transciphering_long() {
|
||||
let config = ConfigBuilder::all_disabled()
|
||||
.enable_default_integers()
|
||||
.build();
|
||||
let (client_key, server_key) = generate_keys(config);
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB".to_string();
|
||||
let mut key = [0u8; 10];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
key[i >> 1] = u8::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC".to_string();
|
||||
let mut iv = [0u8; 10];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
iv[i >> 1] = u8::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
}
|
||||
|
||||
let output_0_63 = "F4CD954A717F26A7D6930830C4E7CF0819F80E03F25F342C64ADC66ABA7F8A8E6EAA49F23632AE3CD41A7BD290A0132F81C6D4043B6E397D7388F3A03B5FE358".to_string();
|
||||
|
||||
let cipher_key = key.map(|x| FheUint8::encrypt(x, &client_key));
|
||||
|
||||
let mut ciphered_message = vec![FheUint64::try_encrypt(0u64, &client_key).unwrap(); 9];
|
||||
|
||||
let mut trivium = TriviumStreamByte::<FheUint8>::new(cipher_key, iv, &server_key);
|
||||
|
||||
let mut vec = Vec::<u64>::with_capacity(8);
|
||||
while vec.len() < 8 {
|
||||
let trans_ciphered_message = trivium.trans_encrypt_64(ciphered_message.pop().unwrap());
|
||||
vec.push(trans_ciphered_message.decrypt(&client_key));
|
||||
}
|
||||
|
||||
let hexadecimal = get_hexagonal_string_from_u64(vec);
|
||||
assert_eq!(output_0_63, hexadecimal[0..64 * 2]);
|
||||
}
|
||||
|
||||
use tfhe::shortint::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn trivium_test_shortint_long() {
|
||||
let config = ConfigBuilder::all_disabled()
|
||||
.enable_default_integers()
|
||||
.build();
|
||||
let (hl_client_key, hl_server_key) = generate_keys(config);
|
||||
let underlying_ck: tfhe::shortint::ClientKey = (*hl_client_key.as_ref()).clone().into();
|
||||
let underlying_sk: tfhe::shortint::ServerKey = (*hl_server_key.as_ref()).clone().into();
|
||||
|
||||
let (client_key, server_key): (ClientKey, ServerKey) = gen_keys(PARAM_MESSAGE_1_CARRY_1);
|
||||
|
||||
let ksk = KeySwitchingKey::new(
|
||||
(&client_key, &server_key),
|
||||
(&underlying_ck, &underlying_sk),
|
||||
PARAM_KEYSWITCH_1_1_TO_2_2,
|
||||
);
|
||||
|
||||
let key_string = "0053A6F94C9FF24598EB".to_string();
|
||||
let mut key = [0; 80];
|
||||
|
||||
for i in (0..key_string.len()).step_by(2) {
|
||||
let mut val = u64::from_str_radix(&key_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
key[8 * (i >> 1) + j] = val % 2;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
let iv_string = "0D74DB42A91077DE45AC".to_string();
|
||||
let mut iv = [0; 80];
|
||||
|
||||
for i in (0..iv_string.len()).step_by(2) {
|
||||
let mut val = u64::from_str_radix(&iv_string[i..i + 2], 16).unwrap();
|
||||
for j in 0..8 {
|
||||
iv[8 * (i >> 1) + j] = val % 2;
|
||||
val >>= 1;
|
||||
}
|
||||
}
|
||||
let output_0_63 = "F4CD954A717F26A7D6930830C4E7CF0819F80E03F25F342C64ADC66ABA7F8A8E6EAA49F23632AE3CD41A7BD290A0132F81C6D4043B6E397D7388F3A03B5FE358".to_string();
|
||||
|
||||
let cipher_key = key.map(|x| client_key.encrypt(x));
|
||||
|
||||
let mut ciphered_message = vec![FheUint64::try_encrypt(0u64, &hl_client_key).unwrap(); 9];
|
||||
|
||||
let mut trivium = TriviumStreamShortint::new(cipher_key, iv, server_key, ksk, hl_server_key);
|
||||
|
||||
let mut vec = Vec::<u64>::with_capacity(8);
|
||||
while vec.len() < 8 {
|
||||
let trans_ciphered_message = trivium.trans_encrypt_64(ciphered_message.pop().unwrap());
|
||||
vec.push(trans_ciphered_message.decrypt(&hl_client_key));
|
||||
}
|
||||
|
||||
let hexadecimal = get_hexagonal_string_from_u64(vec);
|
||||
assert_eq!(output_0_63, hexadecimal[0..64 * 2]);
|
||||
}
|
||||
225
apps/trivium/src/trivium/trivium.rs
Normal file
225
apps/trivium/src/trivium/trivium.rs
Normal file
@@ -0,0 +1,225 @@
|
||||
//! This module implements the Trivium stream cipher, using booleans or FheBool
|
||||
//! for the representaion of the inner bits.
|
||||
|
||||
use crate::static_deque::StaticDeque;
|
||||
|
||||
use tfhe::prelude::*;
|
||||
use tfhe::{set_server_key, unset_server_key, FheBool, ServerKey};
|
||||
|
||||
use rayon::prelude::*;
|
||||
|
||||
/// Internal trait specifying which operations are necessary for TriviumStream generic type
|
||||
pub trait TriviumBoolInput<OpOutput>:
|
||||
Sized
|
||||
+ Clone
|
||||
+ std::ops::BitXor<Output = OpOutput>
|
||||
+ std::ops::BitAnd<Output = OpOutput>
|
||||
+ std::ops::Not<Output = OpOutput>
|
||||
{
|
||||
}
|
||||
impl TriviumBoolInput<bool> for bool {}
|
||||
impl TriviumBoolInput<bool> for &bool {}
|
||||
impl TriviumBoolInput<FheBool> for FheBool {}
|
||||
impl TriviumBoolInput<FheBool> for &FheBool {}
|
||||
|
||||
/// TriviumStream: a struct implementing the Trivium stream cipher, using T for the internal
|
||||
/// representation of bits (bool or FheBool). To be able to compute FHE operations, it also owns
|
||||
/// an Option for a ServerKey.
|
||||
pub struct TriviumStream<T> {
|
||||
a: StaticDeque<93, T>,
|
||||
b: StaticDeque<84, T>,
|
||||
c: StaticDeque<111, T>,
|
||||
fhe_key: Option<ServerKey>,
|
||||
}
|
||||
|
||||
impl TriviumStream<bool> {
|
||||
/// Contructor for `TriviumStream<bool>`: arguments are the secret key and the input vector.
|
||||
/// Outputs a TriviumStream object already initialized (1152 steps have been run before
|
||||
/// returning)
|
||||
pub fn new(key: [bool; 80], iv: [bool; 80]) -> TriviumStream<bool> {
|
||||
// Initialization of Trivium registers: a has the secret key, b the input vector,
|
||||
// and c a few ones.
|
||||
let mut a_register = [false; 93];
|
||||
let mut b_register = [false; 84];
|
||||
let mut c_register = [false; 111];
|
||||
|
||||
for i in 0..80 {
|
||||
a_register[93 - 80 + i] = key[i];
|
||||
b_register[84 - 80 + i] = iv[i];
|
||||
}
|
||||
|
||||
c_register[0] = true;
|
||||
c_register[1] = true;
|
||||
c_register[2] = true;
|
||||
|
||||
TriviumStream::<bool>::new_from_registers(a_register, b_register, c_register, None)
|
||||
}
|
||||
}
|
||||
|
||||
impl TriviumStream<FheBool> {
|
||||
/// Constructor for `TriviumStream<FheBool>`: arguments are the encrypted secret key and input
|
||||
/// vector, and the FHE server key.
|
||||
/// Outputs a TriviumStream object already initialized (1152 steps have been run before
|
||||
/// returning)
|
||||
pub fn new(key: [FheBool; 80], iv: [bool; 80], sk: &ServerKey) -> TriviumStream<FheBool> {
|
||||
set_server_key(sk.clone());
|
||||
|
||||
// Initialization of Trivium registers: a has the secret key, b the input vector,
|
||||
// and c a few ones.
|
||||
let mut a_register = [false; 93].map(|x| FheBool::encrypt_trivial(x));
|
||||
let mut b_register = [false; 84].map(|x| FheBool::encrypt_trivial(x));
|
||||
let mut c_register = [false; 111].map(|x| FheBool::encrypt_trivial(x));
|
||||
|
||||
for i in 0..80 {
|
||||
a_register[93 - 80 + i] = key[i].clone();
|
||||
b_register[84 - 80 + i] = FheBool::encrypt_trivial(iv[i]);
|
||||
}
|
||||
|
||||
c_register[0] = FheBool::try_encrypt_trivial(true).unwrap();
|
||||
c_register[1] = FheBool::try_encrypt_trivial(true).unwrap();
|
||||
c_register[2] = FheBool::try_encrypt_trivial(true).unwrap();
|
||||
|
||||
unset_server_key();
|
||||
TriviumStream::<FheBool>::new_from_registers(
|
||||
a_register,
|
||||
b_register,
|
||||
c_register,
|
||||
Some(sk.clone()),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TriviumStream<T>
|
||||
where
|
||||
T: TriviumBoolInput<T> + std::marker::Send + std::marker::Sync,
|
||||
for<'a> &'a T: TriviumBoolInput<T>,
|
||||
{
|
||||
/// Internal generic contructor: arguments are already prepared registers, and an optional FHE
|
||||
/// server key
|
||||
fn new_from_registers(
|
||||
a_register: [T; 93],
|
||||
b_register: [T; 84],
|
||||
c_register: [T; 111],
|
||||
key: Option<ServerKey>,
|
||||
) -> Self {
|
||||
let mut ret = Self {
|
||||
a: StaticDeque::<93, T>::new(a_register),
|
||||
b: StaticDeque::<84, T>::new(b_register),
|
||||
c: StaticDeque::<111, T>::new(c_register),
|
||||
fhe_key: key,
|
||||
};
|
||||
ret.init();
|
||||
ret
|
||||
}
|
||||
|
||||
/// The specification of Trivium includes running 1152 (= 18*64) unused steps to mix up the
|
||||
/// registers, before starting the proper stream
|
||||
fn init(&mut self) {
|
||||
for _ in 0..18 {
|
||||
self.next_64();
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes one turn of the stream, updating registers and outputting the new bit.
|
||||
pub fn next(&mut self) -> T {
|
||||
match &self.fhe_key {
|
||||
Some(sk) => set_server_key(sk.clone()),
|
||||
None => (),
|
||||
};
|
||||
|
||||
let [o, a, b, c] = self.get_output_and_values(0);
|
||||
|
||||
self.a.push(a);
|
||||
self.b.push(b);
|
||||
self.c.push(c);
|
||||
|
||||
o
|
||||
}
|
||||
|
||||
/// Computes a potential future step of Trivium, n terms in the future. This does not update
|
||||
/// registers, but rather returns with the output, the three values that will be used to
|
||||
/// update the registers, when the time is right. This function is meant to be used in
|
||||
/// parallel.
|
||||
fn get_output_and_values(&self, n: usize) -> [T; 4] {
|
||||
assert!(n < 65);
|
||||
|
||||
let (((temp_a, temp_b), (temp_c, a_and)), (b_and, c_and)) = rayon::join(
|
||||
|| {
|
||||
rayon::join(
|
||||
|| {
|
||||
rayon::join(
|
||||
|| &self.a[65 - n] ^ &self.a[92 - n],
|
||||
|| &self.b[68 - n] ^ &self.b[83 - n],
|
||||
)
|
||||
},
|
||||
|| {
|
||||
rayon::join(
|
||||
|| &self.c[65 - n] ^ &self.c[110 - n],
|
||||
|| &self.a[91 - n] & &self.a[90 - n],
|
||||
)
|
||||
},
|
||||
)
|
||||
},
|
||||
|| {
|
||||
rayon::join(
|
||||
|| &self.b[82 - n] & &self.b[81 - n],
|
||||
|| &self.c[109 - n] & &self.c[108 - n],
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
let ((o, a), (b, c)) = rayon::join(
|
||||
|| {
|
||||
rayon::join(
|
||||
|| &(&temp_a ^ &temp_b) ^ &temp_c,
|
||||
|| &temp_c ^ &(&c_and ^ &self.a[68 - n]),
|
||||
)
|
||||
},
|
||||
|| {
|
||||
rayon::join(
|
||||
|| &temp_a ^ &(&a_and ^ &self.b[77 - n]),
|
||||
|| &temp_b ^ &(&b_and ^ &self.c[86 - n]),
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
[o, a, b, c]
|
||||
}
|
||||
|
||||
/// This calls `get_output_and_values` in parallel 64 times, and stores all results in a Vec.
|
||||
fn get_64_output_and_values(&self) -> Vec<[T; 4]> {
|
||||
(0..64)
|
||||
.into_par_iter()
|
||||
.map(|x| self.get_output_and_values(x))
|
||||
.rev()
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Computes 64 turns of the stream, outputting the 64 bits all at once in a
|
||||
/// Vec (first value is oldest, last is newest)
|
||||
pub fn next_64(&mut self) -> Vec<T> {
|
||||
match &self.fhe_key {
|
||||
Some(sk) => {
|
||||
rayon::broadcast(|_| set_server_key(sk.clone()));
|
||||
}
|
||||
None => (),
|
||||
}
|
||||
let mut values = self.get_64_output_and_values();
|
||||
match &self.fhe_key {
|
||||
Some(_) => {
|
||||
rayon::broadcast(|_| unset_server_key());
|
||||
}
|
||||
None => (),
|
||||
}
|
||||
|
||||
let mut ret = Vec::<T>::with_capacity(64);
|
||||
|
||||
while let Some([o, a, b, c]) = values.pop() {
|
||||
ret.push(o);
|
||||
self.a.push(a);
|
||||
self.b.push(b);
|
||||
self.c.push(c);
|
||||
}
|
||||
ret
|
||||
}
|
||||
}
|
||||
241
apps/trivium/src/trivium/trivium_byte.rs
Normal file
241
apps/trivium/src/trivium/trivium_byte.rs
Normal file
@@ -0,0 +1,241 @@
|
||||
//! This module implements the Trivium stream cipher, using u8 or FheUint8
|
||||
//! for the representaion of the inner bits.
|
||||
|
||||
use crate::static_deque::{StaticByteDeque, StaticByteDequeInput};
|
||||
|
||||
use tfhe::prelude::*;
|
||||
use tfhe::{set_server_key, unset_server_key, FheUint8, ServerKey};
|
||||
|
||||
use rayon::prelude::*;
|
||||
|
||||
/// Internal trait specifying which operations are necessary for TriviumStreamByte generic type
|
||||
pub trait TriviumByteInput<OpOutput>:
|
||||
Sized
|
||||
+ Clone
|
||||
+ Send
|
||||
+ Sync
|
||||
+ StaticByteDequeInput<OpOutput>
|
||||
+ std::ops::BitXor<Output = OpOutput>
|
||||
+ std::ops::BitAnd<Output = OpOutput>
|
||||
+ std::ops::Shr<u8, Output = OpOutput>
|
||||
+ std::ops::Shl<u8, Output = OpOutput>
|
||||
+ std::ops::Add<Output = OpOutput>
|
||||
{
|
||||
}
|
||||
impl TriviumByteInput<u8> for u8 {}
|
||||
impl TriviumByteInput<u8> for &u8 {}
|
||||
impl TriviumByteInput<FheUint8> for FheUint8 {}
|
||||
impl TriviumByteInput<FheUint8> for &FheUint8 {}
|
||||
|
||||
/// TriviumStreamByte: a struct implementing the Trivium stream cipher, using T for the internal
|
||||
/// representation of bits (u8 or FheUint8). To be able to compute FHE operations, it also owns
|
||||
/// an Option for a ServerKey.
|
||||
/// Since the original Trivium registers' sizes are not a multiple of 8, these registers (which
|
||||
/// store byte-like objects) have a size that is the eigth of the closest multiple of 8 above the
|
||||
/// originals' sizes.
|
||||
pub struct TriviumStreamByte<T> {
|
||||
a_byte: StaticByteDeque<12, T>,
|
||||
b_byte: StaticByteDeque<11, T>,
|
||||
c_byte: StaticByteDeque<14, T>,
|
||||
fhe_key: Option<ServerKey>,
|
||||
}
|
||||
|
||||
impl TriviumStreamByte<u8> {
|
||||
/// Contructor for `TriviumStreamByte<u8>`: arguments are the secret key and the input vector.
|
||||
/// Outputs a TriviumStream object already initialized (1152 steps have been run before
|
||||
/// returning)
|
||||
pub fn new(key: [u8; 10], iv: [u8; 10]) -> TriviumStreamByte<u8> {
|
||||
// Initialization of Trivium registers: a has the secret key, b the input vector,
|
||||
// and c a few ones.
|
||||
let mut a_byte_reg = [0u8; 12];
|
||||
let mut b_byte_reg = [0u8; 11];
|
||||
let mut c_byte_reg = [0u8; 14];
|
||||
|
||||
for i in 0..10 {
|
||||
a_byte_reg[12 - 10 + i] = key[i];
|
||||
b_byte_reg[11 - 10 + i] = iv[i];
|
||||
}
|
||||
|
||||
// Magic number 14, aka 00001110: this represents the 3 ones at the beginning of the c
|
||||
// registers, with additional zeros to make the register's size a multiple of 8.
|
||||
c_byte_reg[0] = 14;
|
||||
|
||||
let mut ret =
|
||||
TriviumStreamByte::<u8>::new_from_registers(a_byte_reg, b_byte_reg, c_byte_reg, None);
|
||||
ret.init();
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl TriviumStreamByte<FheUint8> {
|
||||
/// Constructor for `TriviumStream<FheUint8>`: arguments are the encrypted secret key and input
|
||||
/// vector, and the FHE server key.
|
||||
/// Outputs a TriviumStream object already initialized (1152 steps have been run before
|
||||
/// returning)
|
||||
pub fn new(
|
||||
key: [FheUint8; 10],
|
||||
iv: [u8; 10],
|
||||
server_key: &ServerKey,
|
||||
) -> TriviumStreamByte<FheUint8> {
|
||||
set_server_key(server_key.clone());
|
||||
|
||||
// Initialization of Trivium registers: a has the secret key, b the input vector,
|
||||
// and c a few ones.
|
||||
let mut a_byte_reg = [0u8; 12].map(|x| FheUint8::encrypt_trivial(x));
|
||||
let mut b_byte_reg = [0u8; 11].map(|x| FheUint8::encrypt_trivial(x));
|
||||
let mut c_byte_reg = [0u8; 14].map(|x| FheUint8::encrypt_trivial(x));
|
||||
|
||||
for i in 0..10 {
|
||||
a_byte_reg[12 - 10 + i] = key[i].clone();
|
||||
b_byte_reg[11 - 10 + i] = FheUint8::encrypt_trivial(iv[i]);
|
||||
}
|
||||
|
||||
// Magic number 14, aka 00001110: this represents the 3 ones at the beginning of the c
|
||||
// registers, with additional zeros to make the register's size a multiple of 8.
|
||||
c_byte_reg[0] = FheUint8::encrypt_trivial(14u8);
|
||||
|
||||
unset_server_key();
|
||||
let mut ret = TriviumStreamByte::<FheUint8>::new_from_registers(
|
||||
a_byte_reg,
|
||||
b_byte_reg,
|
||||
c_byte_reg,
|
||||
Some(server_key.clone()),
|
||||
);
|
||||
ret.init();
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TriviumStreamByte<T>
|
||||
where
|
||||
T: TriviumByteInput<T> + Send,
|
||||
for<'a> &'a T: TriviumByteInput<T>,
|
||||
{
|
||||
/// Internal generic contructor: arguments are already prepared registers, and an optional FHE
|
||||
/// server key
|
||||
fn new_from_registers(
|
||||
a_register: [T; 12],
|
||||
b_register: [T; 11],
|
||||
c_register: [T; 14],
|
||||
sk: Option<ServerKey>,
|
||||
) -> Self {
|
||||
Self {
|
||||
a_byte: StaticByteDeque::<12, T>::new(a_register),
|
||||
b_byte: StaticByteDeque::<11, T>::new(b_register),
|
||||
c_byte: StaticByteDeque::<14, T>::new(c_register),
|
||||
fhe_key: sk,
|
||||
}
|
||||
}
|
||||
|
||||
/// The specification of Trivium includes running 1152 (= 18*64) unused steps to mix up the
|
||||
/// registers, before starting the proper stream
|
||||
fn init(&mut self) {
|
||||
for _ in 0..18 {
|
||||
self.next_64();
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes 8 potential future step of Trivium, b*8 terms in the future. This does not update
|
||||
/// registers, but rather returns with the output, the three values that will be used to
|
||||
/// update the registers, when the time is right. This function is meant to be used in
|
||||
/// parallel.
|
||||
fn get_output_and_values(&self, b: usize) -> [T; 4] {
|
||||
let n = b * 8 + 7;
|
||||
assert!(n < 65);
|
||||
|
||||
let ((a1, a2, a3, a4, a5), ((b1, b2, b3, b4, b5), (c1, c2, c3, c4, c5))) = rayon::join(
|
||||
|| Self::get_bytes(&self.a_byte, [91 - n, 90 - n, 68 - n, 65 - n, 92 - n]),
|
||||
|| {
|
||||
rayon::join(
|
||||
|| Self::get_bytes(&self.b_byte, [82 - n, 81 - n, 77 - n, 68 - n, 83 - n]),
|
||||
|| Self::get_bytes(&self.c_byte, [109 - n, 108 - n, 86 - n, 65 - n, 110 - n]),
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
let (((temp_a, temp_b), (temp_c, a_and)), (b_and, c_and)) = rayon::join(
|
||||
|| {
|
||||
rayon::join(
|
||||
|| rayon::join(|| a4 ^ a5, || b4 ^ b5),
|
||||
|| rayon::join(|| c4 ^ c5, || a1 & a2),
|
||||
)
|
||||
},
|
||||
|| rayon::join(|| b1 & b2, || c1 & c2),
|
||||
);
|
||||
|
||||
let (temp_a_2, temp_b_2, temp_c_2) = (temp_a.clone(), temp_b.clone(), temp_c.clone());
|
||||
|
||||
let ((o, a), (b, c)) = rayon::join(
|
||||
|| {
|
||||
rayon::join(
|
||||
|| (temp_a_2 ^ temp_b_2) ^ temp_c_2,
|
||||
|| temp_c ^ ((c_and) ^ a3),
|
||||
)
|
||||
},
|
||||
|| rayon::join(|| temp_a ^ (a_and ^ b3), || temp_b ^ (b_and ^ c3)),
|
||||
);
|
||||
|
||||
[o, a, b, c]
|
||||
}
|
||||
|
||||
/// This calls `get_output_and_values` in parallel 8 times, and stores all results in a Vec.
|
||||
fn get_64_output_and_values(&self) -> Vec<[T; 4]> {
|
||||
(0..8)
|
||||
.into_par_iter()
|
||||
.map(|i| self.get_output_and_values(i))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Computes 64 turns of the stream, outputting the 64 bits (in 8 bytes) all at once in a
|
||||
/// Vec (first value is oldest, last is newest)
|
||||
pub fn next_64(&mut self) -> Vec<T> {
|
||||
match &self.fhe_key {
|
||||
Some(sk) => {
|
||||
rayon::broadcast(|_| set_server_key(sk.clone()));
|
||||
}
|
||||
None => (),
|
||||
}
|
||||
let values = self.get_64_output_and_values();
|
||||
match &self.fhe_key {
|
||||
Some(_) => {
|
||||
rayon::broadcast(|_| unset_server_key());
|
||||
}
|
||||
None => (),
|
||||
}
|
||||
|
||||
let mut bytes = Vec::<T>::with_capacity(8);
|
||||
for [o, a, b, c] in values {
|
||||
self.a_byte.push(a);
|
||||
self.b_byte.push(b);
|
||||
self.c_byte.push(c);
|
||||
bytes.push(o);
|
||||
}
|
||||
|
||||
bytes
|
||||
}
|
||||
|
||||
/// Reconstructs a bunch of 5 bytes in a parallel fashion.
|
||||
fn get_bytes<const N: usize>(
|
||||
reg: &StaticByteDeque<N, T>,
|
||||
offsets: [usize; 5],
|
||||
) -> (T, T, T, T, T) {
|
||||
let mut ret = offsets
|
||||
.par_iter()
|
||||
.rev()
|
||||
.map(|&i| reg.byte(i))
|
||||
.collect::<Vec<_>>();
|
||||
(
|
||||
ret.pop().unwrap(),
|
||||
ret.pop().unwrap(),
|
||||
ret.pop().unwrap(),
|
||||
ret.pop().unwrap(),
|
||||
ret.pop().unwrap(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl TriviumStreamByte<FheUint8> {
|
||||
pub fn get_server_key(&self) -> &ServerKey {
|
||||
&self.fhe_key.as_ref().unwrap()
|
||||
}
|
||||
}
|
||||
189
apps/trivium/src/trivium/trivium_shortint.rs
Normal file
189
apps/trivium/src/trivium/trivium_shortint.rs
Normal file
@@ -0,0 +1,189 @@
|
||||
use crate::static_deque::StaticDeque;
|
||||
|
||||
use tfhe::shortint::prelude::*;
|
||||
|
||||
use rayon::prelude::*;
|
||||
|
||||
/// TriviumStreamShortint: a struct implementing the Trivium stream cipher, using a generic
|
||||
/// Ciphertext for the internal representation of bits (intended to represent a single bit). To be
|
||||
/// able to compute FHE operations, it also owns a ServerKey.
|
||||
pub struct TriviumStreamShortint {
|
||||
a: StaticDeque<93, Ciphertext>,
|
||||
b: StaticDeque<84, Ciphertext>,
|
||||
c: StaticDeque<111, Ciphertext>,
|
||||
internal_server_key: ServerKey,
|
||||
transciphering_casting_key: KeySwitchingKey,
|
||||
hl_server_key: tfhe::ServerKey,
|
||||
}
|
||||
|
||||
impl TriviumStreamShortint {
|
||||
/// Contructor for TriviumStreamShortint: arguments are the secret key and the input vector, and
|
||||
/// a ServerKey reference. Outputs a TriviumStream object already initialized (1152 steps
|
||||
/// have been run before returning)
|
||||
pub fn new(
|
||||
key: [Ciphertext; 80],
|
||||
iv: [u64; 80],
|
||||
sk: ServerKey,
|
||||
ksk: KeySwitchingKey,
|
||||
hl_sk: tfhe::ServerKey,
|
||||
) -> Self {
|
||||
// Initialization of Trivium registers: a has the secret key, b the input vector,
|
||||
// and c a few ones.
|
||||
let mut a_register: [Ciphertext; 93] = [0; 93].map(|x| sk.create_trivial(x));
|
||||
let mut b_register: [Ciphertext; 84] = [0; 84].map(|x| sk.create_trivial(x));
|
||||
let mut c_register: [Ciphertext; 111] = [0; 111].map(|x| sk.create_trivial(x));
|
||||
|
||||
for i in 0..80 {
|
||||
a_register[93 - 80 + i] = key[i].clone();
|
||||
b_register[84 - 80 + i] = sk.create_trivial(iv[i]);
|
||||
}
|
||||
|
||||
c_register[0] = sk.create_trivial(1);
|
||||
c_register[1] = sk.create_trivial(1);
|
||||
c_register[2] = sk.create_trivial(1);
|
||||
|
||||
let mut ret = Self {
|
||||
a: StaticDeque::<93, Ciphertext>::new(a_register),
|
||||
b: StaticDeque::<84, Ciphertext>::new(b_register),
|
||||
c: StaticDeque::<111, Ciphertext>::new(c_register),
|
||||
internal_server_key: sk,
|
||||
transciphering_casting_key: ksk,
|
||||
hl_server_key: hl_sk,
|
||||
};
|
||||
ret.init();
|
||||
ret
|
||||
}
|
||||
|
||||
/// The specification of Trivium includes running 1152 (= 18*64) unused steps to mix up the
|
||||
/// registers, before starting the proper stream
|
||||
fn init(&mut self) {
|
||||
for _ in 0..18 {
|
||||
self.next_64();
|
||||
}
|
||||
}
|
||||
|
||||
/// Computes one turn of the stream, updating registers and outputting the new bit.
|
||||
pub fn next(&mut self) -> Ciphertext {
|
||||
let [o, a, b, c] = self.get_output_and_values(0);
|
||||
|
||||
self.a.push(a);
|
||||
self.b.push(b);
|
||||
self.c.push(c);
|
||||
|
||||
o
|
||||
}
|
||||
|
||||
/// Computes a potential future step of Trivium, n terms in the future. This does not update
|
||||
/// registers, but rather returns with the output, the three values that will be used to
|
||||
/// update the registers, when the time is right. This function is meant to be used in
|
||||
/// parallel.
|
||||
fn get_output_and_values(&self, n: usize) -> [Ciphertext; 4] {
|
||||
let (a1, a2, a3, a4, a5) = (
|
||||
&self.a[65 - n],
|
||||
&self.a[92 - n],
|
||||
&self.a[91 - n],
|
||||
&self.a[90 - n],
|
||||
&self.a[68 - n],
|
||||
);
|
||||
let (b1, b2, b3, b4, b5) = (
|
||||
&self.b[68 - n],
|
||||
&self.b[83 - n],
|
||||
&self.b[82 - n],
|
||||
&self.b[81 - n],
|
||||
&self.b[77 - n],
|
||||
);
|
||||
let (c1, c2, c3, c4, c5) = (
|
||||
&self.c[65 - n],
|
||||
&self.c[110 - n],
|
||||
&self.c[109 - n],
|
||||
&self.c[108 - n],
|
||||
&self.c[86 - n],
|
||||
);
|
||||
|
||||
let temp_a = self.internal_server_key.unchecked_add(a1, a2);
|
||||
let temp_b = self.internal_server_key.unchecked_add(b1, b2);
|
||||
let temp_c = self.internal_server_key.unchecked_add(c1, c2);
|
||||
|
||||
let ((new_a, new_b), (new_c, o)) = rayon::join(
|
||||
|| {
|
||||
rayon::join(
|
||||
|| {
|
||||
let mut new_a = self.internal_server_key.unchecked_bitand(c3, c4);
|
||||
self.internal_server_key
|
||||
.unchecked_add_assign(&mut new_a, a5);
|
||||
self.internal_server_key
|
||||
.unchecked_add_assign(&mut new_a, &temp_c);
|
||||
self.internal_server_key.clear_carry_assign(&mut new_a);
|
||||
new_a
|
||||
},
|
||||
|| {
|
||||
let mut new_b = self.internal_server_key.unchecked_bitand(a3, a4);
|
||||
self.internal_server_key
|
||||
.unchecked_add_assign(&mut new_b, b5);
|
||||
self.internal_server_key
|
||||
.unchecked_add_assign(&mut new_b, &temp_a);
|
||||
self.internal_server_key.clear_carry_assign(&mut new_b);
|
||||
new_b
|
||||
},
|
||||
)
|
||||
},
|
||||
|| {
|
||||
rayon::join(
|
||||
|| {
|
||||
let mut new_c = self.internal_server_key.unchecked_bitand(b3, b4);
|
||||
self.internal_server_key
|
||||
.unchecked_add_assign(&mut new_c, c5);
|
||||
self.internal_server_key
|
||||
.unchecked_add_assign(&mut new_c, &temp_b);
|
||||
self.internal_server_key.clear_carry_assign(&mut new_c);
|
||||
new_c
|
||||
},
|
||||
|| {
|
||||
self.internal_server_key.bitxor(
|
||||
&self.internal_server_key.unchecked_add(&temp_a, &temp_b),
|
||||
&temp_c,
|
||||
)
|
||||
},
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
[o, new_a, new_b, new_c]
|
||||
}
|
||||
|
||||
/// This calls `get_output_and_values` in parallel 64 times, and stores all results in a Vec.
|
||||
fn get_64_output_and_values(&self) -> Vec<[Ciphertext; 4]> {
|
||||
(0..64)
|
||||
.into_par_iter()
|
||||
.map(|x| self.get_output_and_values(x))
|
||||
.rev()
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Computes 64 turns of the stream, outputting the 64 bits all at once in a
|
||||
/// Vec (first value is oldest, last is newest)
|
||||
pub fn next_64(&mut self) -> Vec<Ciphertext> {
|
||||
let mut values = self.get_64_output_and_values();
|
||||
|
||||
let mut ret = Vec::<Ciphertext>::with_capacity(64);
|
||||
while let Some([o, a, b, c]) = values.pop() {
|
||||
ret.push(o);
|
||||
self.a.push(a);
|
||||
self.b.push(b);
|
||||
self.c.push(c);
|
||||
}
|
||||
ret
|
||||
}
|
||||
|
||||
pub fn get_internal_server_key(&self) -> &ServerKey {
|
||||
&self.internal_server_key
|
||||
}
|
||||
|
||||
pub fn get_casting_key(&self) -> &KeySwitchingKey {
|
||||
&self.transciphering_casting_key
|
||||
}
|
||||
|
||||
pub fn get_hl_server_key(&self) -> &tfhe::ServerKey {
|
||||
&self.hl_server_key
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user