├── .cargo └── config.toml ├── .github └── workflows │ └── build.yml ├── .gitignore ├── Cargo.toml ├── README.md └── emp-tool ├── Cargo.toml ├── benches ├── aes.rs ├── block.rs ├── ggm.rs ├── hash.rs ├── lpn.rs └── prg.rs ├── examples ├── hash.rs ├── netio.rs └── prg.rs └── src ├── aes.rs ├── block.rs ├── constants.rs ├── ggm_tree.rs ├── hash.rs ├── io_channel.rs ├── io_channel └── net_io_channel.rs ├── lib.rs ├── lpn.rs ├── prg.rs ├── prp.rs ├── sse2neon.rs ├── tkprp.rs └── utils.rs /.cargo/config.toml: -------------------------------------------------------------------------------- 1 | [target.'cfg(any(target_arch = "x86", target_arch = "x86_64"))'] 2 | rustflags = [ 3 | "-C", 4 | "target-cpu=native", 5 | "-C", 6 | "target_feature=+aes,+pclmulqdq", 7 | ] 8 | 9 | [target.'cfg(target_arch = "aarch64")'] 10 | rustflags = ["-C", "target-cpu=native", "-C", "target_feature=+neon,+aes"] 11 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ${{matrix.os}} 16 | 17 | strategy: 18 | matrix: 19 | os: [ubuntu-latest, macos-latest] 20 | rust-toolchain: [stable] 21 | arch: [x86_64] 22 | 23 | steps: 24 | - name: Setup Rust 25 | uses: actions-rs/toolchain@v1 26 | with: 27 | toolchain: ${{matrix.rust-toolchain}} 28 | components: rustfmt 29 | 30 | - name: Check out code 31 | uses: actions/checkout@v3 32 | 33 | - name: Build and test 34 | run: | 35 | cargo fmt -- --check 36 | cargo build --verbose 37 | cargo test --verbose 38 | cargo clippy --verbose 39 | 40 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 8 | Cargo.lock 9 | 10 | # These are backup files generated by rustfmt 11 | **/*.rs.bk 12 | 13 | # MSVC Windows builds of rustc generate these, which store debugging information 14 | *.pdb 15 | 16 | .vscode/ -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "emp-tool" 5 | ] 6 | 7 | [profile.release] 8 | opt-level = 3 9 | debug = true 10 | lto = true 11 | debug-assertions = false 12 | overflow-checks = false 13 | codegen-units = 1 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # emp-rust 2 | Efficient Multi-Party computation toolkit in Rust. 3 | 4 | ## Platforms 5 | emp-rust supports `x86/x86_64` and `aarch64` architectures. To enable AES intrinsics on `aarch64` CPUs, it is recommended to use the nightly version of Rust. 6 | ## Documentation 7 | run 8 | 9 | > `cargo doc --open --no-deps` 10 | 11 | ## Examples 12 | run in one terminal: 13 | 14 | > `cargo run --release --example netio -- --party 1` 15 | 16 | run in another terminal: 17 | 18 | > `cargo run --release --example netio -- --party 2` -------------------------------------------------------------------------------- /emp-tool/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "emp_tool" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 7 | 8 | [dependencies] 9 | rand = { version = "0.8" } 10 | structopt = { version = "0.3.20" } 11 | rand_core = { version = "0.6.4" } 12 | bytemuck = {version = "1.13", features = ["derive"]} 13 | rayon = {version = "1.7.0"} 14 | 15 | [target."cfg(target_arch = \"aarch64\")".dependencies] 16 | sha2 = { version = "0.10.7", features = ["asm"] } 17 | [target."cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))".dependencies] 18 | sha2 = {version = "0.10.7"} 19 | 20 | [dev-dependencies] 21 | rand = { version = "0.8" } 22 | rand_chacha = { version = "0.3" } 23 | criterion = { version = "0.5.1" } 24 | 25 | [[bench]] 26 | name = "block" 27 | harness = false 28 | 29 | [[bench]] 30 | name = "aes" 31 | harness = false 32 | 33 | [[bench]] 34 | name = "hash" 35 | harness = false 36 | 37 | [[bench]] 38 | name = "prg" 39 | harness = false 40 | 41 | [[bench]] 42 | name = "ggm" 43 | harness = false 44 | 45 | [[bench]] 46 | name = "lpn" 47 | harness = false 48 | 49 | [[example]] 50 | name = "netio" 51 | path = "examples/netio.rs" 52 | 53 | [[example]] 54 | name = "prg" 55 | path = "examples/prg.rs" 56 | -------------------------------------------------------------------------------- /emp-tool/benches/aes.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 | 3 | use emp_tool::{aes::Aes, block::Block}; 4 | 5 | fn criterion_benchmark(c: &mut Criterion) { 6 | let x = rand::random::(); 7 | let aes = Aes::new(x); 8 | let blk = rand::random::(); 9 | 10 | c.bench_function("aes::new", move |bench| { 11 | bench.iter(|| { 12 | let z = Aes::new(black_box(x)); 13 | black_box(black_box(z)); 14 | }); 15 | }); 16 | 17 | c.bench_function("aes::encrypt_block", move |bench| { 18 | bench.iter(|| { 19 | let z = aes.encrypt_block(black_box(blk)); 20 | black_box(z); 21 | }); 22 | }); 23 | 24 | c.bench_function("aes::encrypt_many_blocks::<8>", move |bench| { 25 | let key = rand::random::(); 26 | let aes = Aes::new(key); 27 | let blks = rand::random::<[Block; 8]>(); 28 | 29 | bench.iter(|| { 30 | let z = aes.encrypt_many_blocks(black_box(blks)); 31 | black_box(z); 32 | }); 33 | }); 34 | 35 | c.bench_function("aes::encrypt_block_slice::<8>", move |bench| { 36 | let key = rand::random::(); 37 | let aes = Aes::new(key); 38 | let mut blks = rand::random::<[Block; 8]>(); 39 | 40 | bench.iter(|| { 41 | let z = aes.encrypt_block_slice(black_box(&mut blks)); 42 | black_box(z); 43 | }); 44 | }); 45 | 46 | c.bench_function("aes::para_encrypt::<1,8>", move |bench| { 47 | let key = rand::random::(); 48 | let aes = Aes::new(key); 49 | let aes = [aes]; 50 | let mut blks = rand::random::<[Block; 8]>(); 51 | 52 | bench.iter(|| { 53 | let z = Aes::para_encrypt::<1, 8>(black_box(aes), black_box(&mut blks)); 54 | black_box(z); 55 | }); 56 | }); 57 | } 58 | 59 | criterion_group!(benches, criterion_benchmark); 60 | criterion_main!(benches); 61 | -------------------------------------------------------------------------------- /emp-tool/benches/block.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 | 3 | use emp_tool::block::Block; 4 | use rand::{Rng, SeedableRng}; 5 | use rand_chacha::ChaCha12Rng; 6 | 7 | fn criterion_benchmark(c: &mut Criterion) { 8 | let mut rng = ChaCha12Rng::from_entropy(); 9 | let a: [u8; 16] = rng.gen(); 10 | let b: [u8; 16] = rng.gen(); 11 | let a = Block::new(&a); 12 | let b = Block::new(&b); 13 | const SIZE: usize = 1000; 14 | let mut x = Vec::new(); 15 | let mut y = Vec::new(); 16 | for _ in 0..SIZE { 17 | x.push(Block::from(rng.gen::())); 18 | y.push(Block::from(rng.gen::())); 19 | } 20 | let t = x.clone(); 21 | let f = y.clone(); 22 | 23 | let exp = rand::random::(); 24 | 25 | c.bench_function("Block::clmul", move |bench| { 26 | bench.iter(|| { 27 | black_box(black_box(a).clmul(black_box(&b))); 28 | }); 29 | }); 30 | 31 | c.bench_function("Block::xor", move |bench| { 32 | bench.iter(|| { 33 | black_box(a ^ b); 34 | }); 35 | }); 36 | 37 | c.bench_function("Block::or", move |bench| { 38 | bench.iter(|| { 39 | black_box(a | b); 40 | }); 41 | }); 42 | 43 | c.bench_function("Block::and", move |bench| { 44 | bench.iter(|| { 45 | black_box(a & b); 46 | }); 47 | }); 48 | 49 | c.bench_function("Block::default", move |bench| { 50 | bench.iter(|| { 51 | black_box(Block::default()); 52 | }); 53 | }); 54 | 55 | c.bench_function("Block::equal", move |bench| { 56 | bench.iter(|| { 57 | black_box(a == b); 58 | }); 59 | }); 60 | 61 | c.bench_function("Block::gfmul", move |bench| { 62 | bench.iter(|| { 63 | black_box(a.gfmul(&b)); 64 | }); 65 | }); 66 | 67 | c.bench_function("Block::reduce", move |bench| { 68 | bench.iter(|| { 69 | black_box(Block::reduce(&a, &b)); 70 | }); 71 | }); 72 | 73 | c.bench_function("Block::mul", move |bench| { 74 | bench.iter(|| { 75 | black_box(a * b); 76 | }); 77 | }); 78 | 79 | c.bench_function("Block::get_lsb", move |bench| { 80 | bench.iter(|| { 81 | black_box(a.get_lsb()); 82 | }); 83 | }); 84 | 85 | c.bench_function("Block::inn_prod_no_red", move |bench| { 86 | bench.iter(|| { 87 | black_box(Block::inn_prdt_no_red(&x, &y)); 88 | }); 89 | }); 90 | 91 | c.bench_function("Block::inn_prod_red", move |bench| { 92 | bench.iter(|| { 93 | black_box(Block::inn_prdt_red(&t, &f)); 94 | }); 95 | }); 96 | 97 | c.bench_function("Block::pow", move |bench| { 98 | bench.iter(|| { 99 | black_box(a.pow(exp)); 100 | }); 101 | }); 102 | 103 | c.bench_function("Block::inverse", move |bench| { 104 | bench.iter(|| { 105 | black_box(a.inverse()); 106 | }); 107 | }); 108 | 109 | c.bench_function("Block::sigma", move |bench| { 110 | bench.iter(|| { 111 | black_box(Block::sigma(a)); 112 | }); 113 | }); 114 | } 115 | 116 | criterion_group!(benches, criterion_benchmark); 117 | criterion_main!(benches); 118 | -------------------------------------------------------------------------------- /emp-tool/benches/ggm.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 | use emp_tool::{ggm_tree::GgmTree, Block}; 3 | 4 | fn criterion_benchmark(c: &mut Criterion) { 5 | c.bench_function("ggm::gen::16M", move |bench| { 6 | let depth = 24; 7 | let ggm = GgmTree::new(depth); 8 | let mut tree = vec![Block::ZERO; 1 << depth]; 9 | let mut k0 = vec![Block::ZERO; depth]; 10 | let mut k1 = vec![Block::ZERO; depth]; 11 | let seed = rand::random::(); 12 | bench.iter(|| { 13 | black_box(ggm.gen( 14 | black_box(seed), 15 | black_box(&mut tree), 16 | black_box(&mut k0), 17 | black_box(&mut k1), 18 | )); 19 | }); 20 | }); 21 | 22 | c.bench_function("ggm::reconstruction::16M", move |bench| { 23 | let depth = 24; 24 | let ggm = GgmTree::new(depth); 25 | let mut tree = vec![Block::ZERO; 1 << (depth)]; 26 | let k = vec![Block::ZERO; depth]; 27 | let alpha = vec![false; depth]; 28 | bench.iter(|| { 29 | black_box(ggm.reconstruct(black_box(&alpha), black_box(&k), black_box(&mut tree))) 30 | }); 31 | }); 32 | } 33 | 34 | criterion_group!(benches, criterion_benchmark); 35 | criterion_main!(benches); 36 | -------------------------------------------------------------------------------- /emp-tool/benches/hash.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 | 3 | use emp_tool::{ 4 | hash::{CcrHash, CrHash, TccrHash}, 5 | Block, 6 | }; 7 | 8 | fn criterion_benchmark(c: &mut Criterion) { 9 | c.bench_function("hash::cr", move |bench| { 10 | let hash = CrHash::new(); 11 | let i = rand::random::(); 12 | bench.iter(|| { 13 | let z = hash.hash_block(black_box(i)); 14 | black_box(z); 15 | }); 16 | }); 17 | 18 | c.bench_function("hash::cr_blocks::<8>", move |bench| { 19 | let hash = CrHash::new(); 20 | bench.iter(|| { 21 | black_box(hash.hash_many_blocks::<8>([Block::ZERO; 8])); 22 | }); 23 | }); 24 | 25 | c.bench_function("hash::ccr", move |bench| { 26 | let hash = CcrHash::new(); 27 | let i = rand::random::(); 28 | bench.iter(|| { 29 | let z = hash.hash_block(black_box(i)); 30 | black_box(z); 31 | }); 32 | }); 33 | 34 | c.bench_function("hash::ccr_blocks::<8>", move |bench| { 35 | let hash = CcrHash::new(); 36 | bench.iter(|| { 37 | black_box(hash.hash_many_blocks::<8>([Block::ZERO; 8])); 38 | }); 39 | }); 40 | 41 | c.bench_function("hash::tccr", move |bench| { 42 | let hash = TccrHash::new(); 43 | let x = rand::random::(); 44 | let i = rand::random::(); 45 | bench.iter(|| { 46 | let z = hash.hash_block(black_box(x), black_box(i)); 47 | black_box(z); 48 | }); 49 | }); 50 | 51 | c.bench_function("hash::tccr_blocks::<8>", move |bench| { 52 | let hash = TccrHash::new(); 53 | bench.iter(|| { 54 | black_box(hash.hash_many_blocks::<8>([Block::ZERO; 8], [1; 8])); 55 | }); 56 | }); 57 | } 58 | 59 | criterion_group!(benches, criterion_benchmark); 60 | criterion_main!(benches); 61 | -------------------------------------------------------------------------------- /emp-tool/benches/lpn.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 | use emp_tool::{lpn::Lpn, prg::Prg, Block}; 3 | use std::time::Duration; 4 | 5 | fn criterion_benchmark(c: &mut Criterion) { 6 | c.bench_function("lpn-native-small", move |bench| { 7 | let seed = Block::ZERO; 8 | let k = 5_060; 9 | let n = 166_400; 10 | let lpn = Lpn::<10>::new(seed, k); 11 | let mut x = vec![Block::ZERO; k as usize]; 12 | let mut y = vec![Block::ZERO; n]; 13 | let mut prg = Prg::new(); 14 | prg.random_blocks(&mut x); 15 | prg.random_blocks(&mut y); 16 | bench.iter(|| { 17 | black_box(lpn.compute_naive(&mut y, &x)); 18 | }); 19 | }); 20 | 21 | c.bench_function("lpn-native-medium", move |bench| { 22 | let seed = Block::ZERO; 23 | let k = 158_000; 24 | let n = 10_168_320; 25 | let lpn = Lpn::<10>::new(seed, k); 26 | let mut x = vec![Block::ZERO; k as usize]; 27 | let mut y = vec![Block::ZERO; n]; 28 | let mut prg = Prg::new(); 29 | prg.random_blocks(&mut x); 30 | prg.random_blocks(&mut y); 31 | bench.iter(|| { 32 | black_box(lpn.compute_naive(&mut y, &x)); 33 | }); 34 | }); 35 | 36 | c.bench_function("lpn-native-large", move |bench| { 37 | let seed = Block::ZERO; 38 | let k = 588_160; 39 | let n = 10_616_092; 40 | let lpn = Lpn::<10>::new(seed, k); 41 | let mut x = vec![Block::ZERO; k as usize]; 42 | let mut y = vec![Block::ZERO; n]; 43 | let mut prg = Prg::new(); 44 | prg.random_blocks(&mut x); 45 | prg.random_blocks(&mut y); 46 | bench.iter(|| { 47 | black_box(lpn.compute_naive(&mut y, &x)); 48 | }); 49 | }); 50 | 51 | c.bench_function("lpn-rayon-small", move |bench| { 52 | let seed = Block::ZERO; 53 | let k = 5_060; 54 | let n = 166_400; 55 | let lpn = Lpn::<10>::new(seed, k); 56 | let mut x = vec![Block::ZERO; k as usize]; 57 | let mut y = vec![Block::ZERO; n]; 58 | let mut prg = Prg::new(); 59 | prg.random_blocks(&mut x); 60 | prg.random_blocks(&mut y); 61 | bench.iter(|| { 62 | black_box(lpn.compute(&mut y, &x)); 63 | }); 64 | }); 65 | 66 | c.bench_function("lpn-rayon-medium", move |bench| { 67 | let seed = Block::ZERO; 68 | let k = 158_000; 69 | let n = 10_168_320; 70 | let lpn = Lpn::<10>::new(seed, k); 71 | let mut x = vec![Block::ZERO; k as usize]; 72 | let mut y = vec![Block::ZERO; n]; 73 | let mut prg = Prg::new(); 74 | prg.random_blocks(&mut x); 75 | prg.random_blocks(&mut y); 76 | bench.iter(|| { 77 | black_box(lpn.compute(&mut y, &x)); 78 | }); 79 | }); 80 | 81 | c.bench_function("lpn-rayon-large", move |bench| { 82 | let seed = Block::ZERO; 83 | let k = 588_160; 84 | let n = 10_616_092; 85 | let lpn = Lpn::<10>::new(seed, k); 86 | let mut x = vec![Block::ZERO; k as usize]; 87 | let mut y = vec![Block::ZERO; n]; 88 | let mut prg = Prg::new(); 89 | prg.random_blocks(&mut x); 90 | prg.random_blocks(&mut y); 91 | bench.iter(|| { 92 | black_box(lpn.compute(&mut y, &x)); 93 | }); 94 | }); 95 | } 96 | 97 | criterion_group! { 98 | name = lpn; 99 | config = Criterion::default().warm_up_time(Duration::from_millis(1000)).sample_size(10); 100 | targets = criterion_benchmark 101 | } 102 | criterion_main!(lpn); 103 | -------------------------------------------------------------------------------- /emp-tool/benches/prg.rs: -------------------------------------------------------------------------------- 1 | use criterion::{black_box, criterion_group, criterion_main, Criterion}; 2 | 3 | use emp_tool::{prg::Prg, Block}; 4 | use rand_core::RngCore; 5 | 6 | fn criterion_benchmark(c: &mut Criterion) { 7 | c.bench_function("Prg::bool", move |bench| { 8 | let mut prg = Prg::new(); 9 | let mut x = false; 10 | bench.iter(|| { 11 | x = prg.random_bool(); 12 | black_box(x) 13 | }); 14 | }); 15 | 16 | c.bench_function("Prg::bools", move |bench| { 17 | let mut prg = Prg::new(); 18 | let mut x = [false; 10]; 19 | bench.iter(|| { 20 | black_box(prg.random_bools(black_box(&mut x))); 21 | }); 22 | }); 23 | 24 | c.bench_function("Prg::byte", move |bench| { 25 | let mut prg = Prg::new(); 26 | let mut x = 0u8; 27 | bench.iter(|| { 28 | x = prg.random_byte(); 29 | black_box(x); 30 | }); 31 | }); 32 | 33 | c.bench_function("Prg::bytes", move |bench| { 34 | let mut prg = Prg::new(); 35 | let mut x = (0..16 * 1024) 36 | .map(|_| rand::random::()) 37 | .collect::>(); 38 | bench.iter(|| { 39 | prg.fill_bytes(black_box(&mut x)); 40 | }); 41 | }); 42 | 43 | c.bench_function("Prg::block", move |bench| { 44 | let mut prg = Prg::new(); 45 | let mut x = Block::ZERO; 46 | bench.iter(|| { 47 | x = prg.random_block(); 48 | black_box(x); 49 | }); 50 | }); 51 | 52 | c.bench_function("Prg::blocks", move |bench| { 53 | let mut prg = Prg::new(); 54 | let mut x = (0..16 * 1024) 55 | .map(|_| rand::random::()) 56 | .collect::>(); 57 | bench.iter(|| { 58 | prg.random_blocks(black_box(&mut x)); 59 | }); 60 | }); 61 | } 62 | 63 | criterion_group!(benches, criterion_benchmark); 64 | criterion_main!(benches); 65 | -------------------------------------------------------------------------------- /emp-tool/examples/hash.rs: -------------------------------------------------------------------------------- 1 | use std::time::Instant; 2 | 3 | use emp_tool::{hash::Hash, prg::Prg, Block}; 4 | 5 | fn hash_perf() { 6 | let mut length = 2usize; 7 | while length <= 8192 { 8 | let times = 1024 * 1024 * 32 / length; 9 | let mut data = vec![Block::ZERO; length]; 10 | let mut prg = Prg::new(); 11 | prg.random_blocks(&mut data); 12 | 13 | let mut hasher = Hash::new(); 14 | let start = Instant::now(); 15 | for _ in 0..times { 16 | hasher.update_block_slice(&data); 17 | hasher.finalize(); 18 | } 19 | 20 | let interval = start.elapsed().as_micros() as f64; 21 | println!( 22 | "Hash speed with block size {}:\t {}\t Gbps", 23 | length, 24 | ((length * times * 128) as f64) / (interval + 0.0) / 1000.0 25 | ); 26 | length *= 2; 27 | } 28 | } 29 | 30 | pub fn main() { 31 | hash_perf(); 32 | } 33 | -------------------------------------------------------------------------------- /emp-tool/examples/netio.rs: -------------------------------------------------------------------------------- 1 | use std::time::Instant; 2 | 3 | use emp_tool::{ 4 | block::Block, 5 | constants::{ALICE, BOB}, 6 | io_channel::{CommandLineOpt, IOChannel, NetIO}, 7 | }; 8 | use structopt::StructOpt; 9 | 10 | fn netio_perf(io: &mut NetIO, party: usize) { 11 | if party == ALICE { 12 | let mut length = 2usize; 13 | while length <= 8192 * 16 { 14 | let times = 1024 * 1024 * 128 / length; 15 | let start = Instant::now(); 16 | let blks = vec![Block::default(); length]; 17 | for _ in 0..times { 18 | io.send_block_vec(&blks).unwrap(); 19 | } 20 | 21 | let interval = start.elapsed().as_micros() as f64; 22 | println!( 23 | "Loopback speed with block size {}:\t {}\t Gbps", 24 | length, 25 | ((length * times * 128) as f64) / (interval + 0.0) / 1000.0 26 | ); 27 | length *= 2; 28 | } 29 | } else if party == BOB { 30 | let mut length = 2usize; 31 | while length <= 8192 * 16 { 32 | let times = 1024 * 1024 * 128 / length; 33 | for _ in 0..times { 34 | let _blk = io.recv_block_vec(length).unwrap(); 35 | } 36 | length *= 2; 37 | } 38 | } 39 | } 40 | 41 | // Run the main function in two terminals 42 | // cargo run --release --example netio -- --party 1 43 | // cargo run --release --example netio -- --party 2 44 | pub fn main() { 45 | let opt = CommandLineOpt::from_args(); 46 | let party = opt.party; 47 | let is_server = if party == ALICE { true } else { false }; 48 | let mut io = NetIO::new(is_server, "127.0.0.1:12345").unwrap(); 49 | netio_perf(&mut io, party); 50 | } 51 | -------------------------------------------------------------------------------- /emp-tool/examples/prg.rs: -------------------------------------------------------------------------------- 1 | use std::time::Instant; 2 | 3 | use emp_tool::{prg::Prg, Block}; 4 | 5 | fn prg_perf() { 6 | let mut length = 2usize; 7 | while length <= 8192 { 8 | let times = 1024 * 1024 * 32 / length; 9 | let start = Instant::now(); 10 | let mut blks = vec![Block::ZERO; length]; 11 | let mut prg = Prg::new(); 12 | for _ in 0..times { 13 | prg.random_blocks(&mut blks); 14 | } 15 | 16 | let interval = start.elapsed().as_micros() as f64; 17 | println!( 18 | "PRG speed with block size {}:\t {}\t Gbps", 19 | length, 20 | ((length * times * 128) as f64) / (interval + 0.0) / 1000.0 21 | ); 22 | length *= 2; 23 | } 24 | } 25 | 26 | pub fn main() { 27 | prg_perf(); 28 | } 29 | -------------------------------------------------------------------------------- /emp-tool/src/aes.rs: -------------------------------------------------------------------------------- 1 | //! Implement aes128 2 | #[cfg(target_arch = "aarch64")] 3 | use core::arch::aarch64::*; 4 | 5 | #[cfg(target_arch = "x86")] 6 | use core::arch::x86::*; 7 | 8 | #[cfg(target_arch = "x86_64")] 9 | use core::arch::x86_64::*; 10 | 11 | #[cfg(target_arch = "aarch64")] 12 | use crate::sse2neon::AES_SBOX; 13 | 14 | #[cfg(target_arch = "aarch64")] 15 | use crate::{ 16 | _mm_aeskeygenassist_si128, _mm_castps_si128, _mm_castsi128_ps, _mm_cvtsi128_si32, 17 | _mm_shuffle_epi32, _mm_shuffle_ps, _mm_xor_si128, 18 | }; 19 | 20 | use crate::Block; 21 | ///The AES 128 struct 22 | #[derive(Copy, Clone, Debug)] 23 | pub struct Aes([Block; 11]); 24 | 25 | #[allow(unused_macros)] 26 | macro_rules! expand_assist_x86 { 27 | ($v1:ident,$v2:ident,$v3:ident,$v4:ident,$sc:expr,$ac:expr) => { 28 | $v2 = _mm_aeskeygenassist_si128($v4, $ac); 29 | $v3 = _mm_castps_si128(_mm_shuffle_ps( 30 | _mm_castsi128_ps($v3), 31 | _mm_castsi128_ps($v1), 32 | 16, 33 | )); 34 | $v1 = _mm_xor_si128($v1, $v3); 35 | $v3 = _mm_castps_si128(_mm_shuffle_ps( 36 | _mm_castsi128_ps($v3), 37 | _mm_castsi128_ps($v1), 38 | 140, 39 | )); 40 | $v1 = _mm_xor_si128($v1, $v3); 41 | $v2 = _mm_shuffle_epi32($v2, $sc); 42 | $v1 = _mm_xor_si128($v1, $v2); 43 | }; 44 | } 45 | 46 | #[allow(unused_macros)] 47 | macro_rules! expand_assist_arm { 48 | ($v1:expr,$v2:expr,$v3:expr,$v4:expr, $sc:expr,$ac:expr) => { 49 | $v2 = _mm_aeskeygenassist_si128!($v4, $ac); 50 | $v3 = _mm_castps_si128!(_mm_shuffle_ps!( 51 | _mm_castsi128_ps!($v3), 52 | _mm_castsi128_ps!($v1), 53 | 16 54 | )); 55 | $v1 = _mm_xor_si128!($v1, $v3); 56 | $v3 = _mm_castps_si128!(_mm_shuffle_ps!( 57 | _mm_castsi128_ps!($v3), 58 | _mm_castsi128_ps!($v1), 59 | 140 60 | )); 61 | $v1 = _mm_xor_si128!($v1, $v3); 62 | $v2 = _mm_shuffle_epi32!($v2, $sc); 63 | $v1 = _mm_xor_si128!($v1, $v2); 64 | }; 65 | } 66 | 67 | impl Aes { 68 | // /// The AES_BLOCK_SIZE. 69 | // pub const AES_BLOCK_SIZE: usize = 8; 70 | 71 | /// New an AES instance 72 | #[inline(always)] 73 | pub fn new(key: Block) -> Self { 74 | unsafe { Aes::aes_init(key) } 75 | } 76 | 77 | #[inline] 78 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 79 | #[target_feature(enable = "aes")] 80 | unsafe fn aes_init(key: Block) -> Self { 81 | let mut kp = [Block::default(); 11]; 82 | kp[0] = key; 83 | let mut x0 = key.0; 84 | let mut _x1 = _mm_setzero_si128(); 85 | let mut x2 = _mm_setzero_si128(); 86 | 87 | expand_assist_x86!(x0, _x1, x2, x0, 255, 1); 88 | kp[1] = Block(x0); 89 | 90 | expand_assist_x86!(x0, _x1, x2, x0, 255, 2); 91 | kp[2] = Block(x0); 92 | 93 | expand_assist_x86!(x0, _x1, x2, x0, 255, 4); 94 | kp[3] = Block(x0); 95 | 96 | expand_assist_x86!(x0, _x1, x2, x0, 255, 8); 97 | kp[4] = Block(x0); 98 | 99 | expand_assist_x86!(x0, _x1, x2, x0, 255, 16); 100 | kp[5] = Block(x0); 101 | 102 | expand_assist_x86!(x0, _x1, x2, x0, 255, 32); 103 | kp[6] = Block(x0); 104 | 105 | expand_assist_x86!(x0, _x1, x2, x0, 255, 64); 106 | kp[7] = Block(x0); 107 | 108 | expand_assist_x86!(x0, _x1, x2, x0, 255, 128); 109 | kp[8] = Block(x0); 110 | 111 | expand_assist_x86!(x0, _x1, x2, x0, 255, 27); 112 | kp[9] = Block(x0); 113 | 114 | expand_assist_x86!(x0, _x1, x2, x0, 255, 54); 115 | kp[10] = Block(x0); 116 | Self(kp) 117 | } 118 | 119 | #[inline] 120 | #[cfg(target_arch = "aarch64")] 121 | #[target_feature(enable = "aes")] 122 | unsafe fn aes_init(key: Block) -> Self { 123 | let mut kp = [Block::default(); 11]; 124 | kp[0] = key; 125 | let mut x0 = key.0; 126 | let mut _x1 = vdupq_n_u8(0); 127 | let mut x2 = vdupq_n_u8(0); 128 | 129 | expand_assist_arm!(x0, _x1, x2, x0, 255, 1); 130 | kp[1] = Block(x0); 131 | 132 | expand_assist_arm!(x0, _x1, x2, x0, 255, 2); 133 | kp[2] = Block(x0); 134 | 135 | expand_assist_arm!(x0, _x1, x2, x0, 255, 4); 136 | kp[3] = Block(x0); 137 | 138 | expand_assist_arm!(x0, _x1, x2, x0, 255, 8); 139 | kp[4] = Block(x0); 140 | 141 | expand_assist_arm!(x0, _x1, x2, x0, 255, 16); 142 | kp[5] = Block(x0); 143 | 144 | expand_assist_arm!(x0, _x1, x2, x0, 255, 32); 145 | kp[6] = Block(x0); 146 | 147 | expand_assist_arm!(x0, _x1, x2, x0, 255, 64); 148 | kp[7] = Block(x0); 149 | 150 | expand_assist_arm!(x0, _x1, x2, x0, 255, 128); 151 | kp[8] = Block(x0); 152 | 153 | expand_assist_arm!(x0, _x1, x2, x0, 255, 27); 154 | kp[9] = Block(x0); 155 | 156 | expand_assist_arm!(x0, _x1, x2, x0, 255, 54); 157 | kp[10] = Block(x0); 158 | Self(kp) 159 | } 160 | 161 | /// Encrypt one block. 162 | #[inline(always)] 163 | pub fn encrypt_block(&self, blk: Block) -> Block { 164 | unsafe { self.encrypt_backend(blk) } 165 | } 166 | 167 | #[inline] 168 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 169 | #[target_feature(enable = "aes")] 170 | unsafe fn encrypt_backend(&self, blk: Block) -> Block { 171 | let mut ctxt = _mm_xor_si128(blk.0, self.0[0].0); 172 | 173 | for key in self.0[1..10].iter() { 174 | ctxt = _mm_aesenc_si128(ctxt, key.0); 175 | } 176 | 177 | ctxt = _mm_aesenclast_si128(ctxt, self.0[10].0); 178 | Block(ctxt) 179 | } 180 | 181 | #[inline] 182 | #[cfg(target_arch = "aarch64")] 183 | #[target_feature(enable = "aes")] 184 | unsafe fn encrypt_backend(&self, blk: Block) -> Block { 185 | let mut ctxt = blk.0; 186 | 187 | for key in self.0.iter().take(9) { 188 | ctxt = vaesmcq_u8(vaeseq_u8(ctxt, key.0)); 189 | } 190 | 191 | ctxt = veorq_u8(vaeseq_u8(ctxt, self.0[9].0), self.0[10].0); 192 | Block(ctxt) 193 | } 194 | 195 | /// Encrypt many blocks 196 | #[inline(always)] 197 | pub fn encrypt_many_blocks(&self, blks: [Block; N]) -> [Block; N] { 198 | unsafe { self.unsafe_encrypt_many_blocks::(blks) } 199 | } 200 | 201 | #[inline] 202 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 203 | #[target_feature(enable = "aes")] 204 | unsafe fn unsafe_encrypt_many_blocks(&self, blks: [Block; N]) -> [Block; N] { 205 | let mut ctxt = blks.map(|x| x.0); 206 | for ct in ctxt.iter_mut() { 207 | *ct = _mm_xor_si128(*ct, self.0[0].0); 208 | } 209 | 210 | for key in self.0[1..10].iter() { 211 | for ct in ctxt.iter_mut() { 212 | *ct = _mm_aesenc_si128(*ct, key.0); 213 | } 214 | } 215 | 216 | for ct in ctxt.iter_mut() { 217 | *ct = _mm_aesenclast_si128(*ct, self.0[10].0); 218 | } 219 | 220 | ctxt.map(|x| Block(x)) 221 | } 222 | 223 | #[inline] 224 | #[cfg(target_arch = "aarch64")] 225 | #[target_feature(enable = "aes")] 226 | unsafe fn unsafe_encrypt_many_blocks(&self, blks: [Block; N]) -> [Block; N] { 227 | let mut ctxt = blks.map(|x| x.0); 228 | 229 | for key in self.0.iter().take(9) { 230 | for ct in ctxt.iter_mut() { 231 | *ct = vaesmcq_u8(vaeseq_u8(*ct, key.0)); 232 | } 233 | } 234 | 235 | for ct in ctxt.iter_mut() { 236 | *ct = veorq_u8(vaeseq_u8(*ct, self.0[9].0), self.0[10].0); 237 | } 238 | 239 | ctxt.map(Block) 240 | } 241 | 242 | /// Encrypt block slice 243 | #[inline(always)] 244 | pub fn encrypt_block_slice(&self, blks: &mut [Block]) { 245 | let len = blks.len(); 246 | let mut buf = [Block::ZERO; 8]; 247 | for i in 0..len / 8 { 248 | buf.copy_from_slice(&blks[i * 8..(i + 1) * 8]); 249 | blks[i * 8..(i + 1) * 8].copy_from_slice(&self.encrypt_many_blocks(buf)); 250 | } 251 | 252 | let remain = len % 8; 253 | if remain > 0 { 254 | macro_rules! encrypt_some { 255 | ($n:expr) => {{ 256 | if remain == $n { 257 | let mut buf = [Block::ZERO; $n]; 258 | buf.copy_from_slice(&blks[len - remain..]); 259 | blks[len - remain..].copy_from_slice(&self.encrypt_many_blocks(buf)); 260 | } 261 | }}; 262 | } 263 | encrypt_some!(1); 264 | encrypt_some!(2); 265 | encrypt_some!(3); 266 | encrypt_some!(4); 267 | encrypt_some!(5); 268 | encrypt_some!(6); 269 | encrypt_some!(7); 270 | } 271 | } 272 | 273 | /// Encrypt many blocks with many keys. 274 | /// Input: `NK` AES keys `keys`, and `NK * NM` blocks `blks` 275 | /// Output: each batch of NM blocks encrypted by a corresponding AES key. 276 | /// Only handle the first `NK * NM` blocks of blks, do not handle the rest. 277 | #[inline(always)] 278 | pub fn para_encrypt(keys: [Self; NK], blks: &mut [Block]) { 279 | assert!(blks.len() >= NM * NK); 280 | let mut ctxt = [Block::default(); NM]; 281 | keys.iter().enumerate().for_each(|(i, key)| { 282 | ctxt.copy_from_slice(&blks[i * NM..(i + 1) * NM]); 283 | blks[i * NM..(i + 1) * NM].copy_from_slice(&key.encrypt_many_blocks(ctxt)) 284 | }); 285 | } 286 | } 287 | 288 | #[test] 289 | fn aes_test() { 290 | let aes = Aes::new(Block::default()); 291 | let c = aes.encrypt_block(Block::default()); 292 | let res = Block::from(0x2e2b34ca59fa4c883b2c8aefd44be966); 293 | assert_eq!(c, res); 294 | 295 | macro_rules! encrypt_test { 296 | ($n:expr) => {{ 297 | let blks = [Block::default(); $n]; 298 | 299 | let d = aes.encrypt_many_blocks(blks); 300 | assert_eq!(d, [res; $n]); 301 | 302 | let mut f = [Block::default(); $n]; 303 | aes.encrypt_block_slice(&mut f); 304 | assert_eq!(f, [res; $n]); 305 | }}; 306 | } 307 | encrypt_test!(1); 308 | encrypt_test!(2); 309 | encrypt_test!(3); 310 | encrypt_test!(4); 311 | encrypt_test!(5); 312 | encrypt_test!(6); 313 | encrypt_test!(7); 314 | encrypt_test!(8); 315 | encrypt_test!(9); 316 | 317 | let aes1 = Aes::new(Block::ONES); 318 | let mut blks = [Block::default(); 4]; 319 | blks[1] = Block::ONES; 320 | blks[3] = Block::ONES; 321 | Aes::para_encrypt::<2, 2>([aes, aes1], &mut blks); 322 | assert_eq!( 323 | blks, 324 | [ 325 | Block::from(0x2E2B34CA59FA4C883B2C8AEFD44BE966), 326 | Block::from(0x4E668D3ED24773FA0A5A85EAC98C5B3F), 327 | Block::from(0x2CC9BF3845486489CD5F7D878C25F6A1), 328 | Block::from(0x79B93A19527051B230CF80B27C21BFBC) 329 | ] 330 | ); 331 | } 332 | -------------------------------------------------------------------------------- /emp-tool/src/block.rs: -------------------------------------------------------------------------------- 1 | //! Define a 128-bit chunk type and related operations. 2 | 3 | use bytemuck::{Pod, Zeroable}; 4 | use core::mem; 5 | use std::{ 6 | fmt::{Debug, Display}, 7 | ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Mul, MulAssign}, 8 | }; 9 | 10 | #[cfg(target_arch = "aarch64")] 11 | use core::arch::aarch64::*; 12 | 13 | #[cfg(target_arch = "x86")] 14 | use core::arch::x86::*; 15 | 16 | #[cfg(target_arch = "x86_64")] 17 | use core::arch::x86_64::*; 18 | 19 | #[cfg(target_arch = "aarch64")] 20 | use crate::{_mm_and_si128, _mm_shuffle_epi32, _mm_xor_si128}; 21 | 22 | /// A 128-bit chunk type.\ 23 | /// It is also viewed as an element in `GF(2^128)` with polynomial `x^128 + x^7 + x^2 + x + 1`\ 24 | /// Use intrinsics whenever available to speedup.\ 25 | /// Now support aarch64 and x86/x86_64 26 | #[cfg(target_arch = "aarch64")] 27 | #[derive(Clone, Copy)] 28 | #[repr(transparent)] 29 | pub struct Block(pub uint8x16_t); 30 | 31 | /// A 128-bit chunk type.\ 32 | /// It is also viewed as an element in `GF(2^128)` with polynomial `x^128 + x^7 + x^2 + x + 1`\ 33 | /// Use intrinsics whenever available to speedup.\ 34 | /// Now support aarch64 and x86/x86_64 35 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 36 | #[derive(Clone, Copy)] 37 | #[repr(transparent)] 38 | pub struct Block(pub __m128i); 39 | 40 | unsafe impl Pod for Block {} 41 | unsafe impl Zeroable for Block {} 42 | 43 | impl Block { 44 | /// The constant block with value `0`. 45 | pub const ZERO: Block = Block(unsafe { mem::transmute(0u128) }); 46 | 47 | /// The constant block with value `0xFFFF_FFFF_FFFF_FFFF`. 48 | pub const ONES: Block = Block(unsafe { mem::transmute(u128::MAX) }); 49 | 50 | /// The select array with `ZERO_BLOCK` and `ONES_BLOCK`. 51 | pub const SELECT_MASK: [Block; 2] = [Block::ZERO, Block::ONES]; 52 | 53 | #[inline(always)] 54 | /// New a Block with a byte slice with length 16. 55 | pub fn new(bytes: &[u8; 16]) -> Self { 56 | #[cfg(target_arch = "aarch64")] 57 | unsafe { 58 | Self(vld1q_u8(bytes.as_ptr())) 59 | } 60 | 61 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 62 | unsafe { 63 | Self(_mm_loadu_si128(bytes.as_ptr() as *const __m128i)) 64 | } 65 | } 66 | 67 | /// Compute the carry-less multiplication of two field elements. 68 | /// The output consists of two Blocks. 69 | #[inline(always)] 70 | pub fn clmul(self, x: &Self) -> (Self, Self) { 71 | unsafe { self.clmul_unsafe(x) } 72 | } 73 | 74 | #[inline] 75 | #[cfg(target_arch = "aarch64")] 76 | #[target_feature(enable = "neon")] 77 | unsafe fn clmul_unsafe(self, x: &Self) -> (Self, Self) { 78 | let h = self.0; 79 | let y = x.0; 80 | let z = vdupq_n_u8(0); 81 | 82 | let a_lo = mem::transmute(vget_low_u64(vreinterpretq_u64_u8(h))); 83 | let a_hi = mem::transmute(vget_high_u64(vreinterpretq_u64_u8(h))); 84 | let b_lo = mem::transmute(vget_low_u64(vreinterpretq_u64_u8(y))); 85 | let b_hi = mem::transmute(vget_high_u64(vreinterpretq_u64_u8(y))); 86 | 87 | let tmp3 = mem::transmute(vmull_p64(a_lo, b_lo)); 88 | let tmp4 = mem::transmute(vmull_p64(a_hi, b_lo)); 89 | let tmp5 = mem::transmute(vmull_p64(a_lo, b_hi)); 90 | let tmp6 = mem::transmute(vmull_p64(a_hi, b_hi)); 91 | 92 | let tmp4 = veorq_u8(tmp4, tmp5); 93 | let tmp5 = vextq_u8(z, tmp4, 8); 94 | let tmp3 = veorq_u8(tmp3, tmp5); 95 | let tmp4 = vextq_u8(tmp4, z, 8); 96 | let tmp6 = veorq_u8(tmp6, tmp4); 97 | 98 | (Block(tmp3), Block(tmp6)) 99 | } 100 | 101 | #[inline] 102 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 103 | #[target_feature(enable = "pclmulqdq")] 104 | unsafe fn clmul_unsafe(self, x: &Self) -> (Block, Block) { 105 | unsafe { 106 | let h = self.0; 107 | let y = x.0; 108 | 109 | let tmp3 = _mm_clmulepi64_si128(h, y, 0x00); 110 | let tmp4 = _mm_clmulepi64_si128(h, y, 0x10); 111 | let tmp5 = _mm_clmulepi64_si128(h, y, 0x01); 112 | let tmp6 = _mm_clmulepi64_si128(h, y, 0x11); 113 | 114 | let tmp4 = _mm_xor_si128(tmp4, tmp5); 115 | let tmp5 = _mm_slli_si128(tmp4, 8); 116 | let tmp4 = _mm_srli_si128(tmp4, 8); 117 | let tmp3 = _mm_xor_si128(tmp3, tmp5); 118 | let tmp6 = _mm_xor_si128(tmp6, tmp4); 119 | (Block(tmp3), Block(tmp6)) 120 | } 121 | } 122 | 123 | /// The multiplication of two field elements. 124 | #[inline(always)] 125 | pub fn gfmul(self, x: &Self) -> Self { 126 | let (a, b) = self.clmul(x); 127 | Block::reduce(&a, &b) 128 | } 129 | 130 | /// Reduce the long polynomial (consists of two Blocks) with `x^128 + x^7 + x^2 + x + 1` 131 | #[inline(always)] 132 | pub fn reduce(x: &Block, y: &Block) -> Block { 133 | unsafe { Block::reduce_unsafe(x, y) } 134 | } 135 | 136 | #[inline] 137 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 138 | unsafe fn reduce_unsafe(x: &Block, y: &Block) -> Block { 139 | let tmp3 = x.0; 140 | let tmp6 = y.0; 141 | let xmmmask = _mm_setr_epi32(-1, 0x0, 0x0, 0x0); 142 | let tmp7 = _mm_srli_epi32(tmp6, 31); 143 | let tmp8 = _mm_srli_epi32(tmp6, 30); 144 | let tmp9 = _mm_srli_epi32(tmp6, 25); 145 | 146 | let tmp7 = _mm_xor_si128(tmp7, tmp8); 147 | let tmp7 = _mm_xor_si128(tmp7, tmp9); 148 | 149 | let tmp8 = _mm_shuffle_epi32(tmp7, 147); 150 | 151 | let tmp7 = _mm_and_si128(xmmmask, tmp8); 152 | let tmp8 = _mm_andnot_si128(xmmmask, tmp8); 153 | let tmp3 = _mm_xor_si128(tmp3, tmp8); 154 | let tmp6 = _mm_xor_si128(tmp6, tmp7); 155 | 156 | let tmp10 = _mm_slli_epi32(tmp6, 1); 157 | let tmp3 = _mm_xor_si128(tmp3, tmp10); 158 | let tmp11 = _mm_slli_epi32(tmp6, 2); 159 | let tmp3 = _mm_xor_si128(tmp3, tmp11); 160 | let tmp12 = _mm_slli_epi32(tmp6, 7); 161 | let tmp3 = _mm_xor_si128(tmp3, tmp12); 162 | 163 | Block(_mm_xor_si128(tmp3, tmp6)) 164 | } 165 | 166 | #[inline] 167 | #[cfg(target_arch = "aarch64")] 168 | #[target_feature(enable = "neon")] 169 | unsafe fn reduce_unsafe(x: &Block, y: &Block) -> Block { 170 | let tmp3 = x.0; 171 | let tmp6 = y.0; 172 | let xmmmask = vreinterpretq_u8_u32(vld1q_u32([0xffffffff, 0x0, 0x0, 0x0].as_ptr())); 173 | let tmp7 = vreinterpretq_u8_u32(vshlq_u32(vreinterpretq_u32_u8(tmp6), vdupq_n_s32(-31))); 174 | let tmp8 = vreinterpretq_u8_u32(vshlq_u32(vreinterpretq_u32_u8(tmp6), vdupq_n_s32(-30))); 175 | let tmp9 = vreinterpretq_u8_u32(vshlq_u32(vreinterpretq_u32_u8(tmp6), vdupq_n_s32(-25))); 176 | 177 | let tmp7 = veorq_u8(tmp7, tmp8); 178 | let tmp7 = veorq_u8(tmp7, tmp9); 179 | let tmp8 = _mm_shuffle_epi32!(tmp7, 147); 180 | 181 | let tmp7 = vandq_u8(xmmmask, tmp8); 182 | let tmp8 = vbicq_u8(tmp8, xmmmask); 183 | let tmp3 = veorq_u8(tmp3, tmp8); 184 | let tmp6 = veorq_u8(tmp6, tmp7); 185 | 186 | let tmp10 = vreinterpretq_u8_u32(vshlq_u32(vreinterpretq_u32_u8(tmp6), vdupq_n_s32(1))); 187 | let tmp3 = veorq_u8(tmp3, tmp10); 188 | let tmp11 = vreinterpretq_u8_u32(vshlq_u32(vreinterpretq_u32_u8(tmp6), vdupq_n_s32(2))); 189 | let tmp3 = veorq_u8(tmp3, tmp11); 190 | let tmp12 = vreinterpretq_u8_u32(vshlq_u32(vreinterpretq_u32_u8(tmp6), vdupq_n_s32(7))); 191 | let tmp3 = veorq_u8(tmp3, tmp12); 192 | Block(veorq_u8(tmp3, tmp6)) 193 | } 194 | 195 | /// Get the least significant bit of the Block. 196 | #[inline(always)] 197 | pub fn get_lsb(&self) -> bool { 198 | let x = u128::from(*self); 199 | (x & 1) == 1 200 | } 201 | 202 | /// Set the least significant bit to `1`. 203 | #[inline(always)] 204 | pub fn set_lsb(&mut self) { 205 | *self |= Block::from(1u128); 206 | } 207 | 208 | /// Set the `pos` bit to `1`. 209 | #[inline(always)] 210 | pub fn set_bit(self, pos: u64) -> Self { 211 | assert!(pos < 128); 212 | let x = 1u128 << pos; 213 | self | Block::from(x) 214 | } 215 | 216 | /// Convert a byte slice to Block. 217 | #[inline(always)] 218 | pub fn try_from_slice(bytes_slice: &[u8]) -> Option { 219 | if bytes_slice.len() != 16 { 220 | return None; 221 | } 222 | let mut bytes: [u8; 16] = [0; 16]; 223 | bytes[..16].clone_from_slice(&bytes_slice[..16]); 224 | Some(Block::new(&bytes)) 225 | } 226 | 227 | /// Compute the inner product of two block vectors, without reducing the polynomial. 228 | #[inline(always)] 229 | pub fn inn_prdt_no_red(a: &[Block], b: &[Block]) -> (Block, Block) { 230 | assert_eq!(a.len(), b.len()); 231 | a.iter() 232 | .zip(b.iter()) 233 | .fold((Block::default(), Block::default()), |acc, (x, y)| { 234 | let t = x.clmul(y); 235 | (t.0 ^ acc.0, t.1 ^ acc.1) 236 | }) 237 | } 238 | 239 | /// Compute the inner product of two block vectors. 240 | #[inline(always)] 241 | pub fn inn_prdt_red(a: &[Block], b: &[Block]) -> Block { 242 | let (x, y) = Block::inn_prdt_no_red(a, b); 243 | Block::reduce(&x, &y) 244 | } 245 | 246 | /// Compute the exponential function of the block. 247 | #[inline(always)] 248 | pub fn pow(&self, exp: u128) -> Self { 249 | let mut h = *self; 250 | let mut res = if (exp & 1) == 1 { 251 | h 252 | } else { 253 | Block::from(1u128) 254 | }; 255 | 256 | for i in 1..(128 - exp.leading_zeros()) { 257 | h = h * h; 258 | if (exp >> i) & 1 == 1 { 259 | res = h * res; 260 | } 261 | } 262 | res 263 | } 264 | 265 | /// Compute the inverse of the block. 266 | #[inline(always)] 267 | pub fn inverse(&self) -> Self { 268 | let mut h = *self; 269 | if h == Block::ZERO { 270 | panic!("0 has no inverse!"); 271 | } 272 | let mut res = h; 273 | for _ in 1..127 { 274 | h *= h; 275 | res *= h; 276 | } 277 | res * res 278 | } 279 | 280 | /// Let `x0` and `x1` be the lower and higher halves of `x`, respectively. 281 | /// This function compute ``sigma( x = x0 || x1 ) = x1 || (x0 xor x1)``. 282 | #[inline(always)] 283 | pub fn sigma(a: Self) -> Self { 284 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 285 | unsafe { 286 | let x = a.0; 287 | Block(_mm_xor_si128( 288 | _mm_shuffle_epi32(x, 78), 289 | _mm_and_si128(x, mem::transmute([0u64, u64::MAX])), 290 | )) 291 | } 292 | 293 | #[cfg(target_arch = "aarch64")] 294 | unsafe { 295 | let x = a.0; 296 | Block(_mm_xor_si128!( 297 | _mm_shuffle_epi32!(x, 78), 298 | _mm_and_si128!(x, mem::transmute([0u64, u64::MAX])) 299 | )) 300 | } 301 | } 302 | } 303 | 304 | impl Default for Block { 305 | #[inline(always)] 306 | fn default() -> Self { 307 | Block::from(0u128) 308 | } 309 | } 310 | 311 | impl From for [u8; 16] { 312 | #[inline(always)] 313 | fn from(m: Block) -> [u8; 16] { 314 | bytemuck::cast(m) 315 | } 316 | } 317 | 318 | impl From for [u64; 2] { 319 | #[inline(always)] 320 | fn from(m: Block) -> Self { 321 | bytemuck::cast(m) 322 | } 323 | } 324 | 325 | impl From for u128 { 326 | #[inline(always)] 327 | fn from(m: Block) -> u128 { 328 | bytemuck::cast(m) 329 | } 330 | } 331 | 332 | impl From<[u8; 16]> for Block { 333 | #[inline(always)] 334 | fn from(m: [u8; 16]) -> Self { 335 | bytemuck::cast(m) 336 | } 337 | } 338 | 339 | impl From<[u64; 2]> for Block { 340 | #[inline(always)] 341 | fn from(m: [u64; 2]) -> Self { 342 | bytemuck::cast(m) 343 | } 344 | } 345 | impl From for Block { 346 | #[inline(always)] 347 | fn from(m: u128) -> Block { 348 | bytemuck::cast(m) 349 | } 350 | } 351 | 352 | impl PartialEq for Block { 353 | #[inline(always)] 354 | fn eq(&self, other: &Self) -> bool { 355 | let x: u128 = (*self).into(); 356 | let y: u128 = (*other).into(); 357 | x == y 358 | } 359 | } 360 | 361 | impl Debug for Block { 362 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 363 | let block: [u8; 16] = (*self).into(); 364 | for byte in block.iter().rev() { 365 | write!(f, "{:02X}", byte)?; 366 | } 367 | Ok(()) 368 | } 369 | } 370 | 371 | impl Display for Block { 372 | fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { 373 | let block: [u8; 16] = (*self).into(); 374 | for byte in block.iter().rev() { 375 | write!(f, "{:02X}", byte)?; 376 | } 377 | Ok(()) 378 | } 379 | } 380 | 381 | impl AsRef<[u8]> for Block { 382 | #[inline(always)] 383 | fn as_ref(&self) -> &[u8] { 384 | bytemuck::bytes_of(self) 385 | } 386 | } 387 | 388 | impl AsMut<[u8]> for Block { 389 | #[inline(always)] 390 | fn as_mut(&mut self) -> &mut [u8] { 391 | bytemuck::bytes_of_mut(self) 392 | } 393 | } 394 | 395 | impl BitXor for Block { 396 | type Output = Self; 397 | #[inline(always)] 398 | fn bitxor(self, other: Self) -> Self::Output { 399 | #[cfg(target_arch = "aarch64")] 400 | unsafe { 401 | Self(veorq_u8(self.0, other.0)) 402 | } 403 | 404 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 405 | unsafe { 406 | Self(_mm_xor_si128(self.0, other.0)) 407 | } 408 | } 409 | } 410 | 411 | impl BitXorAssign for Block { 412 | #[inline(always)] 413 | fn bitxor_assign(&mut self, rhs: Self) { 414 | *self = *self ^ rhs; 415 | } 416 | } 417 | 418 | impl BitOr for Block { 419 | type Output = Self; 420 | #[inline(always)] 421 | fn bitor(self, rhs: Self) -> Self::Output { 422 | #[cfg(target_arch = "aarch64")] 423 | unsafe { 424 | Self(vorrq_u8(self.0, rhs.0)) 425 | } 426 | 427 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 428 | unsafe { 429 | Self(_mm_or_si128(self.0, rhs.0)) 430 | } 431 | } 432 | } 433 | 434 | impl BitOrAssign for Block { 435 | #[inline(always)] 436 | fn bitor_assign(&mut self, rhs: Self) { 437 | *self = *self | rhs 438 | } 439 | } 440 | 441 | impl BitAnd for Block { 442 | type Output = Self; 443 | #[inline(always)] 444 | fn bitand(self, rhs: Self) -> Self::Output { 445 | #[cfg(target_arch = "aarch64")] 446 | unsafe { 447 | Self(vandq_u8(self.0, rhs.0)) 448 | } 449 | 450 | #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] 451 | unsafe { 452 | Self(_mm_and_si128(self.0, rhs.0)) 453 | } 454 | } 455 | } 456 | 457 | impl BitAndAssign for Block { 458 | #[inline(always)] 459 | fn bitand_assign(&mut self, rhs: Self) { 460 | *self = *self & rhs 461 | } 462 | } 463 | 464 | impl Mul for Block { 465 | type Output = Self; 466 | #[inline(always)] 467 | fn mul(self, rhs: Self) -> Self::Output { 468 | self.gfmul(&rhs) 469 | } 470 | } 471 | 472 | impl MulAssign for Block { 473 | #[inline(always)] 474 | fn mul_assign(&mut self, rhs: Self) { 475 | *self = *self * rhs; 476 | } 477 | } 478 | 479 | impl rand::distributions::Distribution for rand::distributions::Standard { 480 | #[inline] 481 | fn sample(&self, rng: &mut R) -> Block { 482 | Block::from(rng.gen::()) 483 | } 484 | } 485 | 486 | #[test] 487 | fn type_test() { 488 | use rand::{Rng, SeedableRng}; 489 | use rand_chacha::ChaCha12Rng; 490 | let mut rng = ChaCha12Rng::from_entropy(); 491 | 492 | let x: [u8; 16] = rng.gen(); 493 | let blk = Block::from(x); 494 | let _x: [u8; 16] = blk.into(); 495 | assert_eq!(x, _x); 496 | 497 | let x: [u64; 2] = rng.gen(); 498 | let blk = Block::from(x); 499 | let _x: [u64; 2] = blk.into(); 500 | assert_eq!(x, _x); 501 | 502 | let x: u128 = rng.gen(); 503 | let blk = Block::from(x); 504 | let _x: u128 = blk.into(); 505 | assert_eq!(x, _x); 506 | 507 | let y = blk.as_ref(); 508 | assert_eq!(blk, Block::try_from_slice(y).unwrap()); 509 | } 510 | 511 | #[test] 512 | fn clmul_test() { 513 | let x: u128 = 0x7b5b54657374566563746f725d53475d; 514 | let y: u128 = 0x48692853686179295b477565726f6e5d; 515 | let x = Block::from(x); 516 | let y = Block::from(y); 517 | let res1 = Block::from(0xd857e24982ab861c929633d5d36f0451); 518 | let res2 = Block::from(0x1d1e1f2c592e7c45d7946a682e55e763); 519 | assert_eq!(x.clmul(&y), (res1, res2)); 520 | } 521 | 522 | #[test] 523 | fn reduce_test() { 524 | let x = Block::from(0xd857e24982ab861c929633d5d36f0451); 525 | let y = Block::from(0x1d1e1f2c592e7c45d7946a682e55e763); 526 | let z = Block::from(0x040229a09a5ed12e7e4e10da323506d2); 527 | assert_eq!(z, Block::reduce(&x, &y)); 528 | } 529 | 530 | #[test] 531 | fn gfmul_test() { 532 | let mut x = Block::from(0x7b5b54657374566563746f725d53475d); 533 | let y = Block::from(0x48692853686179295b477565726f6e5d); 534 | let z = Block::from(0x040229a09a5ed12e7e4e10da323506d2); 535 | 536 | assert_eq!(z, x.gfmul(&y)); 537 | assert_eq!(z, x * y); 538 | 539 | x *= y; 540 | assert_eq!(z, x); 541 | } 542 | 543 | #[test] 544 | fn bit_test() { 545 | use rand::{Rng, SeedableRng}; 546 | use rand_chacha::ChaCha12Rng; 547 | let mut rng = ChaCha12Rng::from_entropy(); 548 | let x: u128 = rng.gen(); 549 | let y: u128 = rng.gen(); 550 | 551 | let x: Block = Block::from(x); 552 | let y: Block = Block::from(y); 553 | 554 | let _x: u128 = x.into(); 555 | let _y: u128 = y.into(); 556 | 557 | assert_eq!(Block::from(_x ^ _y), x ^ y); 558 | assert_eq!(Block::from(_x | _y), x | y); 559 | assert_eq!(Block::from(_x & _y), x & y); 560 | 561 | let mut z = x; 562 | z ^= y; 563 | assert_eq!(Block::from(_x ^ _y), z); 564 | 565 | z = x; 566 | z |= y; 567 | assert_eq!(Block::from(_x | _y), z); 568 | 569 | z = x; 570 | z &= y; 571 | assert_eq!(Block::from(_x & _y), z); 572 | } 573 | 574 | #[test] 575 | fn lsb_test() { 576 | use rand::{Rng, SeedableRng}; 577 | use rand_chacha::ChaCha12Rng; 578 | let mut rng = ChaCha12Rng::from_entropy(); 579 | 580 | let x: u128 = rng.gen(); 581 | let mut y = Block::from(x); 582 | assert_eq!((x & 1) == 1, y.get_lsb()); 583 | 584 | y.set_lsb(); 585 | assert_eq!(y.get_lsb(), true); 586 | } 587 | 588 | #[test] 589 | fn inn_prdt_test() { 590 | use rand::{Rng, SeedableRng}; 591 | use rand_chacha::ChaCha12Rng; 592 | let mut rng = ChaCha12Rng::from_entropy(); 593 | 594 | const SIZE: usize = 1000; 595 | let mut a = Vec::new(); 596 | let mut b = Vec::new(); 597 | let mut c = (Block::default(), Block::default()); 598 | let mut d = Block::default(); 599 | for i in 0..SIZE { 600 | let r: u128 = rng.gen(); 601 | a.push(Block::from(r)); 602 | let r: u128 = rng.gen(); 603 | b.push(Block::from(r)); 604 | 605 | let z = a[i].clmul(&b[i]); 606 | c.0 = c.0 ^ z.0; 607 | c.1 = c.1 ^ z.1; 608 | 609 | let x = a[i] * b[i]; 610 | d ^= x; 611 | } 612 | 613 | assert_eq!(c, Block::inn_prdt_no_red(&a, &b)); 614 | assert_eq!(d, Block::inn_prdt_red(&a, &b)); 615 | } 616 | 617 | #[test] 618 | fn pow_inverse_test() { 619 | let one = Block::from(1u128); 620 | let exp = rand::random::() % 100; 621 | let x = Block::from(rand::random::()); 622 | let mut pow = one; 623 | 624 | for _ in 0..exp { 625 | pow = pow * x; 626 | } 627 | assert_eq!(pow, x.pow(exp)); 628 | assert_eq!(one, x * x.inverse()); 629 | } 630 | 631 | #[test] 632 | fn to_bytes_test() { 633 | use rand::{Rng, SeedableRng}; 634 | use rand_chacha::ChaCha12Rng; 635 | let mut rng = ChaCha12Rng::from_entropy(); 636 | 637 | let x: Block = rng.gen::().into(); 638 | assert_eq!(x, Block::try_from_slice(x.as_ref()).unwrap()); 639 | 640 | let mut y: Block = rng.gen::().into(); 641 | let _y = Block::try_from_slice(y.as_mut()).unwrap(); 642 | assert_eq!(y, _y); 643 | } 644 | -------------------------------------------------------------------------------- /emp-tool/src/constants.rs: -------------------------------------------------------------------------------- 1 | //! Define constants used in the libraries. 2 | 3 | /// Party PUBLIC 4 | pub const PUBLIC: usize = 0; 5 | 6 | /// Party ALICE 7 | pub const ALICE: usize = 1; 8 | 9 | /// Party BOB 10 | pub const BOB: usize = 2; 11 | -------------------------------------------------------------------------------- /emp-tool/src/ggm_tree.rs: -------------------------------------------------------------------------------- 1 | //! Implement GGM tree for OT. 2 | use crate::{tkprp::TwoKeyPrp, Block}; 3 | 4 | /// Struct of GGM 5 | pub struct GgmTree { 6 | tkprp: TwoKeyPrp, 7 | depth: usize, 8 | } 9 | 10 | impl GgmTree { 11 | ///New GgmTree instance. 12 | #[inline(always)] 13 | pub fn new(depth: usize) -> Self { 14 | let tkprp = TwoKeyPrp::new([Block::ZERO, Block::from(1u128)]); 15 | Self { tkprp, depth } 16 | } 17 | 18 | /// Input: `seed`: a seed.\ 19 | /// Output: `tree`: a GGM (binary tree) `tree`, with size `2^{depth}`.\ 20 | /// Output: `k0`: XORs of all the left-node values in each level, with size `depth`.\ 21 | /// Output: `k1`: XORs of all the right-node values in each level, with size `depth`.\ 22 | /// This implementation is adopted from EMP Toolkit. 23 | pub fn gen(&self, seed: Block, tree: &mut [Block], k0: &mut [Block], k1: &mut [Block]) { 24 | assert_eq!(tree.len(), 1 << (self.depth)); 25 | assert_eq!(k0.len(), self.depth); 26 | assert_eq!(k1.len(), self.depth); 27 | 28 | let mut buf = [Block::ZERO; 8]; 29 | self.tkprp.expand_1to2(tree, seed); 30 | k0[0] = tree[0]; 31 | k1[0] = tree[1]; 32 | 33 | self.tkprp.expand_2to4(&mut buf, tree); 34 | k0[1] = buf[0] ^ buf[2]; 35 | k1[1] = buf[1] ^ buf[3]; 36 | tree[0..4].copy_from_slice(&buf[0..4]); 37 | 38 | for h in 2..self.depth { 39 | k0[h] = Block::ZERO; 40 | k1[h] = Block::ZERO; 41 | let sz = 1 << h; 42 | for i in (0..=sz - 4).rev().step_by(4) { 43 | self.tkprp.expand_4to8(&mut buf, &tree[i..]); 44 | k0[h] ^= buf[0]; 45 | k0[h] ^= buf[2]; 46 | k0[h] ^= buf[4]; 47 | k0[h] ^= buf[6]; 48 | k1[h] ^= buf[1]; 49 | k1[h] ^= buf[3]; 50 | k1[h] ^= buf[5]; 51 | k1[h] ^= buf[7]; 52 | 53 | tree[2 * i..2 * i + 8].copy_from_slice(&buf); 54 | } 55 | } 56 | } 57 | 58 | /// Reconstruct the GGM tree except the value in a given position.\ 59 | /// Input : `k` - a slice of blocks with length `depth`, the values of k are chosen via OT from k0 and k1. \ 60 | /// For the i-th value, if alpha[i] == 1, k[i] = k1[i]; else k[i] = k0[i].\ 61 | /// Input : `alpha` - a slice of bits with length `depth`.\ 62 | /// Output : `tree` - the ggm tree, except `tree[pos] == Block::ZERO`. \ 63 | /// The bit decomposition of `pos` is the complement of `alpha`. I.e., `pos[i] = 1 xor alpha[i]`.\ 64 | pub fn reconstruct(&self, alpha: &[bool], k: &[Block], tree: &mut [Block]) { 65 | let mut pos = 0; 66 | for i in 1..=self.depth { 67 | pos *= 2; 68 | tree[pos] = Block::ZERO; 69 | tree[pos + 1] = Block::ZERO; 70 | if !alpha[i - 1] { 71 | self.reconstruct_layer(i, false, pos, k[i - 1], tree); 72 | pos += 1; 73 | } else { 74 | self.reconstruct_layer(i, true, pos + 1, k[i - 1], tree); 75 | } 76 | } 77 | } 78 | 79 | // Handle each layer. 80 | fn reconstruct_layer( 81 | &self, 82 | depth: usize, 83 | left_or_right: bool, 84 | pos: usize, 85 | k: Block, 86 | tree: &mut [Block], 87 | ) { 88 | let sz = 1 << depth; 89 | let mut sum = Block::ZERO; 90 | let start = if left_or_right { 1 } else { 0 }; 91 | 92 | for i in (start..sz).step_by(2) { 93 | sum ^= tree[i]; 94 | } 95 | tree[pos] = sum ^ k; 96 | 97 | if depth == (self.depth) { 98 | return; 99 | } 100 | 101 | let mut buf = [Block::ZERO; 8]; 102 | if sz == 2 { 103 | self.tkprp.expand_2to4(&mut buf, tree); 104 | tree[0..4].copy_from_slice(&buf[0..4]); 105 | } else { 106 | for i in (0..=sz - 4).rev().step_by(4) { 107 | self.tkprp.expand_4to8(&mut buf, &tree[i..]); 108 | tree[2 * i..2 * i + 8].copy_from_slice(&buf); 109 | } 110 | } 111 | } 112 | } 113 | 114 | #[test] 115 | fn ggm_test() { 116 | use crate::ggm_tree::GgmTree; 117 | use crate::Block; 118 | 119 | let depth = 3; 120 | let mut tree = vec![Block::ZERO; 1 << depth]; 121 | let mut k0 = vec![Block::ZERO; depth]; 122 | let mut k1 = vec![Block::ZERO; depth]; 123 | let mut k = vec![Block::ZERO; depth]; 124 | let alpha = [false, true, false]; 125 | let mut pos = 0; 126 | 127 | for i in 0..alpha.len() { 128 | pos = pos << 1; 129 | if !alpha[i] { 130 | pos += 1; 131 | } 132 | } 133 | 134 | let ggm = GgmTree::new(depth); 135 | 136 | ggm.gen(Block::ZERO, &mut tree, &mut k0, &mut k1); 137 | 138 | for i in 0..depth { 139 | if alpha[i] { 140 | k[i] = k1[i]; 141 | } else { 142 | k[i] = k0[i]; 143 | } 144 | } 145 | 146 | let mut tree_reconstruct = vec![Block::ZERO; 1 << depth]; 147 | ggm.reconstruct(&alpha, &k, &mut tree_reconstruct); 148 | 149 | assert_eq!(tree_reconstruct[pos], Block::ZERO); 150 | tree_reconstruct[pos] = tree[pos]; 151 | assert_eq!(tree, tree_reconstruct); 152 | } 153 | -------------------------------------------------------------------------------- /emp-tool/src/hash.rs: -------------------------------------------------------------------------------- 1 | //! Define hashes based on AES. 2 | 3 | use sha2::{Digest, Sha256}; 4 | 5 | use crate::{aes::Aes, Block}; 6 | 7 | /// Correlation-robust hash function for 128-bit inputs 8 | /// (cf. , §7.2). 9 | /// The function computes `π(x) xor x`. 10 | /// π(x) = AES(key=0x0,x) 11 | pub struct CrHash(Aes); 12 | 13 | impl CrHash { 14 | /// New a function with zero key. 15 | #[inline(always)] 16 | pub fn new() -> Self { 17 | Self(Aes::new(Block::ZERO)) 18 | } 19 | 20 | /// New a function with key. 21 | #[inline(always)] 22 | pub fn new_with_key(key: Block) -> Self { 23 | Self(Aes::new(key)) 24 | } 25 | 26 | /// Hash one block. 27 | #[inline(always)] 28 | pub fn hash_block(&self, blk: Block) -> Block { 29 | self.0.encrypt_block(blk) ^ blk 30 | } 31 | 32 | /// Hash many blocks. 33 | #[inline(always)] 34 | pub fn hash_many_blocks(&self, blks: [Block; N]) -> [Block; N] { 35 | let mut res = self.0.encrypt_many_blocks::(blks); 36 | for i in 0..N { 37 | res[i] ^= blks[i] 38 | } 39 | res 40 | } 41 | } 42 | 43 | impl Default for CrHash { 44 | #[inline(always)] 45 | fn default() -> Self { 46 | Self::new() 47 | } 48 | } 49 | 50 | /// Circular correlation-robust hash function 51 | /// (cf., §7.3). 52 | /// 53 | /// The function computes `H(sigma(x))`, where `H` is a correlation-robust hash 54 | /// function and `sigma( x = x0 || x1 ) = x1 || (x0 xor x1)`. 55 | /// `x0` and `x1` are the lower and higher halves of `x`, respectively. 56 | pub struct CcrHash(Aes); 57 | impl CcrHash { 58 | /// New a function with zero key. 59 | #[inline(always)] 60 | pub fn new() -> Self { 61 | Self(Aes::new(Block::ZERO)) 62 | } 63 | 64 | /// New a function with key. 65 | #[inline(always)] 66 | pub fn new_with_key(key: Block) -> Self { 67 | Self(Aes::new(key)) 68 | } 69 | 70 | /// Hash one block. 71 | #[inline(always)] 72 | pub fn hash_block(&self, blk: Block) -> Block { 73 | let t = Block::sigma(blk); 74 | self.0.encrypt_block(t) ^ t 75 | } 76 | 77 | /// Hash many blocks. 78 | #[inline(always)] 79 | pub fn hash_many_blocks(&self, blks: [Block; N]) -> [Block; N] { 80 | let mut t = [Block::ZERO; N]; 81 | for i in 0..N { 82 | t[i] = Block::sigma(blks[i]); 83 | } 84 | let mut res = self.0.encrypt_many_blocks::(t); 85 | for i in 0..N { 86 | res[i] ^= blks[i] 87 | } 88 | res 89 | } 90 | } 91 | 92 | impl Default for CcrHash { 93 | #[inline(always)] 94 | fn default() -> Self { 95 | Self::new() 96 | } 97 | } 98 | 99 | /// Tweakable circular correlation robust hash function 100 | /// (cf., §7.4). 101 | /// 102 | /// The function computes `π(π(x) ⊕ i) ⊕ π(x)`. 103 | pub struct TccrHash(Aes); 104 | impl TccrHash { 105 | /// New a function with zero key. 106 | #[inline(always)] 107 | pub fn new() -> Self { 108 | Self(Aes::new(Block::ZERO)) 109 | } 110 | 111 | /// New a function with key. 112 | #[inline(always)] 113 | pub fn new_with_key(key: Block) -> Self { 114 | Self(Aes::new(key)) 115 | } 116 | 117 | /// Hash one block. 118 | #[inline(always)] 119 | pub fn hash_block(&self, blk: Block, id: u64) -> Block { 120 | let y = self.0.encrypt_block(blk); 121 | let idb = Block::from([id, 0u64]); 122 | self.0.encrypt_block(y ^ idb) ^ y 123 | } 124 | 125 | /// Hash many blocks. 126 | #[inline(always)] 127 | pub fn hash_many_blocks(&self, blks: [Block; N], ids: [u64; N]) -> [Block; N] { 128 | let y = self.0.encrypt_many_blocks::(blks); 129 | let mut idsb = ids.map(|x| Block::from([x, 0u64])); 130 | for i in 0..N { 131 | idsb[i] ^= y[i]; 132 | } 133 | let mut res = self.0.encrypt_many_blocks::(idsb); 134 | for i in 0..N { 135 | res[i] ^= y[i] 136 | } 137 | res 138 | } 139 | } 140 | 141 | impl Default for TccrHash { 142 | #[inline(always)] 143 | fn default() -> Self { 144 | Self::new() 145 | } 146 | } 147 | 148 | /// A wrapper of SHA256 149 | pub struct Hash(Sha256); 150 | 151 | impl Hash { 152 | /// Hash Digest Size 153 | pub const DIGEST_SIZE: usize = 32; 154 | 155 | /// New a hash instance. 156 | #[inline(always)] 157 | pub fn new() -> Self { 158 | Self(Sha256::new()) 159 | } 160 | 161 | /// Update bytes. 162 | #[inline(always)] 163 | pub fn update(&mut self, m: &[u8]) { 164 | self.0.update(m); 165 | } 166 | 167 | /// Finalize output 168 | #[inline(always)] 169 | pub fn finalize(&mut self) -> [u8; Hash::DIGEST_SIZE] { 170 | let hasher = self.0.clone(); 171 | let mut res = [0u8; Hash::DIGEST_SIZE]; 172 | res.copy_from_slice(&hasher.finalize()); 173 | res 174 | } 175 | 176 | /// Update block. 177 | #[inline(always)] 178 | pub fn update_block(&mut self, m: Block) { 179 | self.update(m.as_ref()); 180 | } 181 | 182 | /// Update block slice. 183 | #[inline(always)] 184 | pub fn update_block_slice(&mut self, m: &[Block]) { 185 | self.update(bytemuck::cast_slice(m)); 186 | } 187 | 188 | /// Hash bytes once. 189 | #[inline(always)] 190 | pub fn hash_bytes_once(&mut self, m: &[u8]) -> [u8; Hash::DIGEST_SIZE] { 191 | self.update(m); 192 | self.finalize() 193 | } 194 | 195 | /// Hash blocks once. 196 | #[inline(always)] 197 | pub fn hash_blocks_once(&mut self, m: &[Block]) -> [u8; Hash::DIGEST_SIZE] { 198 | self.update_block_slice(m); 199 | self.finalize() 200 | } 201 | } 202 | 203 | impl Default for Hash { 204 | #[inline(always)] 205 | fn default() -> Self { 206 | Self::new() 207 | } 208 | } 209 | 210 | #[test] 211 | fn hash_test() { 212 | let h = CrHash::new(); 213 | assert_eq!( 214 | h.hash_block(Block::ONES), 215 | Block::from(0xb19972c12db88c05f5a57a153673a4c0) 216 | ); 217 | 218 | let h = CcrHash::new(); 219 | assert_eq!( 220 | h.hash_block(Block::ONES), 221 | Block::from(0x9e10c525db2c0ea50a1fa067183cf807) 222 | ); 223 | 224 | let h = TccrHash::new(); 225 | assert_eq!( 226 | h.hash_block(Block::ONES, 1), 227 | Block::from(0x68e0f8bae7d74f1581fc3d4b682d6260) 228 | ); 229 | } 230 | -------------------------------------------------------------------------------- /emp-tool/src/io_channel.rs: -------------------------------------------------------------------------------- 1 | //! Define the trait for IO Channel, especially for network IO. 2 | mod net_io_channel; 3 | pub use net_io_channel::NetIO; 4 | 5 | use crate::{ 6 | block::Block, 7 | utils::{pack_bits_to_bytes, unpack_bytes_to_bits}, 8 | }; 9 | use std::io::Result; 10 | 11 | /// The trait IOChannel 12 | pub trait IOChannel { 13 | /// Send bytes into the channel. 14 | /// This function should be implemented. 15 | fn send_bytes(&mut self, buffer: &[u8]) -> Result<()>; 16 | 17 | /// Receive bytes from the channel. 18 | /// This function should be implemented. 19 | fn recv_bytes(&mut self, buffer: &mut [u8]) -> Result<()>; 20 | 21 | /// Flush the channel. 22 | /// This function should be implemented. 23 | fn flush(&mut self) -> Result<()>; 24 | 25 | /// Send a 128-bit block to the channel. 26 | #[inline(always)] 27 | fn send_block(&mut self, buffer: &Block) -> Result<()> { 28 | self.send_bytes(buffer.as_ref()) 29 | } 30 | 31 | /// Send a vector of blocks to the channel. 32 | #[inline(always)] 33 | fn send_block_vec(&mut self, buffer: &[Block]) -> Result<()> { 34 | let bytes = bytemuck::cast_slice(buffer); 35 | self.send_bytes(bytes)?; 36 | Ok(()) 37 | } 38 | 39 | /// Receive a 128-bit block from the channel. 40 | #[inline(always)] 41 | fn recv_block(&mut self) -> Result { 42 | let mut b = Block::default(); 43 | self.recv_bytes(b.as_mut())?; 44 | Ok(b) 45 | } 46 | 47 | /// Receive a vector of blocks with length `len` from the channel. 48 | #[inline(always)] 49 | fn recv_block_vec(&mut self, len: usize) -> Result> { 50 | let mut blks = vec![Block::default(); len]; 51 | let bytes = bytemuck::cast_slice_mut(&mut blks); 52 | self.recv_bytes(bytes).unwrap(); 53 | Ok(blks) 54 | } 55 | 56 | /// Send a bool value to the channel. 57 | #[inline(always)] 58 | fn send_bool(&mut self, buffer: &bool) -> Result<()> { 59 | self.send_bytes(&[*buffer as u8]) 60 | } 61 | 62 | /// Receive a bool value from the channel. 63 | #[inline(always)] 64 | fn recv_bool(&mut self) -> Result { 65 | let mut b = [0u8; 1]; 66 | self.recv_bytes(&mut b)?; 67 | Ok(b[0] != 0) 68 | } 69 | 70 | /// Send a vector of bool values to the channel. 71 | #[inline(always)] 72 | fn send_bool_vec(&mut self, buffer: &[bool]) -> Result<()> { 73 | let bytes = pack_bits_to_bytes(buffer); 74 | self.send_bytes(&bytes)?; 75 | Ok(()) 76 | } 77 | 78 | /// Receive a vector of bool values with length `len` from the channel. 79 | #[inline(always)] 80 | fn recv_bool_vec(&mut self, len: usize) -> Result> { 81 | let mut bytes = vec![0u8; (len - 1) / 8 + 1]; 82 | self.recv_bytes(&mut bytes)?; 83 | Ok(unpack_bytes_to_bits(&bytes, len)) 84 | } 85 | } 86 | 87 | use structopt::StructOpt; 88 | 89 | /// Define the `CommandLineOpt` struct to read command-line args for IOChannel. 90 | #[derive(StructOpt, Debug)] 91 | pub struct CommandLineOpt { 92 | /// `party` indicates the role of participant, only consider `PUBLIC`, `ALICE` and `BOB`. 93 | #[structopt(short, long, default_value = "-1")] 94 | pub party: usize, 95 | } 96 | -------------------------------------------------------------------------------- /emp-tool/src/io_channel/net_io_channel.rs: -------------------------------------------------------------------------------- 1 | // use crate::constants::NETWORK_BUFFER_SIZE; 2 | use crate::io_channel::IOChannel; 3 | use core::time; 4 | use std::io::{BufReader, BufWriter, Read, Result, Write}; 5 | use std::net::{TcpListener, TcpStream, ToSocketAddrs}; 6 | use std::thread::sleep; 7 | 8 | /// A TCP network stream with buffer `NETWORK_BUFFER_SIZE`.\ 9 | /// This NetIO struct implements the IOChannel trait. 10 | pub struct NetIO { 11 | /// Indicate it is a server or a client. 12 | _is_server: bool, 13 | 14 | /// A buffered reader that is used to receive messages. 15 | reader: BufReader, 16 | 17 | /// A buffered writer that is used to send messages. 18 | writer: BufWriter, 19 | 20 | /// A counter that records the size of communication in Bytes. 21 | comm_cnt: usize, 22 | 23 | /// A counter that records the number of round trips. 24 | round_cnt: usize, 25 | 26 | /// A counter that records the number of flush operations. 27 | flush_cnt: usize, 28 | 29 | /// Indicate that the message is sent or not. 30 | has_sent: bool, 31 | } 32 | 33 | impl NetIO { 34 | // Network buffer size, default `1MB`. 35 | const NETWORK_BUFFER_SIZE: usize = 1024 * 1024; 36 | 37 | /// New a NetIO with socket address `addr`.\ 38 | /// Determine the server with `is_server`. 39 | pub fn new(is_server: bool, addr: A) -> Result { 40 | let stream = if is_server { 41 | let listener = TcpListener::bind(addr).expect("Failed to bind!"); 42 | let (stream, _) = listener.accept().expect("Failed to accept connection"); 43 | println!("Connected!"); 44 | 45 | stream.set_nodelay(true).expect("Failed to set TCP nodelay"); 46 | 47 | stream 48 | } else { 49 | let stream = loop { 50 | let _stream = TcpStream::connect(addr); 51 | match _stream { 52 | Ok(_stream) => { 53 | println!("Connected!"); 54 | break _stream; 55 | } 56 | Err(_) => sleep(time::Duration::from_millis(500)), 57 | } 58 | }; 59 | // let stream = TcpStream::connect(addr).expect("Failed to connect to server"); 60 | // println!("Connected!"); 61 | 62 | stream.set_nodelay(true).expect("Failed to set TCP nodelay"); 63 | 64 | stream 65 | }; 66 | 67 | let reader = 68 | BufReader::with_capacity(NetIO::NETWORK_BUFFER_SIZE, stream.try_clone().unwrap()); 69 | let writer = BufWriter::with_capacity(NetIO::NETWORK_BUFFER_SIZE, stream); 70 | 71 | Ok(Self { 72 | _is_server: is_server, 73 | reader, 74 | writer, 75 | comm_cnt: 0, 76 | round_cnt: 0, 77 | flush_cnt: 0, 78 | has_sent: false, 79 | }) 80 | } 81 | } 82 | 83 | impl IOChannel for NetIO { 84 | #[inline(always)] 85 | fn send_bytes(&mut self, buffer: &[u8]) -> Result<()> { 86 | self.comm_cnt += buffer.len(); 87 | self.has_sent = true; 88 | self.writer.write_all(buffer) 89 | } 90 | 91 | #[inline(always)] 92 | fn recv_bytes(&mut self, buffer: &mut [u8]) -> Result<()> { 93 | if self.has_sent { 94 | self.flush().unwrap(); 95 | self.round_cnt += 1; 96 | } 97 | self.has_sent = false; 98 | self.reader.read_exact(buffer) 99 | } 100 | 101 | #[inline(always)] 102 | fn flush(&mut self) -> Result<()> { 103 | self.flush_cnt += 1; 104 | self.writer.flush() 105 | } 106 | } 107 | 108 | impl Drop for NetIO { 109 | /// Flush the channel when dropping the object. 110 | fn drop(&mut self) { 111 | self.flush().unwrap(); 112 | } 113 | } 114 | 115 | #[test] 116 | fn io_test() { 117 | use crate::block::Block; 118 | 119 | let addr = "127.0.0.1:12345"; 120 | const NUM: usize = 10; 121 | let send_bytes = rand::random::<[u8; NUM]>(); 122 | let send_bool = rand::random::(); 123 | let send_bool_vec = rand::random::<[bool; NUM]>(); 124 | let send_block = rand::random::(); 125 | let send_block_vec = rand::random::<[Block; NUM]>(); 126 | 127 | let handle: std::thread::JoinHandle<()> = std::thread::spawn(move || { 128 | let mut io = NetIO::new(true, addr).unwrap(); 129 | 130 | io.send_bytes(&send_bytes).unwrap(); 131 | io.send_bool(&send_bool).unwrap(); 132 | io.send_bool_vec(&send_bool_vec.to_vec()).unwrap(); 133 | io.send_block(&send_block).unwrap(); 134 | io.send_block_vec(&send_block_vec.to_vec()).unwrap(); 135 | }); 136 | 137 | { 138 | let mut io = NetIO::new(false, addr).unwrap(); 139 | 140 | let mut recv_bytes = vec![0u8; NUM]; 141 | io.recv_bytes(&mut recv_bytes).unwrap(); 142 | let recv_bool = io.recv_bool().unwrap(); 143 | let recv_bool_vec = io.recv_bool_vec(NUM).unwrap(); 144 | let recv_block = io.recv_block().unwrap(); 145 | let recv_block_vec = io.recv_block_vec(NUM).unwrap(); 146 | 147 | assert_eq!(send_bytes.to_vec(), recv_bytes); 148 | assert_eq!(send_bool, recv_bool); 149 | assert_eq!(send_bool_vec.to_vec(), recv_bool_vec); 150 | assert_eq!(send_block, recv_block); 151 | assert_eq!(send_block_vec.to_vec(), recv_block_vec); 152 | } 153 | handle.join().unwrap(); 154 | } 155 | -------------------------------------------------------------------------------- /emp-tool/src/lib.rs: -------------------------------------------------------------------------------- 1 | #![deny(missing_docs)] 2 | 3 | //! This crate defines and implements basic tools for MPC 4 | #![cfg_attr(target_arch = "aarch64", feature(stdsimd))] 5 | pub mod aes; 6 | 7 | pub mod block; 8 | pub mod constants; 9 | pub mod ggm_tree; 10 | pub mod hash; 11 | pub mod io_channel; 12 | pub mod lpn; 13 | pub mod prg; 14 | pub mod prp; 15 | pub mod sse2neon; 16 | pub mod tkprp; 17 | pub mod utils; 18 | 19 | pub use aes::Aes; 20 | pub use block::Block; 21 | pub use constants::{ALICE, BOB, PUBLIC}; 22 | pub use hash::{CcrHash, CrHash, TccrHash}; 23 | pub use io_channel::{CommandLineOpt, IOChannel, NetIO}; 24 | pub use utils::{pack_bits_to_bytes, unpack_bytes_to_bits}; 25 | -------------------------------------------------------------------------------- /emp-tool/src/lpn.rs: -------------------------------------------------------------------------------- 1 | //! Implement LPN with local linear code. 2 | //! More especifically, a local linear code is a random boolean matrix with at most D non-zero values in each row. 3 | 4 | use crate::{prp::Prp, Block}; 5 | use rayon::prelude::*; 6 | /// A struct related to LPN. 7 | /// The `seed` defines a sparse binary matrix `A` with at most `D` non-zero values in each row.\ 8 | /// `A` - is a binary matrix with `k` columns and `n` rows. The concrete number of `n` is determined by the input length. `A` will be generated on-the-fly.\ 9 | /// `x` - is a `F_{2^128}` vector with length `k`.\ 10 | /// `e` - is a `F_{2^128}` vector with length `n`.\ 11 | /// Given a vector `x` and `e`, compute `y = Ax + e`.\ 12 | /// Note that in the standard LPN problem, `x` is a binary vector, `e` is a sparse binary vector. The way we difined here is a more generic way in term of computing `y`. 13 | pub struct Lpn { 14 | // The seed to generate the random sparse matrix A. 15 | seed: Block, 16 | 17 | // The length of the secret, i.e., x. 18 | k: u32, 19 | 20 | // A mask to optimize reduction operation. 21 | mask: u32, 22 | } 23 | 24 | impl Lpn { 25 | /// New an LPN instance 26 | pub fn new(seed: Block, k: u32) -> Self { 27 | let mut mask = 1; 28 | while mask < k { 29 | mask <<= 1; 30 | mask |= 0x1; 31 | } 32 | Self { seed, k, mask } 33 | } 34 | 35 | // Compute 4 rows as a batch, this is for the `compute_naive` function. 36 | #[inline] 37 | fn compute_four_rows_non_indep(&self, y: &mut [Block], x: &[Block], pos: usize, prp: &Prp) { 38 | let mut cnt = 0u64; 39 | let index = [0; D].map(|_| { 40 | let i: u64 = cnt; 41 | cnt += 1; 42 | Block::from([pos as u64, i]) 43 | }); 44 | 45 | let mut index: [Block; D] = prp.permute_many_blocks(index); 46 | let index: &mut [u32] = bytemuck::cast_slice_mut::<_, u32>(&mut index); 47 | 48 | for (i, y) in y[pos..].iter_mut().enumerate().take(4) { 49 | for ind in index[i * D..(i + 1) * D].iter_mut() { 50 | *ind &= self.mask; 51 | *ind = if *ind >= self.k { *ind - self.k } else { *ind }; 52 | 53 | *y ^= x[*ind as usize]; 54 | } 55 | } 56 | } 57 | 58 | // Compute 4 rows as a batch, this is for the `compute` function. 59 | #[inline] 60 | fn compute_four_rows_indep(&self, y: &mut [Block], x: &[Block], pos: usize, prp: &Prp) { 61 | let mut cnt = 0u64; 62 | let index = [0; D].map(|_| { 63 | let i = cnt; 64 | cnt += 1; 65 | Block::from([pos as u64, i]) 66 | }); 67 | 68 | let mut index = prp.permute_many_blocks(index); 69 | let index = bytemuck::cast_slice_mut::<_, u32>(&mut index); 70 | 71 | for (i, y) in y.iter_mut().enumerate().take(4) { 72 | for ind in index[i * D..(i + 1) * D].iter_mut() { 73 | *ind &= self.mask; 74 | *ind = if *ind >= self.k { *ind - self.k } else { *ind }; 75 | 76 | *y ^= x[*ind as usize]; 77 | } 78 | } 79 | } 80 | 81 | // Compute one row. 82 | #[inline] 83 | fn compute_one_row(&self, y: &mut [Block], x: &[Block], pos: usize, prp: &Prp) { 84 | let block_size = (D + 4 - 1) / 4; 85 | let mut index = (0..block_size) 86 | .map(|i| Block::from([pos as u64, i as u64])) 87 | .collect::>(); 88 | prp.permute_block_slice(&mut index); 89 | let index = bytemuck::cast_slice_mut::<_, u32>(&mut index); 90 | 91 | for ind in index.iter_mut().take(D) { 92 | *ind &= self.mask; 93 | *ind = if *ind >= self.k { *ind - self.k } else { *ind }; 94 | y[pos] ^= x[*ind as usize]; 95 | } 96 | } 97 | 98 | /// Compute `Ax + e` in a naive way.\ 99 | /// Input: `x` with length `k`.\ 100 | /// Input: `y` with length `n`, this is actually `e` in LPN.\ 101 | /// Output: `y = Ax + y`.\ 102 | /// Use `compute` function for optimized performance, but will keep it probably for test. 103 | pub fn compute_naive(&self, y: &mut [Block], x: &[Block]) { 104 | assert_eq!(x.len() as u32, self.k); 105 | assert!(x.len() >= D); 106 | let prp = Prp::new(self.seed); 107 | let batch_size = y.len() / 4; 108 | 109 | for i in 0..batch_size { 110 | self.compute_four_rows_non_indep(y, x, i * 4, &prp); 111 | } 112 | 113 | for i in batch_size * 4..y.len() { 114 | self.compute_one_row(y, x, i, &prp); 115 | } 116 | } 117 | 118 | /// Compute `Ax + e` with multiple threads.\ 119 | /// Input: `x` with length `k`.\ 120 | /// Input: `y` with length `n`, this is actually `e` in LPN.\ 121 | /// Output: `y = Ax + y`.\ 122 | pub fn compute(&self, y: &mut [Block], x: &[Block]) { 123 | assert_eq!(x.len() as u32, self.k); 124 | assert!(x.len() >= D); 125 | let prp = Prp::new(self.seed); 126 | let size = y.len() - (y.len() % 4); 127 | 128 | y.par_chunks_exact_mut(4).enumerate().for_each(|(i, y)| { 129 | self.compute_four_rows_indep(y, x, i * 4, &prp); 130 | }); 131 | 132 | for i in size..y.len() { 133 | self.compute_one_row(y, x, i, &prp); 134 | } 135 | } 136 | } 137 | 138 | #[test] 139 | fn lpn_test() { 140 | use crate::prg::Prg; 141 | 142 | let k = 20; 143 | let n = 200; 144 | let lpn = Lpn::<10>::new(Block::ZERO, k); 145 | let mut x = vec![Block::ONES; k as usize]; 146 | let mut y = vec![Block::ONES; n]; 147 | let mut prg = Prg::new(); 148 | prg.random_blocks(&mut x); 149 | prg.random_blocks(&mut y); 150 | let mut z = y.clone(); 151 | 152 | lpn.compute_naive(&mut y, &x); 153 | lpn.compute(&mut z, &x); 154 | 155 | assert_eq!(y, z); 156 | } 157 | -------------------------------------------------------------------------------- /emp-tool/src/prg.rs: -------------------------------------------------------------------------------- 1 | //! Implement AES-based PRG. 2 | 3 | use crate::{aes::Aes, Block}; 4 | use rand::Rng; 5 | use rand_core::{ 6 | block::{BlockRng, BlockRngCore}, 7 | CryptoRng, RngCore, SeedableRng, 8 | }; 9 | 10 | ///Struct of PRG Core 11 | #[derive(Clone, Copy, Debug)] 12 | struct PrgCore { 13 | aes: Aes, 14 | state: u64, 15 | } 16 | 17 | impl BlockRngCore for PrgCore { 18 | type Item = u32; 19 | type Results = [u32; 32]; 20 | 21 | // Compute [AES(state)..AES(state+8)] 22 | #[inline(always)] 23 | fn generate(&mut self, results: &mut Self::Results) { 24 | let states = [0; 8].map( 25 | #[inline(always)] 26 | |_| { 27 | let x = self.state; 28 | self.state += 1; 29 | Block::from([x, 0]) 30 | }, 31 | ); 32 | *results = bytemuck::cast(self.aes.encrypt_many_blocks(states)) 33 | } 34 | } 35 | 36 | impl SeedableRng for PrgCore { 37 | type Seed = Block; 38 | 39 | #[inline(always)] 40 | fn from_seed(seed: Self::Seed) -> Self { 41 | let aes = Aes::new(seed); 42 | Self { aes, state: 0u64 } 43 | } 44 | } 45 | 46 | impl CryptoRng for PrgCore {} 47 | 48 | /// Struct of PRG 49 | #[derive(Clone, Debug)] 50 | pub struct Prg(BlockRng); 51 | 52 | impl RngCore for Prg { 53 | #[inline(always)] 54 | fn next_u32(&mut self) -> u32 { 55 | self.0.next_u32() 56 | } 57 | 58 | #[inline(always)] 59 | fn next_u64(&mut self) -> u64 { 60 | self.0.next_u64() 61 | } 62 | 63 | #[inline(always)] 64 | fn fill_bytes(&mut self, dest: &mut [u8]) { 65 | self.0.fill_bytes(dest) 66 | } 67 | 68 | #[inline(always)] 69 | fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { 70 | self.0.try_fill_bytes(dest) 71 | } 72 | } 73 | 74 | impl SeedableRng for Prg { 75 | type Seed = Block; 76 | 77 | #[inline(always)] 78 | fn from_seed(seed: Self::Seed) -> Self { 79 | Prg(BlockRng::::from_seed(seed)) 80 | } 81 | 82 | #[inline(always)] 83 | fn from_rng(rng: R) -> Result { 84 | BlockRng::::from_rng(rng).map(Prg) 85 | } 86 | } 87 | 88 | impl CryptoRng for Prg {} 89 | 90 | impl Prg { 91 | /// New a Prg with random seed. 92 | #[inline(always)] 93 | pub fn new() -> Self { 94 | let seed = rand::random::(); 95 | Prg::from_seed(seed) 96 | } 97 | 98 | /// Generate a random bool value. 99 | #[inline(always)] 100 | pub fn random_bool(&mut self) -> bool { 101 | self.gen() 102 | } 103 | 104 | /// Fill a bool slice with random bool values. 105 | #[inline(always)] 106 | pub fn random_bools(&mut self, buf: &mut [bool]) { 107 | self.fill(buf); 108 | } 109 | 110 | /// Generate a random byte value. 111 | #[inline(always)] 112 | pub fn random_byte(&mut self) -> u8 { 113 | self.gen() 114 | } 115 | 116 | /// Fill a byte slice with random values. 117 | #[inline(always)] 118 | pub fn random_bytes(&mut self, buf: &mut [u8]) { 119 | self.fill_bytes(buf); 120 | } 121 | 122 | /// Generate a random block. 123 | #[inline(always)] 124 | pub fn random_block(&mut self) -> Block { 125 | self.gen() 126 | } 127 | 128 | /// Fill a block slice with random block values. 129 | #[inline(always)] 130 | pub fn random_blocks(&mut self, buf: &mut [Block]) { 131 | let bytes: &mut [u8] = bytemuck::cast_slice_mut(buf); 132 | self.fill_bytes(bytes); 133 | } 134 | } 135 | 136 | impl Default for Prg { 137 | #[inline(always)] 138 | fn default() -> Self { 139 | Self::new() 140 | } 141 | } 142 | 143 | #[test] 144 | fn prg_test() { 145 | let mut prg = Prg::new(); 146 | let mut x = vec![Block::ZERO; 2]; 147 | prg.random_blocks(&mut x); 148 | assert_ne!(x[0], x[1]); 149 | } 150 | -------------------------------------------------------------------------------- /emp-tool/src/prp.rs: -------------------------------------------------------------------------------- 1 | //! An implementation of Pseudo Random Permutation (PRP) based on AES. 2 | 3 | use crate::{aes::Aes, Block}; 4 | 5 | /// Struct of PRP 6 | pub struct Prp(Aes); 7 | 8 | impl Prp { 9 | /// New an instance of Prp. 10 | #[inline(always)] 11 | pub fn new(seed: Block) -> Self { 12 | Prp(Aes::new(seed)) 13 | } 14 | 15 | /// Permute one block. 16 | #[inline(always)] 17 | pub fn permute_block(&self, blk: Block) -> Block { 18 | self.0.encrypt_block(blk) 19 | } 20 | 21 | /// Permute many blocks. 22 | #[inline(always)] 23 | pub fn permute_many_blocks(&self, blks: [Block; N]) -> [Block; N] { 24 | self.0.encrypt_many_blocks(blks) 25 | } 26 | 27 | /// Permute block slice. 28 | #[inline(always)] 29 | pub fn permute_block_slice(&self, blks: &mut [Block]) { 30 | self.0.encrypt_block_slice(blks); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /emp-tool/src/sse2neon.rs: -------------------------------------------------------------------------------- 1 | //! Define sse to neon instructions. 2 | 3 | /// AES Sbox 4 | pub const AES_SBOX: [u8; 256] = [ 5 | 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76, 6 | 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 7 | 0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15, 8 | 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75, 9 | 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 10 | 0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF, 11 | 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8, 12 | 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 13 | 0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73, 14 | 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB, 15 | 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 16 | 0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08, 17 | 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A, 18 | 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 19 | 0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF, 20 | 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16, 21 | ]; 22 | 23 | /// implement _mm_shuffle_epi32 with neon. 24 | #[macro_export] 25 | macro_rules! _mm_shuffle_epi32 { 26 | ($a:expr,$IMM8:expr) => {{ 27 | let ret = vmovq_n_u32(vgetq_lane_u32(vreinterpretq_u32_u8($a), $IMM8 & (0x3))); 28 | let ret = vsetq_lane_u32( 29 | vgetq_lane_u32(vreinterpretq_u32_u8($a), ($IMM8 >> 2) & (0x3)), 30 | ret, 31 | 1, 32 | ); 33 | 34 | let ret = vsetq_lane_u32( 35 | vgetq_lane_u32(vreinterpretq_u32_u8($a), ($IMM8 >> 4) & (0x3)), 36 | ret, 37 | 2, 38 | ); 39 | let ret = vreinterpretq_u8_u32(vsetq_lane_u32( 40 | vgetq_lane_u32(vreinterpretq_u32_u8($a), ($IMM8 >> 6) & (0x3)), 41 | ret, 42 | 3, 43 | )); 44 | ret 45 | }}; 46 | } 47 | 48 | /// implement _mm_shuffle_ps with neon. 49 | #[macro_export] 50 | macro_rules! _mm_shuffle_ps { 51 | ($a:expr,$b:expr,$imm:expr) => {{ 52 | let ret = vmovq_n_f32(vgetq_lane_f32($a, ($imm) & (0x3))); 53 | let ret = vsetq_lane_f32(vgetq_lane_f32($a, ($imm >> 2) & (0x3)), ret, 1); 54 | let ret = vsetq_lane_f32(vgetq_lane_f32($b, ($imm >> 4) & (0x3)), ret, 2); 55 | let ret = vsetq_lane_f32(vgetq_lane_f32($b, ($imm >> 6) & (0x3)), ret, 3); 56 | ret 57 | }}; 58 | } 59 | 60 | /// implement _mm_cvtsi128_si32 with neon. 61 | #[macro_export] 62 | macro_rules! _mm_cvtsi128_si32 { 63 | ($a:expr) => {{ 64 | vgetq_lane_s32(vreinterpretq_s32_u8($a), 0) 65 | }}; 66 | } 67 | 68 | /// implement _mm_aeskeygenassist_si128 with neon. 69 | #[macro_export] 70 | macro_rules! _mm_aeskeygenassist_si128 { 71 | ($key:expr,$rcon:expr) => {{ 72 | let x1 = _mm_cvtsi128_si32!(_mm_shuffle_epi32!($key, 0x55)); 73 | let x3 = _mm_cvtsi128_si32!(_mm_shuffle_epi32!($key, 0xFF)); 74 | 75 | let mut x1: [u8; 4] = bytemuck::cast(x1); 76 | let mut x3: [u8; 4] = bytemuck::cast(x3); 77 | 78 | for i in 0..4 { 79 | x1[i] = AES_SBOX[x1[i] as usize]; 80 | x3[i] = AES_SBOX[x3[i] as usize]; 81 | } 82 | let x1: u32 = bytemuck::cast(x1); 83 | let x3: u32 = bytemuck::cast(x3); 84 | 85 | vreinterpretq_u8_u32(vld1q_u32( 86 | [ 87 | x1, 88 | ((x1 >> 8) | (x1 << 24)) ^ $rcon, 89 | x3, 90 | ((x3 >> 8) | (x3 << 24)) ^ $rcon, 91 | ] 92 | .as_ptr(), 93 | )) 94 | }}; 95 | } 96 | 97 | /// implement _mm_castsi128_ps with neon. 98 | #[macro_export] 99 | macro_rules! _mm_castsi128_ps { 100 | ($a:expr) => {{ 101 | vreinterpretq_f32_u8($a) 102 | }}; 103 | } 104 | 105 | /// implement _mm_castps_si128 with neon. 106 | #[macro_export] 107 | macro_rules! _mm_castps_si128 { 108 | ($a:expr) => {{ 109 | vreinterpretq_u8_f32($a) 110 | }}; 111 | } 112 | 113 | /// implement _mm_xor_si128 with neon. 114 | #[macro_export] 115 | macro_rules! _mm_xor_si128 { 116 | ($a:expr,$b:expr) => {{ 117 | veorq_u8($a, $b) 118 | }}; 119 | } 120 | 121 | /// implement _mm_and_si128 with neon. 122 | #[macro_export] 123 | macro_rules! _mm_and_si128 { 124 | ($a:expr,$b:expr) => {{ 125 | vandq_u8($a, $b) 126 | }}; 127 | } 128 | -------------------------------------------------------------------------------- /emp-tool/src/tkprp.rs: -------------------------------------------------------------------------------- 1 | //! Implement the two-key PRG as G(k) = PRF_seed0(k)\xor k || PRF_seed1(k)\xor k 2 | //! Refer to (, Page 8) 3 | 4 | use crate::{aes::Aes, Block}; 5 | 6 | /// Struct of two-key prp. 7 | pub struct TwoKeyPrp([Aes; 2]); 8 | 9 | impl TwoKeyPrp { 10 | /// New an instance of TwoKeyPrp 11 | #[inline(always)] 12 | pub fn new(seeds: [Block; 2]) -> Self { 13 | Self([Aes::new(seeds[0]), Aes::new(seeds[1])]) 14 | } 15 | 16 | /// expand 1 to 2 17 | #[inline(always)] 18 | pub(crate) fn expand_1to2(&self, children: &mut [Block], parent: Block) { 19 | children[0] = parent; 20 | children[1] = parent; 21 | Aes::para_encrypt::<2, 1>(self.0, children); 22 | children[0] ^= parent; 23 | children[1] ^= parent; 24 | } 25 | 26 | /// expand 2 to 4 27 | // p[0] p[1] 28 | // c[0] c[1] c[2] c[3] 29 | // t[0] t[2] t[1] t[3] 30 | #[inline(always)] 31 | pub(crate) fn expand_2to4(&self, children: &mut [Block], parent: &[Block]) { 32 | let mut tmp = [Block::ZERO; 4]; 33 | children[3] = parent[1]; 34 | children[2] = parent[1]; 35 | children[1] = parent[0]; 36 | children[0] = parent[0]; 37 | 38 | tmp[3] = parent[1]; 39 | tmp[1] = parent[1]; 40 | tmp[2] = parent[0]; 41 | tmp[0] = parent[0]; 42 | 43 | Aes::para_encrypt::<2, 2>(self.0, &mut tmp); 44 | 45 | children[3] ^= tmp[3]; 46 | children[2] ^= tmp[1]; 47 | children[1] ^= tmp[2]; 48 | children[0] ^= tmp[0]; 49 | } 50 | 51 | /// expand 4 to 8 52 | // p[0] p[1] p[2] p[3] 53 | // c[0] c[1] c[2] c[3] c[4] c[5] c[6] c[7] 54 | // t[0] t[4] t[1] t[5] t[2] t[6] t[3] t[7] 55 | #[inline(always)] 56 | pub(crate) fn expand_4to8(&self, children: &mut [Block], parent: &[Block]) { 57 | let mut tmp = [Block::ZERO; 8]; 58 | children[7] = parent[3]; 59 | children[6] = parent[3]; 60 | children[5] = parent[2]; 61 | children[4] = parent[2]; 62 | children[3] = parent[1]; 63 | children[2] = parent[1]; 64 | children[1] = parent[0]; 65 | children[0] = parent[0]; 66 | 67 | tmp[7] = parent[3]; 68 | tmp[3] = parent[3]; 69 | tmp[6] = parent[2]; 70 | tmp[2] = parent[2]; 71 | tmp[5] = parent[1]; 72 | tmp[1] = parent[1]; 73 | tmp[4] = parent[0]; 74 | tmp[0] = parent[0]; 75 | 76 | Aes::para_encrypt::<2, 4>(self.0, &mut tmp); 77 | 78 | children[7] ^= tmp[7]; 79 | children[6] ^= tmp[3]; 80 | children[5] ^= tmp[6]; 81 | children[4] ^= tmp[2]; 82 | children[3] ^= tmp[5]; 83 | children[2] ^= tmp[1]; 84 | children[1] ^= tmp[4]; 85 | children[0] ^= tmp[0]; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /emp-tool/src/utils.rs: -------------------------------------------------------------------------------- 1 | //! Useful utils used in the libraries 2 | 3 | /// Pack a bit vector into a byte vecotr. 4 | #[inline(always)] 5 | pub fn pack_bits_to_bytes(bits: &[bool]) -> Vec { 6 | let nbytes = (bits.len() - 1) / 8 + 1; 7 | let mut bytes = vec![0; nbytes]; 8 | for i in 0..nbytes { 9 | for j in 0..8 { 10 | if 8 * i + j >= bits.len() { 11 | break; 12 | } 13 | bytes[i] |= (bits[8 * i + j] as u8) << j; 14 | } 15 | } 16 | bytes 17 | } 18 | 19 | /// Unpack a byte vector to a bit vector with length size. 20 | #[inline(always)] 21 | pub fn unpack_bytes_to_bits(bytes: &[u8], size: usize) -> Vec { 22 | let mut bits = Vec::::new(); 23 | for (i, byte) in bytes.iter().enumerate() { 24 | for j in 0..8 { 25 | if 8 * i + j >= size { 26 | break; 27 | } 28 | bits.push(((byte >> j) & 1) != 0); 29 | } 30 | } 31 | bits 32 | } 33 | 34 | #[test] 35 | fn pack_unpack_test() { 36 | let n = 10; 37 | let mut bits = vec![false; n]; 38 | for x in bits.iter_mut() { 39 | *x = rand::random(); 40 | } 41 | let bytes = pack_bits_to_bytes(&bits); 42 | let _bits = unpack_bytes_to_bits(&bytes, n); 43 | assert_eq!(bits, _bits); 44 | } 45 | --------------------------------------------------------------------------------