fn main() {
println!("cargo:rerun-if-changed=build.rs");
let dest_path = std::path::Path::new(&std::env::var_os("OUT_DIR").unwrap()).join("tables.rs");
let tables_txt = calculate_tables();
std::fs::write(dest_path, tables_txt).unwrap();
}
fn calculate_tables() -> String {
use crate::aes_affine_mapping::aes_sbox_affine_mapping as affine_mapping;
use crate::aes_affine_mapping::aes_sbox_inverse_affine_mapping as inverse_mapping;
use crate::gf28::GF2_8;
use crate::t_box::*;
let mut gf = GF2_8::default();
let mut substitued_gf = GF2_8::default();
let mut invrsboxed_gf: GF2_8;
let mut sboxtable_code = String::with_capacity(2048);
sboxtable_code.push_str("// S-Box\nstatic SBOX: &[u8; 256] = &[\n");
let mut inversetable_code = String::with_capacity(2048);
inversetable_code.push_str("// Inversed S-Box\nstatic SINV: &[u8; 256] = &[\n");
let mut e_t0_code = String::with_capacity(4096);
e_t0_code.push_str("// T-Box 0 for encryption\nstatic TE0: &[u32; 256] = &[\n");
let mut e_t1_code = String::with_capacity(4096);
e_t1_code.push_str("// T-Box 1 for encryption\nstatic TE1: &[u32; 256] = &[\n");
let mut e_t2_code = String::with_capacity(4096);
e_t2_code.push_str("// T-Box 2 for encryption\nstatic TE2: &[u32; 256] = &[\n");
let mut e_t3_code = String::with_capacity(4096);
e_t3_code.push_str("// T-Box 3 for encryption\nstatic TE3: &[u32; 256] = &[\n");
let mut d_t0_code = String::with_capacity(4096);
d_t0_code.push_str("// T-Box 0 for decryption\nstatic TD0: &[u32; 256] = &[\n");
let mut d_t1_code = String::with_capacity(4096);
d_t1_code.push_str("// T-Box 1 for decryption\nstatic TD1: &[u32; 256] = &[\n");
let mut d_t2_code = String::with_capacity(4096);
d_t2_code.push_str("// T-Box 2 for decryption\nstatic TD2: &[u32; 256] = &[\n");
let mut d_t3_code = String::with_capacity(4096);
d_t3_code.push_str("// T-Box 3 for decryption\nstatic TD3: &[u32; 256] = &[\n");
let mut mapped_inverse: u8;
let mut invsbox: u8;
let mut number: u8;
for m in 0..16 {
sboxtable_code.push_str(" ");
inversetable_code.push_str(" ");
e_t0_code.push_str(" ");
e_t1_code.push_str(" ");
e_t2_code.push_str(" ");
e_t3_code.push_str(" ");
d_t0_code.push_str(" ");
d_t1_code.push_str(" ");
d_t2_code.push_str(" ");
d_t3_code.push_str(" ");
for n in 0..16 {
number = (m << 4) | n;
gf.set(number);
mapped_inverse = affine_mapping(gf.inverse().unwrap_or_default().get_byte());
substitued_gf.set(mapped_inverse);
gf.set(inverse_mapping(number));
invrsboxed_gf = gf.inverse().unwrap_or_default();
invsbox = invrsboxed_gf.get_byte();
sboxtable_code.push_str(format!("0x{:02X}, ", mapped_inverse).as_str());
inversetable_code.push_str(format!("0x{:02X}, ", invsbox).as_str());
e_t0_code.push_str(format!("0x{:08X}, ", e_t0_element(&substitued_gf)).as_str());
e_t1_code.push_str(format!("0x{:08X}, ", e_t1_element(&substitued_gf)).as_str());
e_t2_code.push_str(format!("0x{:08X}, ", e_t2_element(&substitued_gf)).as_str());
e_t3_code.push_str(format!("0x{:08X}, ", e_t3_element(&substitued_gf)).as_str());
d_t0_code.push_str(format!("0x{:08X}, ", d_t0_element(&invrsboxed_gf)).as_str());
d_t1_code.push_str(format!("0x{:08X}, ", d_t1_element(&invrsboxed_gf)).as_str());
d_t2_code.push_str(format!("0x{:08X}, ", d_t2_element(&invrsboxed_gf)).as_str());
d_t3_code.push_str(format!("0x{:08X}, ", d_t3_element(&invrsboxed_gf)).as_str());
if n == 7 {
e_t0_code.pop();
e_t0_code.push_str("\n ");
e_t1_code.pop();
e_t1_code.push_str("\n ");
e_t2_code.pop();
e_t2_code.push_str("\n ");
e_t3_code.pop();
e_t3_code.push_str("\n ");
d_t0_code.pop();
d_t0_code.push_str("\n ");
d_t1_code.pop();
d_t1_code.push_str("\n ");
d_t2_code.pop();
d_t2_code.push_str("\n ");
d_t3_code.pop();
d_t3_code.push_str("\n ");
}
}
sboxtable_code.pop();
sboxtable_code.push('\n');
inversetable_code.pop();
inversetable_code.push('\n');
e_t0_code.pop();
e_t0_code.push('\n');
e_t1_code.pop();
e_t1_code.push('\n');
e_t2_code.pop();
e_t2_code.push('\n');
e_t3_code.pop();
e_t3_code.push('\n');
d_t0_code.pop();
d_t0_code.push('\n');
d_t1_code.pop();
d_t1_code.push('\n');
d_t2_code.pop();
d_t2_code.push('\n');
d_t3_code.pop();
d_t3_code.push('\n');
}
sboxtable_code.push_str("];\n");
inversetable_code.push_str("];\n");
e_t0_code.push_str("];\n");
e_t1_code.push_str("];\n");
e_t2_code.push_str("];\n");
e_t3_code.push_str("];\n");
d_t0_code.push_str("];\n");
d_t1_code.push_str("];\n");
d_t2_code.push_str("];\n");
d_t3_code.push_str("];\n");
let mut final_out = String::with_capacity(32768);
final_out.push_str(&sboxtable_code);
final_out.push_str(&inversetable_code);
final_out.push_str(&e_t0_code);
final_out.push_str(&e_t1_code);
final_out.push_str(&e_t2_code);
final_out.push_str(&e_t3_code);
final_out.push_str(&d_t0_code);
final_out.push_str(&d_t1_code);
final_out.push_str(&d_t2_code);
final_out.push_str(&d_t3_code);
let x = GF2_8::new(0b_0000_0010);
let mut a = GF2_8::new(0b_0000_0001);
final_out.push_str(
"// Addend (round coefficient) needed in the round function\nconst RC: &[u8; 10] = &[\n ",
);
final_out.push_str(format!("0x{:02X},\n", a.get_byte()).as_str());
for _ in 1..10 {
a = x * a;
final_out.push_str(format!(" 0x{:02X},\n", a.get_byte()).as_str());
}
final_out.push_str("];\n");
final_out
}
mod gf28 {
use std::fmt;
use std::ops::{Add, Div, Mul, Sub};
#[derive(Copy, Clone)]
pub struct GF2_8 {
inner: u8,
}
impl Default for GF2_8 {
fn default() -> Self {
Self { inner: 0u8 }
}
}
const IRREDU_POLYNO: u16 = 0b1_0001_1011;
macro_rules! bitwise_multiply_with_mod {
($left:expr, $right:expr) => {{
let mut result: u16 = 0;
let mut digit: u16 = 1;
for i in 0..8 {
if (digit & $right) != 0 {
result ^= $left << i;
}
digit <<= 1;
}
if result >= 0b_1_0000_0000 {
let modp = IRREDU_POLYNO << 6;
digit <<= 6;
for i in 0..7 {
if (digit & result) != 0 {
result ^= modp >> i;
}
digit >>= 1;
}
}
result
}};
}
macro_rules! bitwise_divide {
($dividend:expr, $divisor:expr) => {{
let mut shift = $divisor.leading_zeros() - 7;
let divisor: u16 = $divisor << shift;
shift += 1;
let mut reminder: u16 = $dividend;
let mut quotient: u16 = 0;
let mut digit: u16 = 0b_1_0000_0000;
for i in 0..shift {
if (digit & reminder) != 0 {
reminder ^= divisor >> i;
quotient ^= 1;
}
quotient <<= 1;
digit >>= 1;
}
quotient >>= 1;
(quotient, reminder)
}};
}
impl GF2_8 {
pub fn new(value: u8) -> Self {
Self { inner: value }
}
pub fn get_byte(&self) -> u8 {
self.inner
}
pub fn set(&mut self, value: u8) {
self.inner = value;
}
pub fn inverse(&self) -> Option<Self> {
if self.inner >= 2u8 {
let mut t2: u16 = 0u16;
let mut t1: u16 = 1u16;
let mut r2: u16 = IRREDU_POLYNO;
let mut r1: u16 = self.inner as u16;
let mut tmp: u16;
while r1 != 0u16 {
let (quotient, reminder) = bitwise_divide!(r2, r1);
tmp = t2 ^ bitwise_multiply_with_mod!(quotient, t1);
r2 = r1;
r1 = reminder;
t2 = t1;
t1 = tmp;
}
Some(Self { inner: t2 as u8 })
} else if self.inner == 1u8 {
Some(*self)
} else {
None
}
}
}
impl fmt::Display for GF2_8 {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:08b}", self.inner)
}
}
impl Add for GF2_8 {
type Output = Self;
fn add(self, other: Self) -> Self {
Self {
inner: self.inner ^ other.inner,
}
}
}
impl Sub for GF2_8 {
type Output = Self;
fn sub(self, other: Self) -> Self {
Self {
inner: self.inner ^ other.inner,
}
}
}
impl Mul for GF2_8 {
type Output = Self;
fn mul(self, other: Self) -> Self {
Self {
inner: bitwise_multiply_with_mod!(self.inner as u16, other.inner as u16) as u8,
}
}
}
impl Div for GF2_8 {
type Output = Self;
fn div(self, other: Self) -> Self {
if other.inner != 1 {
self * other.inverse().expect("0 has no inverse.")
} else {
Self { inner: self.inner }
}
}
}
#[cfg(test)]
mod tests {
use super::GF2_8;
#[test]
fn basics_works() {
let mut foo = GF2_8::new(0b_1000_0000);
assert_eq!(foo.inner, 0b_1000_0000);
foo.set(0b_0000_0010);
assert_eq!(foo.get_byte(), 0b_0000_0010);
}
#[test]
fn add_works() {
let mut foo = GF2_8::new(0b_1000_0000);
let mut bar = GF2_8::new(0b_0000_0010);
assert_eq!((foo + bar).inner, 0b_1000_0010);
foo = GF2_8::new(0b_1100_0010);
bar = GF2_8::new(0b_0010_1111);
assert_eq!((foo + bar).inner, 0b_1110_1101);
}
#[test]
fn sub_works() {
let mut foo = GF2_8::new(0b_1000_0000);
let mut bar = GF2_8::new(0b_0000_0010);
assert_eq!((foo - bar).inner, 0b_1000_0010);
foo = GF2_8::new(0b_1100_0010);
bar = GF2_8::new(0b_0010_1111);
assert_eq!((foo - bar).inner, 0b_1110_1101);
}
#[test]
fn mul_works() {
let mut foo = GF2_8::new(0b_1000_0000);
let mut bar = GF2_8::new(0b_0000_0010);
assert_eq!((foo * bar).inner, 0b_0001_1011);
foo = GF2_8::new(0b_1100_0010);
bar = GF2_8::new(0b_0010_1111);
assert_eq!((foo * bar).inner, 0b_0000_0001);
}
#[test]
fn inverse_works() {
let mut foo = GF2_8::new(0b_1000_0000);
let mut bar = GF2_8::new(0b_0000_0010);
assert_eq!(foo.inverse().unwrap().inner, 0x83);
assert_eq!(bar.inverse().unwrap().inner, 0x8D);
foo = GF2_8::new(0b_1100_0010);
bar = GF2_8::new(0b_0010_1111);
assert_eq!(foo.inverse().unwrap().inner, 0x2F);
assert_eq!(bar.inverse().unwrap().inner, 0xC2);
foo = GF2_8::new(0);
assert_eq!(foo.inverse().unwrap_or_default().inner, 0);
}
#[test]
fn div_works() {
let mut foo = GF2_8::new(0b_1000_0000);
let mut bar = GF2_8::new(0b_0000_0010);
assert_eq!((foo / bar).inner, 0b_0100_0000);
foo = GF2_8::new(0b_1100_0010);
bar = GF2_8::new(0b_0010_1111);
assert_eq!((foo / bar).inner, 0b_0011_0101);
foo = GF2_8::new(0b_1010_0110);
bar = GF2_8::new(1);
assert_eq!((foo / bar).inner, 0b_1010_0110);
}
#[test]
#[should_panic]
fn div_zero_panic() {
let foo = GF2_8::new(1);
let bar = GF2_8::new(0);
let _p = foo / bar;
}
}
}
mod aes_affine_mapping {
const AES_AFFINE_MAPPING_MATRIX: [u8; 8] = [
0b_1000_1111,
0b_1100_0111,
0b_1110_0011,
0b_1111_0001,
0b_1111_1000,
0b_0111_1100,
0b_0011_1110,
0b_0001_1111,
];
const AES_AFFINE_MAPPING_VECTOR: [u8; 8] = [1, 1, 0, 0, 0, 1, 1, 0];
const AES_INVERSE_AFFINE_MAPPING_MATRIX: [u8; 8] = [
0b_0010_0101,
0b_1001_0010,
0b_0100_1001,
0b_1010_0100,
0b_0101_0010,
0b_0010_1001,
0b_1001_0100,
0b_0100_1010,
];
const AES_INVERSE_AFFINE_MAPPING_VECTOR: [u8; 8] = [1, 0, 1, 0, 0, 0, 0, 0];
macro_rules! swap_binary {
($input:expr) => {{
let mut input: u8 = $input;
let mut output: u8 = input & 0b_0000_0001;
for _ in 1..8 {
output <<= 1;
input >>= 1;
output ^= input & 0b_0000_0001;
}
output
}};
}
macro_rules! affine_mapping_operate {
($value:ident, $matrix:ident, $vector:ident) => {{
let mut result: u8 = 0;
for i in (0..8).rev() {
result ^= ((swap_binary!($matrix[i]) & $value).count_ones() as u8 ^ $vector[i])
& 0b_0000_0001;
if i != 0 {
result <<= 1;
}
}
result
}};
}
pub fn aes_sbox_affine_mapping(value: u8) -> u8 {
affine_mapping_operate!(value, AES_AFFINE_MAPPING_MATRIX, AES_AFFINE_MAPPING_VECTOR)
}
pub fn aes_sbox_inverse_affine_mapping(value: u8) -> u8 {
affine_mapping_operate!(
value,
AES_INVERSE_AFFINE_MAPPING_MATRIX,
AES_INVERSE_AFFINE_MAPPING_VECTOR
)
}
#[cfg(test)]
mod tests {
use super::aes_sbox_affine_mapping as affine_mapping;
use super::aes_sbox_inverse_affine_mapping as inverse_mapping;
#[test]
fn it_works() {
for i in 0..255 {
assert_eq!(i, inverse_mapping(affine_mapping(i)));
}
assert_eq!(255, inverse_mapping(affine_mapping(255)));
}
}
}
mod t_box {
use super::gf28::GF2_8;
const ENCRYPT_T0_VECTOR: [u8; 4] = [0x02, 0x01, 0x01, 0x03];
const ENCRYPT_T1_VECTOR: [u8; 4] = [0x03, 0x02, 0x01, 0x01];
const ENCRYPT_T2_VECTOR: [u8; 4] = [0x01, 0x03, 0x02, 0x01];
const ENCRYPT_T3_VECTOR: [u8; 4] = [0x01, 0x01, 0x03, 0x02];
const DECRYPT_T0_VECTOR: [u8; 4] = [0x0E, 0x09, 0x0D, 0x0B];
const DECRYPT_T1_VECTOR: [u8; 4] = [0x0B, 0x0E, 0x09, 0x0D];
const DECRYPT_T2_VECTOR: [u8; 4] = [0x0D, 0x0B, 0x0E, 0x09];
const DECRYPT_T3_VECTOR: [u8; 4] = [0x09, 0x0D, 0x0B, 0x0E];
macro_rules! do_the_calculation {
($gf:ident, $vector:ident) => {{
let mut multiplier = GF2_8::default();
let mut values = [0_u8; 4];
for i in 0..4 {
multiplier.set($vector[i]);
values[i] = (multiplier * (*$gf)).get_byte();
}
::std::primitive::u32::from_le_bytes(values)
}};
}
pub fn e_t0_element(gf: &GF2_8) -> u32 {
do_the_calculation!(gf, ENCRYPT_T0_VECTOR)
}
pub fn e_t1_element(gf: &GF2_8) -> u32 {
do_the_calculation!(gf, ENCRYPT_T1_VECTOR)
}
pub fn e_t2_element(gf: &GF2_8) -> u32 {
do_the_calculation!(gf, ENCRYPT_T2_VECTOR)
}
pub fn e_t3_element(gf: &GF2_8) -> u32 {
do_the_calculation!(gf, ENCRYPT_T3_VECTOR)
}
pub fn d_t0_element(gf: &GF2_8) -> u32 {
do_the_calculation!(gf, DECRYPT_T0_VECTOR)
}
pub fn d_t1_element(gf: &GF2_8) -> u32 {
do_the_calculation!(gf, DECRYPT_T1_VECTOR)
}
pub fn d_t2_element(gf: &GF2_8) -> u32 {
do_the_calculation!(gf, DECRYPT_T2_VECTOR)
}
pub fn d_t3_element(gf: &GF2_8) -> u32 {
do_the_calculation!(gf, DECRYPT_T3_VECTOR)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn et0_works() {
let tester = GF2_8::new(0xC2).inverse().unwrap();
assert_eq!(e_t0_element(&tester), 0x712F2F5E);
}
#[test]
fn dt0_works() {
let tester = GF2_8::new(0x02);
assert_eq!(d_t0_element(&tester), 0x161A121C);
}
}
}