diff options
author | Daniel Schadt <kingdread@gmx.de> | 2025-06-17 23:42:57 +0200 |
---|---|---|
committer | Daniel Schadt <kingdread@gmx.de> | 2025-06-17 23:43:58 +0200 |
commit | 79e1a87f789cbb40d2041063c674817bb0484e5f (patch) | |
tree | e6f9e987171d7c3dd982c7683734930175d67529 /src | |
parent | 8b6b19848f47c15524b08013610f07c115239da5 (diff) | |
download | zears-79e1a87f789cbb40d2041063c674817bb0484e5f.tar.gz zears-79e1a87f789cbb40d2041063c674817bb0484e5f.tar.bz2 zears-79e1a87f789cbb40d2041063c674817bb0484e5f.zip |
remove some more XOR operations
In pass_two, one of the operands to e is always fixed (s). This means we
can pre-compute the delta-xors for all 8 values at once, which saves
some time (~7%)
Diffstat (limited to 'src')
-rw-r--r-- | src/lib.rs | 128 |
1 files changed, 96 insertions, 32 deletions
@@ -480,19 +480,7 @@ fn cipher_aez_tiny(mode: Mode, aez: &Aez, tweaks: Tweak, message: &mut [u8]) { } } -fn cipher_aez_core(mode: Mode, aez: &Aez, tweaks: Tweak, message: &mut [u8]) { - assert!(message.len() >= 32); - let delta = aez_hash(aez, tweaks); - let mut blocks = BlockAccessor::new(message); - let (m_u, m_v, m_x, m_y, d) = ( - blocks.m_u(), - blocks.m_v(), - blocks.m_x(), - blocks.m_y(), - blocks.m_uv_len(), - ); - let len_v = d.saturating_sub(128); - +fn pass_one(aez: &Aez, blocks: &mut BlockAccessor) -> Block { let mut x = Block::null(); let mut e1_eval = E::new(1, 0, aez); let e0_eval = E::new(0, 0, aez); @@ -510,6 +498,48 @@ fn cipher_aez_core(mode: Mode, aez: &Aez, tweaks: Tweak, message: &mut [u8]) { x = x ^ xi; } + x +} + +fn pass_two(aez: &Aez, blocks: &mut BlockAccessor, s: Block) -> Block { + let mut y = Block::null(); + let e2_eval = E::new(2, 0, aez); + let mut e1_eval = E::new(1, 0, aez); + let e0_eval = E::new(0, 0, aez); + + for ((raw_wi, raw_xi), s_) in blocks.pairs_mut().zip(e2_eval.evals_for(s)) { + e1_eval.advance(); + let wi = Block::from(*raw_wi); + let xi = Block::from(*raw_xi); + let yi = wi ^ s_; + let zi = xi ^ s_; + let ci_ = yi ^ e0_eval.eval(zi); + let ci = zi ^ e1_eval.eval(ci_); + + ci.write_to(raw_wi); + ci_.write_to(raw_xi); + + y = y ^ yi; + } + + y +} + +fn cipher_aez_core(mode: Mode, aez: &Aez, tweaks: Tweak, message: &mut [u8]) { + assert!(message.len() >= 32); + let delta = aez_hash(aez, tweaks); + let mut blocks = BlockAccessor::new(message); + let (m_u, m_v, m_x, m_y, d) = ( + blocks.m_u(), + blocks.m_v(), + blocks.m_x(), + blocks.m_y(), + blocks.m_uv_len(), + ); + let len_v = d.saturating_sub(128); + + let mut x = pass_one(aez, &mut blocks); + match d { 0 => (), _ if d <= 127 => { @@ -534,25 +564,7 @@ fn cipher_aez_core(mode: Mode, aez: &Aez, tweaks: Tweak, message: &mut [u8]) { } let s = s_x ^ s_y; - let mut y = Block::null(); - let mut e2_eval = E::new(2, 0, aez); - let mut e1_eval = E::new(1, 0, aez); - for (raw_wi, raw_xi) in blocks.pairs_mut() { - e2_eval.advance(); - e1_eval.advance(); - let wi = Block::from(*raw_wi); - let xi = Block::from(*raw_xi); - let s_ = e2_eval.eval(s); - let yi = wi ^ s_; - let zi = xi ^ s_; - let ci_ = yi ^ e0_eval.eval(zi); - let ci = zi ^ e1_eval.eval(ci_); - - ci.write_to(raw_wi); - ci_.write_to(raw_xi); - - y = y ^ yi; - } + let mut y = pass_two(aez, &mut blocks, s); let mut c_u = Block::default(); let mut c_v = Block::default(); @@ -678,6 +690,10 @@ impl<'a> E<'a> { self.aez.aes.aes4(block ^ delta) } + fn evals_for(self, block: Block) -> impl Iterator<Item=Block> { + Eiter::new(self, block) + } + /// Advance this computation by going from i to i+1. /// /// Afterwards, this computation will represent E_K^{j, i+1} @@ -692,6 +708,54 @@ impl<'a> E<'a> { } } +struct Eiter<'a> { + e: E<'a>, + value: Block, + blocks: [Block; 8], + len: usize, +} + +impl<'a> Eiter<'a> { + fn new(e: E<'a>, value: Block) -> Self { + assert_eq!(e.i, 0); + Eiter { + e, + value, + blocks: [Default::default(); 8], + len: 0, + } + } + + fn refill(&mut self) { + self.e.ki_p_i = self.e.ki_p_i * 2; + let pre_xored = self.value ^ self.e.kj_t_j ^ self.e.ki_p_i; + self.blocks = [ + self.e.aez.aes.aes4(pre_xored ^ self.e.aez.key_l_multiples[1]), + self.e.aez.aes.aes4(pre_xored ^ self.e.aez.key_l_multiples[2]), + self.e.aez.aes.aes4(pre_xored ^ self.e.aez.key_l_multiples[3]), + self.e.aez.aes.aes4(pre_xored ^ self.e.aez.key_l_multiples[4]), + self.e.aez.aes.aes4(pre_xored ^ self.e.aez.key_l_multiples[5]), + self.e.aez.aes.aes4(pre_xored ^ self.e.aez.key_l_multiples[6]), + self.e.aez.aes.aes4(pre_xored ^ self.e.aez.key_l_multiples[7]), + self.e.aez.aes.aes4(pre_xored ^ self.e.aez.key_l_multiples[0]), + ]; + self.len = 8; + } +} + +impl<'a> Iterator for Eiter<'a> { + type Item = Block; + + fn next(&mut self) -> Option<Self::Item> { + if self.len == 0 { + self.refill(); + } + let result = Some(self.blocks[8 - self.len]); + self.len -= 1; + result + } +} + /// Shorthand to get E_K^{j,i}(block) fn e(j: i32, i: u32, aez: &Aez, block: Block) -> Block { if j == -1 { |