Skip to content

Commit

Permalink
kuznyechik: implement new software backend
Browse files Browse the repository at this point in the history
  • Loading branch information
newpavlov committed Aug 2, 2024
1 parent cfbb0a5 commit 24c8171
Show file tree
Hide file tree
Showing 14 changed files with 417 additions and 49 deletions.
40 changes: 8 additions & 32 deletions .github/workflows/kuznyechik.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,44 +39,15 @@ jobs:
- env:
RUSTFLAGS: "-Dwarnings --cfg kuznyechik_force_soft"
run: cargo build --target ${{ matrix.target }}
- env:
RUSTFLAGS: "-Dwarnings --cfg kuznyechik_force_soft --cfg kuznyechik_compact_soft"
run: cargo build --target ${{ matrix.target }}

minimal-versions:
uses: RustCrypto/actions/.github/workflows/minimal-versions.yml@master
with:
working-directory: ${{ github.workflow }}

sse2:
runs-on: ubuntu-latest
strategy:
matrix:
rust:
- 1.65.0 # MSRV
- stable
target:
- i686-unknown-linux-gnu
- x86_64-unknown-linux-gnu
include:
- target: i686-unknown-linux-gnu
deps: sudo apt update && sudo apt install gcc-multilib
steps:
- uses: actions/checkout@v3
- uses: RustCrypto/actions/cargo-cache@master
- uses: dtolnay/rust-toolchain@master
with:
toolchain: ${{ matrix.rust }}
targets: ${{ matrix.target }}
- run: ${{ matrix.deps }}
- env:
RUSTFLAGS: "-Dwarnings -C target-feature=+sse2"
run: |
cargo test --target ${{ matrix.target }}
cargo test --target ${{ matrix.target }} --all-features
- env:
RUSTFLAGS: "-Dwarnings -C target-feature=+sse2 --cfg kuznyechik_force_soft"
run: |
cargo test --target ${{ matrix.target }}
cargo test --target ${{ matrix.target }} --all-features
test:
runs-on: ubuntu-latest
strategy:
Expand All @@ -98,3 +69,8 @@ jobs:
run: |
cargo test
cargo test --all-features
- env:
RUSTFLAGS: "-Dwarnings --cfg kuznyechik_force_soft --cfg kuznyechik_compact_soft"
run: |
cargo test
cargo test --all-features
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion kuznyechik/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ categories = ["cryptography", "no-std"]

[dependencies]
cipher = "=0.5.0-pre.6"
cfg-if = "1"

[dev-dependencies]
cipher = { version = "=0.5.0-pre.6", features = ["dev"] }
Expand All @@ -24,7 +25,7 @@ zeroize = ["cipher/zeroize"]

[lints.rust.unexpected_cfgs]
level = "warn"
check-cfg = ["cfg(kuznyechik_force_soft)"]
check-cfg = ["cfg(kuznyechik_force_soft)", "cfg(kuznyechik_compact_soft)"]

[package.metadata.docs.rs]
all-features = true
Expand Down
170 changes: 170 additions & 0 deletions kuznyechik/src/big_soft/backends.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
use super::consts::{Table, DEC_TABLE, ENC_TABLE, RKEY_GEN};
use crate::{
consts::{P, P_INV},
Block, Key,
};
use cipher::{
array::Array, consts, inout::InOut, BlockBackend, BlockSizeUser, ParBlocks, ParBlocksSizeUser,
};

pub(super) type RoundKeys = [u128; 10];
type ParBlocksSize = consts::U3;

#[rustfmt::skip]
macro_rules! unroll_par {
($var:ident, $body:block) => {
{ let $var: usize = 0; $body; }
{ let $var: usize = 1; $body; }
{ let $var: usize = 2; $body; }
};
}

#[inline(always)]
fn sub_bytes(block: u128, sbox: &[u8; 256]) -> u128 {
u128::from_le_bytes(block.to_le_bytes().map(|v| sbox[v as usize]))
}

#[inline(always)]
fn transform(block: u128, table: &Table) -> u128 {
let table: &[[u128; 256]; 16] = unsafe { &*(table.as_ptr().cast()) };
let block = block.to_le_bytes();
let mut res = 0u128;
for i in 0..16 {
res ^= table[i][block[i] as usize];
}
#[cfg(target_endian = "big")]
let res = res.swap_bytes();
res
}

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
}

let mut enc_keys = [0; 10];

let mut k1 = u128::from_le_bytes(key[..16].try_into().unwrap());
let mut k2 = u128::from_le_bytes(key[16..].try_into().unwrap());

enc_keys[0] = k1;
enc_keys[1] = k2;

let mut cidx = 0;
for i in 1..5 {
for _ in 0..4 {
let mut t = k1 ^ next_const(cidx);
cidx += 1;
t = transform(t, &ENC_TABLE);
k2 ^= t;

let mut t = k2 ^ next_const(cidx);
cidx += 1;
t = transform(t, &ENC_TABLE);
k1 ^= t;
}

enc_keys[2 * i] = k1;
enc_keys[2 * i + 1] = k2;
}

enc_keys
}

pub(super) fn inv_enc_keys(enc_keys: &RoundKeys) -> RoundKeys {
let mut dec_keys = [0; 10];

dec_keys[0] = enc_keys[9];
for i in 1..9 {
let k = sub_bytes(enc_keys[i], &P);
dec_keys[9 - i] = transform(k, &DEC_TABLE);
}
dec_keys[9] = enc_keys[0];

dec_keys
}

pub(crate) struct EncBackend<'a>(pub(crate) &'a RoundKeys);

impl<'a> BlockSizeUser for EncBackend<'a> {
type BlockSize = consts::U16;
}

impl<'a> ParBlocksSizeUser for EncBackend<'a> {
type ParBlocksSize = ParBlocksSize;
}

impl<'a> BlockBackend for EncBackend<'a> {
#[inline]
fn proc_block(&mut self, mut block: InOut<'_, '_, Block>) {
let k = self.0;

let mut b: u128 = u128::from_le_bytes(block.get_in().0);

for i in 0..9 {
b ^= k[i];
b = transform(b, &ENC_TABLE);
}
b ^= k[9];

*block.get_out() = Array(b.to_le_bytes());
}

#[inline]
fn proc_par_blocks(&mut self, mut blocks: InOut<'_, '_, ParBlocks<Self>>) {
let k = self.0;

let mut bs = blocks.get_in().0.map(|b| u128::from_le_bytes(b.0));

for i in 0..9 {
unroll_par!(j, {
bs[j] ^= k[i];
bs[j] = transform(bs[j], &ENC_TABLE);
});
}

let blocks_out = blocks.get_out();
unroll_par!(i, {
bs[i] ^= k[9];
blocks_out[i].0 = u128::to_le_bytes(bs[i]);
});
}
}

pub(crate) struct DecBackend<'a>(pub(crate) &'a RoundKeys);

impl<'a> BlockSizeUser for DecBackend<'a> {
type BlockSize = consts::U16;
}

impl<'a> ParBlocksSizeUser for DecBackend<'a> {
type ParBlocksSize = consts::U1;
}

impl<'a> BlockBackend for DecBackend<'a> {
#[inline]
fn proc_block(&mut self, mut block: InOut<'_, '_, Block>) {
let k = self.0;

let mut b: u128 = u128::from_le_bytes(block.get_in().0);

b ^= k[0];
b = sub_bytes(b, &P);
b = transform(b, &DEC_TABLE);

for i in 1..9 {
b = transform(b, &DEC_TABLE);
b ^= k[i];
}
b = sub_bytes(b, &P_INV);
b ^= k[9];

*block.get_out() = Array(b.to_le_bytes());
}
}
Loading

0 comments on commit 24c8171

Please sign in to comment.