sparx-cipher 0.1.2

Another SPARX block cipher implementation for Rust
Documentation
#![cfg_attr(feature = "cargo-clippy", allow(needless_range_loop))]

use ::params::*;


macro_rules! split {
    ( $x:expr ) => {
        ($x as u16, ($x >> 16) as u16)
    }
}

macro_rules! merge {
    ( $l:expr, $r:expr ) => {
        u32::from($l) | (u32::from($r) << 16)
    }
}

// --

#[cfg(feature = "x64_128")]
#[inline]
fn l(x: &mut [u32; BLOCK_SIZE]) {
    let (l, r) = split!(x[0]);
    let tmp = (l ^ r).rotate_left(8);
    x[1] ^= x[0] ^ merge!(tmp, tmp);
    x.swap(0, 1);
}

#[cfg(feature = "x64_128")]
#[inline]
fn l_inv(x: &mut [u32; BLOCK_SIZE]) {
    x.swap(0, 1);
    let (l, r) = split!(x[0]);
    let tmp = (l ^ r).rotate_left(8);
    x[1] ^= x[0] ^ merge!(tmp, tmp);
}

#[cfg(any(feature = "x128_128", feature = "x128_256"))]
#[inline]
fn l(x: &mut [u32; BLOCK_SIZE]) {
    let (x0l, x0r) = split!(x[0]);
    let (x1l, x1r) = split!(x[1]);
    let tmp = (x0l ^ x0r ^ x1l ^ x1r).rotate_left(8);
    let tmp = merge!(tmp, tmp);

    x[2] ^= merge!(x1l, x0r) ^ tmp;
    x[3] ^= merge!(x0l, x1r) ^ tmp;

    x.swap(0, 2);
    x.swap(1, 3);
}

#[cfg(any(feature = "x128_128", feature = "x128_256"))]
#[inline]
fn l_inv(x: &mut [u32; BLOCK_SIZE]) {
    x.swap(0, 2);
    x.swap(1, 3);

    let (x0l, x0r) = split!(x[0]);
    let (x1l, x1r) = split!(x[1]);
    let tmp = (x0l ^ x0r ^ x1l ^ x1r).rotate_left(8);
    let tmp = merge!(tmp, tmp);

    x[2] ^= merge!(x1l, x0r) ^ tmp;
    x[3] ^= merge!(x0l, x1r) ^ tmp;
}

#[cfg(feature = "x64_128")]
fn key_perm(k: &mut [u32; KEY_SIZE], c: u16) {
    a(&mut k[0]);

    let (k0l, k0r) = split!(k[0]);
    let (k1l, k1r) = split!(k[1]);
    k[1] = merge!(k1l.wrapping_add(k0l), k1r.wrapping_add(k0r));;

    let (k3l, k3r) = split!(k[3]);
    k[3] = merge!(k3l, k3r.wrapping_add(c));

    let tmp = k[3];
    k[3] = k[2];
    k[2] = k[1];
    k[1] = k[0];
    k[0] = tmp;
}

#[cfg(feature = "x128_128")]
fn key_perm(k: &mut [u32; KEY_SIZE], c: u16) {
    a(&mut k[0]);
    let (k0l, k0r) = split!(k[0]);
    let (k1l, k1r) = split!(k[1]);
    k[1] = merge!(k1l.wrapping_add(k0l), k1r.wrapping_add(k0r));

    a(&mut k[2]);
    let (k2l, k2r) = split!(k[2]);
    let (k3l, k3r) = split!(k[3]);
    k[3] = merge!(k3l.wrapping_add(k2l), k3r.wrapping_add(k2r).wrapping_add(c));

    let tmp = k[3];
    k[3] = k[2];
    k[2] = k[1];
    k[1] = k[0];
    k[0] = tmp;
}

#[cfg(feature = "x128_256")]
fn key_perm(k: &mut [u32; KEY_SIZE], c: u16) {
    a(&mut k[0]);
    let (k0l, k0r) = split!(k[0]);
    let (k1l, k1r) = split!(k[1]);
    k[1] = merge!(k1l.wrapping_add(k0l), k1r.wrapping_add(k0r));

    a(&mut k[4]);
    let (k2l, k2r) = split!(k[4]);
    let (k3l, k3r) = split!(k[5]);
    k[5] = merge!(k3l.wrapping_add(k2l), k3r.wrapping_add(k2r).wrapping_add(c));

    let tmp1 = k[5];
    let tmp2 = k[6];
    let tmp3 = k[7];
    k[7] = k[4];
    k[6] = k[3];
    k[5] = k[2];
    k[4] = k[1];
    k[3] = k[0];
    k[0] = tmp1;
    k[1] = tmp2;
    k[2] = tmp3;
}

#[inline]
fn a(x: &mut u32) {
    let (mut l, mut r) = split!(*x);
    l = l.rotate_right(7).wrapping_add(r);
    r = r.rotate_left(2) ^ l;
    *x = merge!(l, r);
}

#[inline]
fn a_inv(x: &mut u32) {
    let (mut l, mut r) = split!(*x);
    r = (r ^ l).rotate_right(2);
    l = l.wrapping_sub(r).rotate_left(7);
    *x = merge!(l, r);
}

// --

pub fn key_schedule(master_key: &mut [u32; KEY_SIZE], subkey: &mut SubKey) {
    for c in 0..(BRANCHES * STEPS + 1) {
        subkey[c][..ROUNDS_PER_STEP].copy_from_slice(&master_key[..ROUNDS_PER_STEP]);
        key_perm(master_key, c as u16 + 1);
    }
}

pub fn encrypt_block(subkey: &SubKey, block: &mut [u32; BLOCK_SIZE]) {
    for s in 0..STEPS {
        for b in 0..BRANCHES {
            for r in 0..ROUNDS_PER_STEP {
                block[b] ^= subkey[BRANCHES * s + b][r];
                a(&mut block[b]);
            }
        }
        l(block);
    }

    for b in 0..BRANCHES {
        block[b] ^= subkey[BRANCHES * STEPS][b];
    }
}

pub fn decrypt_block(subkey: &SubKey, block: &mut [u32; BLOCK_SIZE]) {
    for b in 0..BRANCHES {
        block[b] ^= subkey[BRANCHES * STEPS][b];
    }

    for s in (0..STEPS).rev() {
        l_inv(block);
        for b in 0..BRANCHES {
            for r in (0..ROUNDS_PER_STEP).rev() {
                a_inv(&mut block[b]);
                block[b] ^= subkey[BRANCHES * s + b][r];
            }
        }
    }
}