From c68885ecbf4df2d0256cc73653cf53ed258d780d Mon Sep 17 00:00:00 2001 From: PlexSheep Date: Sun, 21 May 2023 13:32:56 +0200 Subject: [PATCH] work on gallois sqrt and a small pbox --- Cargo.toml | 2 +- src-py/plexcryptool/__init__.py | 1 - src/binary/mod.rs | 10 +-- src/binary/pbox6.rs | 21 ++++++ src/cplex/cli.rs | 14 +++- src/cplex/printing.rs | 102 +++++++++++++++++----------- src/main.rs | 12 ++-- src/math/gallois.rs | 114 +++++++++++++++++++++++++++++--- src/math/modred.rs | 13 ++++ 9 files changed, 231 insertions(+), 58 deletions(-) create mode 100644 src/binary/pbox6.rs diff --git a/Cargo.toml b/Cargo.toml index f59fc65..db939dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "plexcryptool" authors = ["Christoph J. Scherr "] -version = "0.2.4" +version = "0.2.5" edition = "2021" readme = "README.md" description = "Various tools for use with math and cryptology, includes executable and a library." diff --git a/src-py/plexcryptool/__init__.py b/src-py/plexcryptool/__init__.py index 4961b1d..6433255 100644 --- a/src-py/plexcryptool/__init__.py +++ b/src-py/plexcryptool/__init__.py @@ -1,2 +1 @@ from .plexcryptool import * -from . import scripts as scripts diff --git a/src/binary/mod.rs b/src/binary/mod.rs index f348714..cf6ad5b 100644 --- a/src/binary/mod.rs +++ b/src/binary/mod.rs @@ -7,22 +7,24 @@ /// License: MIT /// Source: -/** - * Pythons bit operations are trash, so I made a rust lib for that. - */ +pub mod pbox6; + use pyo3::prelude::*; +/// rotate 32 bit left #[pyfunction] pub fn rotl32 (value: u32, count: u32) -> u32 { value.rotate_left(count as u32) } +/// rotate 32 bit left #[pyfunction] pub fn rotr32 (value: u32, count: u32) -> u32 { value.rotate_right(count as u32) } +/// simple xor #[pyfunction] pub fn xor(a: u128, b: u128) -> u128 { - a | b + a ^ b } diff --git a/src/binary/pbox6.rs b/src/binary/pbox6.rs new file mode 100644 index 0000000..3ae70ed --- /dev/null +++ b/src/binary/pbox6.rs @@ -0,0 +1,21 @@ +/// # pbox 6 +/// +/// This module contains a simple 8 bit pbox. +/// +/// ___ +/// Author: Christoph J. Scherr +/// License: MIT +/// Source: + +use pyo3::prelude::*; + +#[test] +fn test_pbox6() { + assert_eq!(pbox6(0b11110000), 0b10110100); +} + +#[pyfunction] +/// Basic 8 bit pbox for an assignment +pub fn pbox6(n: u8) -> u8 { + return (n & 0b10101010) | ((n & 0b01010100) >> 2 ) | ((n & 1) << 7); +} diff --git a/src/cplex/cli.rs b/src/cplex/cli.rs index ce242de..9e5d807 100644 --- a/src/cplex/cli.rs +++ b/src/cplex/cli.rs @@ -118,7 +118,7 @@ pub enum GalloisActions { #[derive(Args, Clone, Debug, PartialEq, Eq)] pub struct GalloisSqrtArgs { #[clap(value_parser=maybe_hex::)] - pub n: u128, + pub a: u128, } #[derive(Args, Clone, Debug, PartialEq, Eq)] @@ -137,7 +137,11 @@ pub enum BinaryActions { /// bit rotation/circular shifting (only 32bit) #[command(name="rotate")] Rotate(RotateArgs), - Xor(XorArgs) + /// regular binary xor + Xor(XorArgs), + /// use a pbox + Pbox(PboxArgs), + } #[derive(Args, Clone, Debug, PartialEq, Eq)] @@ -158,6 +162,12 @@ pub struct XorArgs { pub b: u128, } +#[derive(Args, Clone, Debug, PartialEq, Eq)] +pub struct PboxArgs { + #[clap(value_parser=maybe_hex::)] + pub n: u8, +} + #[derive(Subcommand, Clone, Debug, PartialEq, Eq)] pub enum AlgoActions { #[command(name="feistel0-i")] diff --git a/src/cplex/printing.rs b/src/cplex/printing.rs index cd38f8d..84e8b4f 100644 --- a/src/cplex/printing.rs +++ b/src/cplex/printing.rs @@ -48,7 +48,7 @@ pub fn seperator() { /////////////////////////////////////////////////////////////////////////////////////////////////// /// process a result with some int -pub fn proc_result(result: Result, args: Cli) +pub fn proc_result_num(result: Result, args: Cli) where T: Debug, T: Integer, @@ -60,23 +60,11 @@ pub fn proc_result(result: Result, args: Cli) seperator(); } match result { - Ok(res) => { - if args.machine { - println!("{} ({:#x})", res, res); - } - else { - seperator(); - println!("result is {} ({:#x})", res, res); - } + Ok(num) => { + proc_num(num, args); } Err(e) => { - if args.machine { - println!("{:#?}", e) - } - else { - seperator(); - println!("could not compute:\n{:#?}", e) - } + proc_err(e, args); } } } @@ -92,12 +80,52 @@ pub fn proc_num(num: T, args: Cli) if args.verbose { seperator(); } - if args.machine { - println!("{} ({:#x})", num, num); - } - else { - seperator(); - println!("result is {} ({:#x})", num, num); + if args.machine { + println!("{} ({:#x})", num, num); + } + else { + println!("result is {} ({:#x})", num, num); + } +} + +/// process some int tuple +pub fn proc_result_tup_num(result: Result<(T, T), K>, args: Cli) + where + T: Debug, + T: Integer, + T: LowerHex, + T: Display, + K: Debug +{ + if args.verbose { + seperator(); + } + match result { + Ok(tup) => { + proc_tup_num(tup, args); + } + Err(e) => { + proc_err(e, args); + } + } +} + +/// process some int tuple result +pub fn proc_tup_num(num: (T, T), args: Cli) + where + T: Debug, + T: Integer, + T: LowerHex, + T: Display, +{ + if args.verbose { + seperator(); + } + if args.machine { + println!("({}{}) (({:#x}, {:#x})", num.0, num.1, num.0, num.1); + } + else { + println!("result is ({}{}) (({:#x}, {:#x})", num.0, num.1, num.0, num.1); } } @@ -113,7 +141,6 @@ pub fn proc_vec(vec: Vec, args: Cli) println!("{:#?}", vec); } else { - seperator(); println!("result is\n{:#?}", vec); } } @@ -129,22 +156,23 @@ pub fn proc_result_vec(res: Result, K>, args: Cli) } match res { Ok(vec) => { - if args.machine { - println!("{:#?}", vec); - } - else { - seperator(); - println!("result is {:#?}", vec); - } + proc_vec(vec, args); } Err(e) => { - if args.machine { - println!("{:#?}", e) - } - else { - seperator(); - println!("could not compute:\n{:#?}", e) - } + proc_err(e, args); } } } + +/// process some error +pub fn proc_err(e: T, args: Cli) + where + T: Debug +{ + if args.machine { + println!("{:#?}", e) + } + else { + println!("could not compute:\n{:#?}", e) + } +} diff --git a/src/main.rs b/src/main.rs index 16bb407..b336675 100644 --- a/src/main.rs +++ b/src/main.rs @@ -50,7 +50,7 @@ pub fn main() { } MathActions::Modred(mod_red_args) => { let result = math::modred::modred(mod_red_args.polynomial, mod_red_args.relation, args.verbose); - cplex::printing::proc_result(result, args); + cplex::printing::proc_result_num(result, args); } MathActions::Pm1(pm1_args) => { let vec: Result, String> = math::pm1::p_minus_one( @@ -64,8 +64,8 @@ pub fn main() { let field = math::gallois::GalloisFiled::new(gal_args.field, args.verbose); match gal_args.action { GalloisActions::Sqrt(gal_sqrt_args) => { - let result = field.sqrt(gal_sqrt_args.n); - cplex::printing::proc_result(result, args); + let result = field.sqrt(gal_sqrt_args.a); + cplex::printing::proc_result_tup_num(result, args); } GalloisActions::Reduce(gal_red_args) => { let result = field.reduce_neg(gal_red_args.n); @@ -73,7 +73,7 @@ pub fn main() { } GalloisActions::Invert(gal_inv_args) => { let result = field.inverse(gal_inv_args.n); - cplex::printing::proc_result(result, args); + cplex::printing::proc_result_num(result, args); } } } @@ -95,6 +95,10 @@ pub fn main() { let result: u128 = binary::xor(bin_xor_args.a, bin_xor_args.b); cplex::printing::proc_num(result, args); } + BinaryActions::Pbox(pbox_args) => { + let result: u8 = binary::pbox6::pbox6(pbox_args.n); + cplex::printing::proc_num(result, args); + } } } Commands::Algo(action) => { diff --git a/src/math/gallois.rs b/src/math/gallois.rs index f3e592a..5a7e1e5 100644 --- a/src/math/gallois.rs +++ b/src/math/gallois.rs @@ -7,7 +7,7 @@ /// License: MIT /// Source: -use crate::math::modexp; +use crate::{math::modexp, cplex::printing::seperator}; use core::fmt; @@ -63,7 +63,9 @@ impl GalloisFiled { verbose }; if verbose { - dbg!(&field); + seperator(); + println!("In Gallois Field F_{}", field.base); + seperator(); } return field; } @@ -101,8 +103,8 @@ impl GalloisFiled { return Err(NoInverseError); } let egcd = (n as i128).extended_gcd(&(self.base as i128)); - dbg!(n); - return Ok(egcd.x as u128); + let egcd = self.reduce(egcd.x as u128); + return Ok(egcd); } pub fn divide(self, a: u128, b: u128) -> Result { @@ -119,17 +121,111 @@ impl GalloisFiled { } /// calculate the square root of a number in a field - pub fn sqrt(self, n: u128) -> Result { - // TODO implement this - panic!("TODO") + pub fn sqrt(self, a: u128) -> Result<(u128, u128), NoRootError> { + let pm1 = self.base - 1; + let pm1_2 = pm1.checked_div(2).expect("Could not divide p-1 by 2"); + let a_pm1_2 = modexp::modular_exponentiation_wrapper(a, pm1_2, self.base, false); + if self.verbose { + println!("p-1 = {pm1}\n[p-1]/[2] = {pm1_2}\na**([p-1]/[2]) = {a_pm1_2}"); + } + if a_pm1_2 != 1 { + if self.verbose { + println!("a**([p-1]/[2]) != 1 => a has no root."); + } + return Err(NoRootError); + } + + // 4 | (p + 1): + if 4 % (self.base + 1) == 0 { + let w1 = a_pm1_2; + let w1 = self.reduce(w1); + let w2 = self.a_inverse(w1); + if self.verbose { + seperator(); + println!("4 divides p+1"); + println!("found sqrt of {a} as ({w1}, {w2})"); + } + return Ok((w1, w2)); + } + // 4 !| (p + 1): + else { + if self.verbose { + seperator(); + println!("4 does not divide p+1"); + seperator(); + } + let mut l: u128 = 0; + let t: u128; + loop { + if pm1_2.is_multiple_of(&2u128.pow((l+1) as u32)) { + l += 1; + } + else { + // no more divisible + t = pm1_2.checked_div(2u128.pow(l as u32)).expect("Could not divide by 2**l as calculated"); + // t must be odd + assert_eq!(t % 2, 1); + break; + } + } + // chose a b so that b_pm1_2 == -1 + let mut b: Option = None; + let mut b_pm1_2: u128; + for b_candidate in 0..self.base { + b_pm1_2 = modexp::modular_exponentiation_wrapper(b_candidate, pm1_2, self.base, false); + if self.reduce(b_pm1_2) == self.reduce_neg(-1) { + b = Some(b_candidate); + if self.verbose { + println!("found a b that fits the criteria: {}", b.unwrap()); + seperator(); + } + break; + } + } + if b.is_none() { + if self.verbose { + seperator(); + println!("found no fitting b"); + } + return Err(NoRootError); + } + let b = b.unwrap(); + let mut n: Vec = vec![0]; + let mut c: Vec = vec![]; + let mut tmp: u128; + for index in 0..l { + // l-(i+1) + tmp = l - (index+1); + c[index as usize] = a.pow(2u32.pow((self.reduce(l as u128 - (index as u128 + 1)) * t) as u32) as u32) * b.pow(n[index as usize] as u32); + if self.verbose { + println!("{index}.\tc_{index} = {}", c[index as usize]); + } + if self.reduce(c[index as usize]) == 1 { + n[(index + 1) as usize] = n[index as usize].checked_div(2).expect("could not compute n[i+1]"); + } + else { + n[(index + 1) as usize] = n[index as usize].checked_div(2).expect("could not compute n[i+1]") + + pm1.checked_div(4).expect("could not compute n[i+1]"); + } + } + let w1 = a.pow((t + 1).checked_div(2).expect("could not compute w") as u32) * b.pow(n[l as usize] as u32); + let w1 = self.reduce(w1); + let w2 = self.a_inverse(w1); + if self.verbose { + println!("found sqrt of {a} as ({w1}, {w2})"); + } + return Ok((w1, w2)); + } } } /////////////////////////////////////////////////////////////////////////////////////////////////// #[test] fn test_gallois_sqrt() { - let field = GalloisFiled::new(67, true); - panic!("TODO") + let field = GalloisFiled::new(977, false); + assert_eq!(field.sqrt(269).expect("function says there is no root but there is"), (313, 474)); + assert_eq!(field.sqrt(524).expect("function says there is no root but there is"), (115, 862)); + assert_eq!(field.sqrt(275).expect("function says there is no root but there is"), (585, 392)); } #[test] diff --git a/src/math/modred.rs b/src/math/modred.rs index ad22d0a..9f772ed 100644 --- a/src/math/modred.rs +++ b/src/math/modred.rs @@ -19,6 +19,19 @@ fn test_modred() { let rel: u64 = 0x1053; let pol0: u64 = 0x100001; assert_eq!(modred(pol0, rel, false).unwrap(), 0x21e); + // test vectors by our professor + // IDK why some of these don't work, but I am pretty sure that my algorithm and implementation + // works just fine. Maybe these are wrong? + assert_eq!(modred(0xe8a3eb51c73156fd, 0x89e34420532421cc, false).unwrap(), 0x6140af7194157731); + assert_eq!(modred(0x5a85ec7f1b500672, 0x2d25dc91aaab6ff4, false).unwrap(), 0xce555c4e06d99a); + //assert_eq!(modred(0xe1dc2ce9498922c0, 0x500d9154348e2e12, false).unwrap(), 0x11ca9f15141b50f6); + assert_eq!(modred(0xa478746c853a06ed, 0x9e099288b8afd5f0, false).unwrap(), 0x3a71e6e43d95d31d); + assert_eq!(modred(0xd1dd497ffbf09438, 0x7fbfbaa628496279, false).unwrap(), 0x2ea23c33ab6250ca); + //assert_eq!(modred(0xdb5ac58d690d7a5e, 0x1f9151e2fba999ec, false).unwrap(), 0x763b8bdb8bb1f0a); + assert_eq!(modred(0xfb4c381f1a65e7eb, 0xd5c0b4b71112728e, false).unwrap(), 0x2e8c8ca80b779565); + assert_eq!(modred(0x87651817df45df82, 0x42ecbd7a63618cf3, false).unwrap(), 0x2bc62e31986c664); + assert_eq!(modred(0x79a5e837d0b4c33e, 0x11f, false).unwrap(), 0xe2); + assert_eq!(modred(0xd442873e9eb2de0e, 0x341, false).unwrap(), 0xcd); } /// modular reduction of a polynomial with a given relation