-
Notifications
You must be signed in to change notification settings - Fork 44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add LPN and GGM related #54
Changes from all commits
4985b81
5f11ba7
bab096a
e2b7bd0
8e2bc1b
f1d9e28
6da64fe
b9aa297
60c2050
26193f7
83809d7
97a5dcf
4ec7d6c
0c98b11
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
use criterion::{black_box, criterion_group, criterion_main, Criterion}; | ||
use mpz_core::{lpn::LpnEncoder, prg::Prg, Block}; | ||
use std::time::Duration; | ||
|
||
fn criterion_benchmark(c: &mut Criterion) { | ||
c.bench_function("lpn-rayon-small", move |bench| { | ||
let seed = Block::ZERO; | ||
let k = 5_060; | ||
let n = 166_400; | ||
let lpn = LpnEncoder::<10>::new(seed, k); | ||
let mut x = vec![Block::ZERO; k as usize]; | ||
let mut y = vec![Block::ZERO; n]; | ||
let mut prg = Prg::new(); | ||
prg.random_blocks(&mut x); | ||
prg.random_blocks(&mut y); | ||
bench.iter(|| { | ||
black_box(lpn.compute(&mut y, &x)); | ||
}); | ||
}); | ||
|
||
c.bench_function("lpn-rayon-medium", move |bench| { | ||
let seed = Block::ZERO; | ||
let k = 158_000; | ||
let n = 10_168_320; | ||
let lpn = LpnEncoder::<10>::new(seed, k); | ||
let mut x = vec![Block::ZERO; k as usize]; | ||
let mut y = vec![Block::ZERO; n]; | ||
let mut prg = Prg::new(); | ||
prg.random_blocks(&mut x); | ||
prg.random_blocks(&mut y); | ||
bench.iter(|| { | ||
black_box(lpn.compute(&mut y, &x)); | ||
}); | ||
}); | ||
|
||
c.bench_function("lpn-rayon-large", move |bench| { | ||
let seed = Block::ZERO; | ||
let k = 588_160; | ||
let n = 10_616_092; | ||
let lpn = LpnEncoder::<10>::new(seed, k); | ||
let mut x = vec![Block::ZERO; k as usize]; | ||
let mut y = vec![Block::ZERO; n]; | ||
let mut prg = Prg::new(); | ||
prg.random_blocks(&mut x); | ||
prg.random_blocks(&mut y); | ||
bench.iter(|| { | ||
black_box(lpn.compute(&mut y, &x)); | ||
}); | ||
}); | ||
} | ||
|
||
criterion_group! { | ||
name = lpn; | ||
config = Criterion::default().warm_up_time(Duration::from_millis(1000)).sample_size(10); | ||
targets = criterion_benchmark | ||
} | ||
criterion_main!(lpn); |
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -18,16 +18,20 @@ impl GgmTree { | |||||||
Self { tkprp, depth } | ||||||||
} | ||||||||
|
||||||||
/// Input: `seed`: a seed. | ||||||||
/// Output: `tree`: a GGM (binary tree) `tree`, with size `2^{depth-1}` | ||||||||
/// Output: `k0`: XORs of all the left-node values in each level, with size `depth-1`. | ||||||||
/// Output: `k1`: XORs of all the right-node values in each level, with size `depth-1`. | ||||||||
/// This implementation is adapted from EMP Toolkit. | ||||||||
/// Create a GGM tree in-place. | ||||||||
/// | ||||||||
/// # Arguments | ||||||||
/// | ||||||||
/// * `seed` - a seed. | ||||||||
/// * `tree` - the destination to write the GGM (binary tree) `tree`, with size `2^{depth}`. | ||||||||
/// * `k0` - XORs of all the left-node values in each level, with size `depth`. | ||||||||
/// * `k1`- XORs of all the right-node values in each level, with size `depth`. | ||||||||
// This implementation is adapted from EMP Toolkit. | ||||||||
pub fn gen(&self, seed: Block, tree: &mut [Block], k0: &mut [Block], k1: &mut [Block]) { | ||||||||
assert!(tree.len() == 1 << (self.depth - 1)); | ||||||||
assert!(k0.len() == self.depth - 1); | ||||||||
assert!(k1.len() == self.depth - 1); | ||||||||
let mut buf = vec![Block::ZERO; 8]; | ||||||||
assert_eq!(tree.len(), 1 << (self.depth)); | ||||||||
assert_eq!(k0.len(), self.depth); | ||||||||
assert_eq!(k1.len(), self.depth); | ||||||||
let mut buf = [Block::ZERO; 8]; | ||||||||
self.tkprp.expand_1to2(tree, seed); | ||||||||
k0[0] = tree[0]; | ||||||||
k1[0] = tree[1]; | ||||||||
|
@@ -37,9 +41,11 @@ impl GgmTree { | |||||||
k1[1] = buf[1] ^ buf[3]; | ||||||||
tree[0..4].copy_from_slice(&buf[0..4]); | ||||||||
|
||||||||
for h in 2..self.depth - 1 { | ||||||||
for h in 2..self.depth { | ||||||||
k0[h] = Block::ZERO; | ||||||||
k1[h] = Block::ZERO; | ||||||||
|
||||||||
// How many nodes there are in this layer | ||||||||
let sz = 1 << h; | ||||||||
for i in (0..=sz - 4).rev().step_by(4) { | ||||||||
self.tkprp.expand_4to8(&mut buf, &tree[i..]); | ||||||||
|
@@ -56,43 +62,108 @@ impl GgmTree { | |||||||
} | ||||||||
} | ||||||||
} | ||||||||
|
||||||||
/// Reconstruct the GGM tree except the value in a given position. | ||||||||
/// | ||||||||
/// This reconstructs the GGM tree entirely except `tree[pos] == Block::ZERO`. The bit decomposition of `pos` is the complement of `alpha`. i.e., `pos[i] = 1 xor alpha[i]`. | ||||||||
/// | ||||||||
/// # Arguments | ||||||||
/// | ||||||||
/// * `k` - a slice of blocks with length `depth`, the values of k are chosen via OT from k0 and k1. For the i-th value, if alpha[i] == 1, k[i] = k1[i]; else k[i] = k0[i]. | ||||||||
/// * `alpha` - a slice of bits with length `depth`. | ||||||||
/// * `tree` - the destination to write the GGM tree. | ||||||||
pub fn reconstruct(&self, tree: &mut [Block], k: &[Block], alpha: &[bool]) { | ||||||||
assert_eq!(tree.len(), 1 << (self.depth)); | ||||||||
assert_eq!(k.len(), self.depth); | ||||||||
assert_eq!(alpha.len(), self.depth); | ||||||||
|
||||||||
let mut pos = 0; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we want some asserts on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, we need that asserts. |
||||||||
for i in 1..=self.depth { | ||||||||
pos *= 2; | ||||||||
tree[pos] = Block::ZERO; | ||||||||
tree[pos + 1] = Block::ZERO; | ||||||||
if !alpha[i - 1] { | ||||||||
self.reconstruct_layer(i, false, pos, k[i - 1], tree); | ||||||||
pos += 1; | ||||||||
} else { | ||||||||
self.reconstruct_layer(i, true, pos + 1, k[i - 1], tree); | ||||||||
} | ||||||||
} | ||||||||
} | ||||||||
|
||||||||
// Handle each layer. | ||||||||
fn reconstruct_layer( | ||||||||
&self, | ||||||||
depth: usize, | ||||||||
left_or_right: bool, | ||||||||
pos: usize, | ||||||||
k: Block, | ||||||||
tree: &mut [Block], | ||||||||
) { | ||||||||
// How many nodes there are in this layer | ||||||||
let sz = 1 << depth; | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
|
||||||||
let mut sum = Block::ZERO; | ||||||||
let start = if left_or_right { 1 } else { 0 }; | ||||||||
|
||||||||
for i in (start..sz).step_by(2) { | ||||||||
sum ^= tree[i]; | ||||||||
} | ||||||||
tree[pos] = sum ^ k; | ||||||||
|
||||||||
if depth == (self.depth) { | ||||||||
return; | ||||||||
} | ||||||||
|
||||||||
let mut buf = [Block::ZERO; 8]; | ||||||||
if sz == 2 { | ||||||||
self.tkprp.expand_2to4(&mut buf, tree); | ||||||||
tree[0..4].copy_from_slice(&buf[0..4]); | ||||||||
} else { | ||||||||
for i in (0..=sz - 4).rev().step_by(4) { | ||||||||
self.tkprp.expand_4to8(&mut buf, &tree[i..]); | ||||||||
tree[2 * i..2 * i + 8].copy_from_slice(&buf); | ||||||||
} | ||||||||
} | ||||||||
} | ||||||||
} | ||||||||
|
||||||||
#[test] | ||||||||
fn ggm_test() { | ||||||||
use crate::ggm_tree::GgmTree; | ||||||||
use crate::Block; | ||||||||
|
||||||||
let depth = 3; | ||||||||
let mut tree = vec![Block::ZERO; 1 << (depth - 1)]; | ||||||||
let mut k0 = vec![Block::ZERO; depth - 1]; | ||||||||
let mut k1 = vec![Block::ZERO; depth - 1]; | ||||||||
let mut tree = vec![Block::ZERO; 1 << depth]; | ||||||||
let mut k0 = vec![Block::ZERO; depth]; | ||||||||
let mut k1 = vec![Block::ZERO; depth]; | ||||||||
let mut k = vec![Block::ZERO; depth]; | ||||||||
let alpha = [false, true, false]; | ||||||||
let mut pos = 0; | ||||||||
|
||||||||
for a in alpha { | ||||||||
pos <<= 1; | ||||||||
if !a { | ||||||||
pos += 1; | ||||||||
} | ||||||||
} | ||||||||
|
||||||||
let ggm = GgmTree::new(depth); | ||||||||
|
||||||||
ggm.gen(Block::ZERO, &mut tree, &mut k0, &mut k1); | ||||||||
|
||||||||
// Test vectors are from EMP Toolkit. | ||||||||
assert_eq!( | ||||||||
tree, | ||||||||
[ | ||||||||
Block::from(0x92A6DDEAA3E99F9BECB268BD9EF67C91_u128.to_le_bytes()), | ||||||||
Block::from(0x9E7E9C02ED1E62385EE8A9EDDC63A2B5_u128.to_le_bytes()), | ||||||||
Block::from(0xBD4B85E90AACBD106694537DB6251264_u128.to_le_bytes()), | ||||||||
Block::from(0x230485DC4360014833E07D8D914411A2_u128.to_le_bytes()), | ||||||||
] | ||||||||
); | ||||||||
|
||||||||
assert_eq!( | ||||||||
k0, | ||||||||
[ | ||||||||
Block::from(0x2E2B34CA59FA4C883B2C8AEFD44BE966_u128.to_le_bytes()), | ||||||||
Block::from(0x2FED5803A945228B8A263BC028D36EF5_u128.to_le_bytes()), | ||||||||
] | ||||||||
); | ||||||||
|
||||||||
assert_eq!( | ||||||||
k1, | ||||||||
[ | ||||||||
Block::from(0x7E46C568D1CD4972BB1A61F95DD80EDC_u128.to_le_bytes()), | ||||||||
Block::from(0xBD7A19DEAE7E63706D08D4604D27B317_u128.to_le_bytes()), | ||||||||
] | ||||||||
); | ||||||||
for i in 0..depth { | ||||||||
if alpha[i] { | ||||||||
k[i] = k1[i]; | ||||||||
} else { | ||||||||
k[i] = k0[i]; | ||||||||
} | ||||||||
} | ||||||||
|
||||||||
let mut tree_reconstruct = vec![Block::ZERO; 1 << depth]; | ||||||||
ggm.reconstruct(&mut tree_reconstruct, &k, &alpha); | ||||||||
|
||||||||
assert_eq!(tree_reconstruct[pos], Block::ZERO); | ||||||||
tree_reconstruct[pos] = tree[pos]; | ||||||||
assert_eq!(tree, tree_reconstruct); | ||||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.