Skip to content

Commit

Permalink
kuznyechik: use const eval to generate tables (#451)
Browse files Browse the repository at this point in the history
This PR significantly reduces size of the crate. But now clean build of
the crate takes 7-12 seconds, which is not great, but tolerable enough.
Hopefully, performance of const eval will be improved in future.

We could improve build times by using a build script and
`include_bytes!`, but it would result in a somewhat less clear code and
it would mean introduction of the first algorithmic crate which uses
build script.

Additionally, this PR adds a chain encryption test for a more thorough
testing.

Closes #448
  • Loading branch information
newpavlov authored Sep 26, 2024
1 parent 0ce5b88 commit 6b7ce12
Show file tree
Hide file tree
Showing 23 changed files with 379 additions and 269 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/kuznyechik.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
strategy:
matrix:
rust:
- 1.65.0 # MSRV
- 1.81.0 # MSRV
- stable
target:
- thumbv7em-none-eabi
Expand Down Expand Up @@ -55,7 +55,7 @@ jobs:
strategy:
matrix:
rust:
- 1.65.0 # MSRV
- 1.81.0 # MSRV
- stable
steps:
- uses: actions/checkout@v4
Expand All @@ -82,7 +82,7 @@ jobs:
strategy:
matrix:
rust:
- 1.65.0
- 1.81.0
- stable
steps:
- uses: actions/checkout@v4
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/workspace.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
- uses: RustCrypto/actions/cargo-cache@master
- uses: dtolnay/rust-toolchain@master
with:
toolchain: 1.80.0
toolchain: 1.81.0
components: clippy
- run: cargo clippy --all --exclude aes --all-features -- -D warnings

Expand Down
4 changes: 3 additions & 1 deletion kuznyechik/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Bump `cipher` to v0.5.0-pre.1; MSRV 1.65 ([#394])
- Bump `cipher` dependency to v0.5.0-pre.2 ([#398])
- Use `BlockCipherEncrypt`/`BlockCipherDecrypt` trait names ([#400])
- bump `cipher` dependency to `0.5.0-pre.4` ([#413])
- Bump `cipher` dependency to `0.5.0-pre.4` ([#413])
- Use const eval to generate tables ([#451])

### Fixed
- Fix kuznyechik 32bit build ([#406])
Expand All @@ -23,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#400]: https://github.com/RustCrypto/block-ciphers/pull/400
[#406]: https://github.com/RustCrypto/block-ciphers/pull/406
[#413]: https://github.com/RustCrypto/block-ciphers/pull/413
[#451]: https://github.com/RustCrypto/block-ciphers/pull/451


## 0.8.2 (2023-08-06)
Expand Down
4 changes: 2 additions & 2 deletions kuznyechik/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ description = "Kuznyechik (GOST R 34.12-2015) block cipher"
authors = ["RustCrypto Developers"]
license = "MIT OR Apache-2.0"
edition = "2021"
rust-version = "1.65"
rust-version = "1.81"
readme = "README.md"
documentation = "https://docs.rs/kuznyechik"
repository = "https://github.com/RustCrypto/block-ciphers"
Expand All @@ -25,7 +25,7 @@ zeroize = ["cipher/zeroize"]

[lints.rust.unexpected_cfgs]
level = "warn"
check-cfg = ["cfg(kuznyechik_force_soft)", "cfg(kuznyechik_compact_soft)"]
check-cfg = ['cfg(kuznyechik_backend, values("soft", "compact_soft"))']

[package.metadata.docs.rs]
all-features = true
Expand Down
12 changes: 4 additions & 8 deletions kuznyechik/src/big_soft/backends.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::consts::{Table, DEC_TABLE, ENC_TABLE, RKEY_GEN};
use crate::{
consts::{P, P_INV},
fused_tables::{Table, DEC_TABLE, ENC_TABLE},
utils::KEYGEN,
Block, Key,
};
use cipher::{
Expand All @@ -27,7 +28,7 @@ fn sub_bytes(block: u128, sbox: &[u8; 256]) -> u128 {

#[inline(always)]
fn transform(block: u128, table: &Table) -> u128 {
let table: &[[u128; 256]; 16] = unsafe { &*(table.as_ptr().cast()) };
let table: &[[u128; 256]; 16] = unsafe { &*(table.0.as_ptr().cast()) };
let block = block.to_le_bytes();
let mut res = 0u128;
for i in 0..16 {
Expand All @@ -41,12 +42,7 @@ fn transform(block: u128, table: &Table) -> u128 {
pub(super) fn expand_enc_keys(key: &Key) -> RoundKeys {
#[inline(always)]
fn next_const(i: usize) -> u128 {
// correct alignment of `p` is guaranteed since the table is aligned to 16 bytes
let t: &[u128; 32] = unsafe { &*(RKEY_GEN.as_ptr().cast()) };
let val = t[i];
#[cfg(target_endian = "big")]
let val = val.swap_bytes();
val
u128::from_le_bytes(KEYGEN[i].0)
}

let mut enc_keys = [0; 10];
Expand Down
2 changes: 0 additions & 2 deletions kuznyechik/src/big_soft/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ use cipher::{
};

mod backends;
#[path = "../fused_tables/consts.rs"]
mod consts;

use backends::{expand_enc_keys, inv_enc_keys, DecBackend, EncBackend, RoundKeys};

Expand Down
52 changes: 10 additions & 42 deletions kuznyechik/src/compact_soft/backends.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use super::consts::GF;
use crate::consts::{P, P_INV};
use crate::{Block, Key};
use crate::{
consts::{P, P_INV},
utils::{l_step, KEYGEN},
Block, Key,
};
use cipher::{
consts, BlockCipherDecBackend, BlockCipherEncBackend, BlockSizeUser, InOut, ParBlocksSizeUser,
};
Expand All @@ -14,35 +16,6 @@ fn x(a: &mut Block, b: &Block) {
}
}

fn l_step(msg: &mut Block, i: usize) {
#[inline(always)]
fn get_idx(b: usize, i: usize) -> usize {
b.wrapping_sub(i) & 0x0F
}
#[inline(always)]
fn get_m(msg: &Block, b: usize, i: usize) -> usize {
msg[get_idx(b, i)] as usize
}

let mut x = msg[get_idx(15, i)];
x ^= GF[3][get_m(msg, 14, i)];
x ^= GF[1][get_m(msg, 13, i)];
x ^= GF[2][get_m(msg, 12, i)];
x ^= GF[0][get_m(msg, 11, i)];
x ^= GF[5][get_m(msg, 10, i)];
x ^= GF[4][get_m(msg, 9, i)];
x ^= msg[get_idx(8, i)];
x ^= GF[6][get_m(msg, 7, i)];
x ^= msg[get_idx(6, i)];
x ^= GF[4][get_m(msg, 5, i)];
x ^= GF[5][get_m(msg, 4, i)];
x ^= GF[0][get_m(msg, 3, i)];
x ^= GF[2][get_m(msg, 2, i)];
x ^= GF[1][get_m(msg, 1, i)];
x ^= GF[3][get_m(msg, 0, i)];
msg[get_idx(15, i)] = x;
}

#[inline(always)]
fn lsx(block: &mut Block, key: &Block) {
x(block, key);
Expand All @@ -52,7 +25,7 @@ fn lsx(block: &mut Block, key: &Block) {
}
// l
for i in 0..16 {
l_step(block, i);
block.0 = l_step(block.0, i);
}
}

Expand All @@ -61,7 +34,7 @@ fn lsx_inv(block: &mut Block, key: &Block) {
x(block, key);
// l_inv
for i in 0..16 {
l_step(block, 15 - i);
block.0 = l_step(block.0, 15 - i);
}
// s_inv
for i in 0..16 {
Expand All @@ -70,22 +43,17 @@ fn lsx_inv(block: &mut Block, key: &Block) {
}

fn get_c(n: usize) -> Block {
let mut v = Block::default();
v[15] = n as u8;
for i in 0..16 {
l_step(&mut v, i);
}
v
KEYGEN[n].0.into()
}

fn f(k1: &mut Block, k2: &mut Block, n: usize) {
for i in 0..4 {
let mut k1_cpy = *k1;
lsx(&mut k1_cpy, &get_c(8 * n + 2 * i + 1));
lsx(&mut k1_cpy, &get_c(8 * n + 2 * i));
x(k2, &k1_cpy);

let mut k2_cpy = *k2;
lsx(&mut k2_cpy, &get_c(8 * n + 2 * i + 2));
lsx(&mut k2_cpy, &get_c(8 * n + 2 * i + 1));
x(k1, &k2_cpy);
}
}
Expand Down
143 changes: 0 additions & 143 deletions kuznyechik/src/compact_soft/consts.rs

This file was deleted.

1 change: 0 additions & 1 deletion kuznyechik/src/compact_soft/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use cipher::{
};

mod backends;
mod consts;

use backends::{expand, DecBackend, EncBackend, RoundKeys};

Expand Down
Loading

0 comments on commit 6b7ce12

Please sign in to comment.