From a5a3ea61faa236cbbebb507e331bc21a05ade249 Mon Sep 17 00:00:00 2001 From: Alivecow Date: Fri, 22 Nov 2024 15:28:00 +0100 Subject: [PATCH 1/3] refactor: Split Polynomial class into poly.rs file --- src/tasks/tasks01/pfmath.rs | 2 +- src/utils/field.rs | 802 +---------------------------------- src/utils/poly.rs | 819 +++++++++++++++++++++++++++++++++++- 3 files changed, 825 insertions(+), 798 deletions(-) diff --git a/src/tasks/tasks01/pfmath.rs b/src/tasks/tasks01/pfmath.rs index 1df7e96..9fb7014 100644 --- a/src/tasks/tasks01/pfmath.rs +++ b/src/tasks/tasks01/pfmath.rs @@ -2,7 +2,7 @@ use anyhow::Result; use base64::{prelude::BASE64_STANDARD, Engine}; use serde_json::Value; -use crate::utils::field::{sort_polynomial_array, FieldElement, Polynomial}; +use crate::utils::{field::FieldElement, poly::Polynomial}; pub fn gfpoly_add(args: &Value) -> Result { let poly_a = Polynomial::from_c_array(&args["A"].clone()); diff --git a/src/utils/field.rs b/src/utils/field.rs index 2864a5e..6894023 100644 --- a/src/utils/field.rs +++ b/src/utils/field.rs @@ -1,3 +1,6 @@ +use base64::prelude::*; +use std::{str::FromStr, u128, u8, usize}; + use std::{ cmp::Ordering, mem::discriminant, @@ -5,396 +8,14 @@ use std::{ }; use anyhow::{anyhow, Ok, Result}; -use base64::prelude::*; use serde_json::Value; -use crate::utils::poly::polynomial_2_block; - +use super::poly::polynomial_2_block; use super::{ math::{reverse_bits_in_bytevec, xor_bytes}, poly::gfmul, }; -#[derive(Debug, serde::Serialize)] -pub struct Polynomial { - polynomial: Vec, -} - -impl Polynomial { - pub const fn new(polynomial: Vec) -> Self { - Self { polynomial } - } - - pub fn from_c_array(array: &Value) -> Self { - let mut polynomial: Vec = vec![]; - let c_array: Vec = array - .as_array() - .expect("Input is not an array") - .iter() - .map(|x| { - x.as_str() - .expect("Array element is not a string") - .to_string() - }) - .collect(); - - eprintln!("{:?}", c_array); - - for coefficient in c_array { - polynomial.push(FieldElement::new( - BASE64_STANDARD - .decode(coefficient) - .expect("Error on poly decode:"), - )); - } - Self { polynomial } - } - - pub fn to_c_array(self) -> Vec { - let mut output: Vec = vec![]; - for coeff in self.polynomial { - output.push(BASE64_STANDARD.encode(coeff)); - } - - output - } - - pub fn pow(&self, mut exponent: u128) -> Polynomial { - if exponent == 0 { - return Polynomial::new(vec![FieldElement::new( - polynomial_2_block(vec![0], "gcm").unwrap(), - )]); - } - - let base = self.clone(); - let mut result = base.clone(); - exponent -= 1; - while exponent > 0 { - result = result * base.clone(); - exponent -= 1; - } - - result - } - - pub fn pow_mod(mut self, mut exponent: u128, modulus: Polynomial) -> Polynomial { - let mut result: Polynomial = Polynomial::new(vec![FieldElement::new( - polynomial_2_block(vec![0], "gcm").unwrap(), - )]); - - if exponent == 1 { - eprintln!("special case 1: {:02X?}", self.clone().div(&modulus).1); - - return self.div(&modulus).1; - } - - if exponent == 0 { - let result = Polynomial::new(vec![FieldElement::new( - polynomial_2_block(vec![0], "gcm").unwrap(), - )]); - - eprintln!("Returned value is: {:02X?}", result); - return result; - } - - //eprintln!("Initial result: {:?}", result); - while exponent > 0 { - //eprintln!("Current exponent: {:02X}", exponent); - if exponent & 1 == 1 { - let temp = &self * &result; - //eprintln!("After multiplication: {:?}", temp); - result = temp.div(&modulus).1; - //eprintln!("After mod: {:?}", result); - } - let temp_square = &self * &self; - //eprintln!("After squaring: {:?}", temp_square); - self = temp_square.div(&modulus).1; - //eprintln!("After mod: {:?}", self); - exponent >>= 1; - } - - eprintln!("result in powmod before reduction: {:02X?}", result); - - while !result.polynomial.is_empty() - && result - .polynomial - .last() - .unwrap() - .as_ref() - .iter() - .all(|&x| x == 0) - { - result.polynomial.pop(); - } - - eprintln!("result in powmod after reduction: {:02X?}", result); - - if result.is_empty() { - result = Polynomial::new(vec![FieldElement::new(vec![0; 16])]); - } - - result - } - - // Returns (quotient, remainder) - pub fn div(self, rhs: &Self) -> (Self, Self) { - // Div by zero check ommitted since data is guaranteed to be non 0 - - eprintln!("{:?}, {:?}", self.polynomial.len(), rhs.polynomial.len()); - - if self.polynomial.len() < rhs.polynomial.len() { - return (Polynomial::new(vec![FieldElement::new(vec![0; 16])]), self); - } - - let mut remainder = self.clone(); - let divisor = rhs; - let dividend_deg = remainder.polynomial.len() - 1; - let divisor_deg = divisor.polynomial.len() - 1; - - if dividend_deg < divisor_deg { - return ( - Polynomial::new(vec![FieldElement::new( - polynomial_2_block(vec![0; 16], "gcm").unwrap(), - )]), - remainder, - ); - } - - let mut quotient_coeffs = - vec![ - FieldElement::new(polynomial_2_block(vec![0; 16], "gcm").unwrap()); - dividend_deg - divisor_deg + 1 - ]; - - while remainder.polynomial.len() >= divisor.polynomial.len() { - let deg_diff = remainder.polynomial.len() - divisor.polynomial.len(); - - let leading_dividend = remainder.polynomial.last().unwrap(); - let leading_divisor = divisor.polynomial.last().unwrap(); - let quot_coeff = leading_dividend / leading_divisor; - - quotient_coeffs[deg_diff] = quot_coeff.clone(); - - let mut subtrahend = - vec![FieldElement::new(polynomial_2_block(vec![0; 16], "gcm").unwrap()); deg_diff]; - subtrahend.extend( - divisor - .polynomial - .iter() - .map(|x| x.clone() * quot_coeff.clone()), - ); - let subtrahend_poly = Polynomial::new(subtrahend); - - remainder = remainder + subtrahend_poly; - - while !remainder.polynomial.is_empty() - && remainder - .polynomial - .last() - .unwrap() - .as_ref() - .iter() - .all(|&x| x == 0) - { - remainder.polynomial.pop(); - } - } - - if remainder.is_empty() { - remainder = Polynomial::new(vec![FieldElement::new(vec![0; 16])]); - } - (Polynomial::new(quotient_coeffs), remainder) - } - - fn is_zero(&self) -> bool { - for field_element in &self.polynomial { - if !field_element.is_zero() { - return false; - } - } - true - } - - fn monic(mut self) -> Self { - let divident = self.polynomial.last().unwrap().clone(); - - for fieldelement in &mut self.polynomial.iter_mut() { - *fieldelement = fieldelement.clone() / divident.clone(); - } - - todo!(); - } -} - -impl Clone for Polynomial { - fn clone(&self) -> Self { - Polynomial { - polynomial: self.polynomial.clone(), - } - } -} - -impl Mul for Polynomial { - type Output = Self; - fn mul(self, rhs: Self) -> Self::Output { - if self.is_zero() || rhs.is_zero() { - return Polynomial::new(vec![FieldElement::new(vec![0; 16])]); - } - let mut polynomial: Vec = - vec![FieldElement::new(vec![0; 16]); self.polynomial.len() + rhs.polynomial.len() - 1]; - for i in 0..self.polynomial.len() { - for j in 0..rhs.polynomial.len() { - polynomial[i + j] = &polynomial[i + j] - + &(self.polynomial.get(i).unwrap() * rhs.polynomial.get(j).unwrap()); - } - } - Polynomial::new(polynomial) - } -} - -impl Mul for &Polynomial { - type Output = Polynomial; - fn mul(self, rhs: Self) -> Self::Output { - if self.is_zero() || rhs.is_zero() { - return Polynomial::new(vec![FieldElement::new(vec![0])]); - } - let mut polynomial: Vec = - vec![FieldElement::new(vec![0; 16]); self.polynomial.len() + rhs.polynomial.len() - 1]; - for i in 0..self.polynomial.len() { - for j in 0..rhs.polynomial.len() { - polynomial[i + j] = &polynomial[i + j] - + &(self.polynomial.get(i).unwrap() * rhs.polynomial.get(j).unwrap()); - } - } - Polynomial::new(polynomial) - } -} - -impl Add for Polynomial { - type Output = Self; - fn add(self, rhs: Self) -> Self::Output { - let mut polynomial: Vec; - - if self.polynomial.len() > rhs.polynomial.len() { - polynomial = self.polynomial.clone(); - for i in 0..rhs.polynomial.len() { - polynomial[i] = polynomial[i].clone() + rhs.polynomial[i].clone(); - } - } else { - polynomial = rhs.polynomial.clone(); - for i in 0..self.polynomial.len() { - polynomial[i] = polynomial[i].clone() + self.polynomial[i].clone(); - } - } - - while !polynomial.is_empty() && polynomial.last().unwrap().as_ref().iter().all(|&x| x == 0) - { - polynomial.pop(); - } - - if polynomial.is_empty() { - return Polynomial::new(vec![FieldElement::new(vec![0; 16])]); - } - - Polynomial::new(polynomial) - } -} - -impl Sub for &FieldElement { - type Output = FieldElement; - - fn sub(self, rhs: Self) -> FieldElement { - self + rhs - } -} - -trait IsEmpty { - fn is_empty(&self) -> bool; -} - -impl IsEmpty for Polynomial { - fn is_empty(&self) -> bool { - self.polynomial.is_empty() - } -} -impl AsRef<[FieldElement]> for Polynomial { - fn as_ref(&self) -> &[FieldElement] { - &self.polynomial - } -} - -impl PartialEq for Polynomial { - fn eq(&self, other: &Self) -> bool { - if self.polynomial.len() != other.polynomial.len() { - return false; - } - // Compare each coefficient - self.polynomial - .iter() - .zip(other.polynomial.iter()) - .all(|(a, b)| a == b) - } -} - -impl PartialOrd for Polynomial { - fn partial_cmp(&self, other: &Self) -> Option { - match other.polynomial.len().cmp(&self.polynomial.len()) { - Ordering::Equal => { - for (field_a, field_b) in - self.as_ref().iter().rev().zip(other.as_ref().iter().rev()) - { - eprintln!( - "Poly partord: {:02X?} {:02X?} ", - self.clone().to_c_array(), - other.clone().to_c_array() - ); - - match field_a - .reverse_bits() - .partial_cmp(&field_b.reverse_bits()) - .unwrap() - { - Ordering::Equal => continue, - other => return Some(other), - } - } - Some(Ordering::Equal) - } - other => Some(other.reverse()), - } - } -} - -impl Eq for Polynomial {} - -impl Ord for Polynomial { - fn cmp(&self, other: &Self) -> Ordering { - match other.polynomial.len().cmp(&self.polynomial.len()) { - Ordering::Equal => { - for (field_a, field_b) in - self.as_ref().iter().rev().zip(other.as_ref().iter().rev()) - { - match field_a.reverse_bits().cmp(&field_b.reverse_bits()) { - Ordering::Equal => continue, - other => return other, - } - } - Ordering::Equal - } - other => other.reverse(), - } - } -} - -pub fn sort_polynomial_array(mut polys: Vec) -> Result> { - // Algorithm to sort polynomials - // First sorting round - // Sorting by degree of polynomial - polys.sort(); - - Ok(polys) -} - #[derive(Debug, serde::Serialize)] pub struct FieldElement { field_element: Vec, @@ -453,11 +74,11 @@ impl FieldElement { FieldElement::new(inverse) } - fn is_zero(&self) -> bool { + pub fn is_zero(&self) -> bool { self.field_element.iter().all(|&x| x == 0x00) } - fn reverse_bits(&self) -> Self { + pub fn reverse_bits(&self) -> Self { FieldElement::new(reverse_bits_in_bytevec(self.field_element.clone())) } } @@ -817,415 +438,4 @@ mod tests { assert_eq!(BASE64_STANDARD.encode(sum), "OZuIncPAGEp4tYouDownAA=="); } - - #[test] - fn test_field_add_03() { - let json1 = json!([ - "NeverGonnaGiveYouUpAAA==", - "NeverGonnaLetYouDownAA==", - "NeverGonnaRunAroundAAA==", - "AndDesertYouAAAAAAAAAA==" - ]); - let json2 = json!(["KryptoanalyseAAAAAAAAA==", "DHBWMannheimAAAAAAAAAA=="]); - let element1: Polynomial = Polynomial::from_c_array(&json1); - let element2: Polynomial = Polynomial::from_c_array(&json2); - - let sum = element2 + element1; - - assert_eq!( - sum.to_c_array(), - vec![ - "H1d3GuyA9/0OxeYouUpAAA==", - "OZuIncPAGEp4tYouDownAA==", - "NeverGonnaRunAroundAAA==", - "AndDesertYouAAAAAAAAAA==" - ] - ); - } - - #[test] - fn test_field_add_multiple_zeros() { - let json1 = json!([ - "AAAAAAAAAAAAAAAAAAAAAA==", - "AAAAAAAAAAAAAAAAAAAAAA==", - "AAAAAAAAAAAAAAAAAAAAAA==", - "AAAAAAAAAAAAAAAAAAAAAA==" - ]); - let json2 = json!(["AAAAAAAAAAAAAAAAAAAAAA==", "AAAAAAAAAAAAAAAAAAAAAA=="]); - let element1: Polynomial = Polynomial::from_c_array(&json1); - let element2: Polynomial = Polynomial::from_c_array(&json2); - - let sum = element2 + element1; - - assert_eq!(sum.to_c_array(), vec!["AAAAAAAAAAAAAAAAAAAAAA==",]); - } - - #[test] - fn test_field_add_same_element() { - let json1 = json!(["NeverGonnaGiveYouUpAAA=="]); - let json2 = json!(["NeverGonnaGiveYouUpAAA=="]); - let element1: Polynomial = Polynomial::from_c_array(&json1); - let element2: Polynomial = Polynomial::from_c_array(&json2); - - let sum = element2 + element1; - - assert_eq!(sum.to_c_array(), vec!["AAAAAAAAAAAAAAAAAAAAAA==",]); - } - - #[test] - fn test_field_add_zero() { - let json1 = json!([ - "NeverGonnaGiveYouUpAAA==", - "NeverGonnaLetYouDownAA==", - "NeverGonnaRunAroundAAA==", - "AndDesertYouAAAAAAAAAA==" - ]); - let json2 = json!(["AAAAAAAAAAAAAAAAAAAAAA=="]); - let element1: Polynomial = Polynomial::from_c_array(&json1); - let element2: Polynomial = Polynomial::from_c_array(&json2); - - let sum = element2 + element1; - - assert_eq!( - sum.to_c_array(), - vec![ - "NeverGonnaGiveYouUpAAA==", - "NeverGonnaLetYouDownAA==", - "NeverGonnaRunAroundAAA==", - "AndDesertYouAAAAAAAAAA==" - ] - ); - } - - #[test] - fn test_field_add_zero_to_zero() { - let json1 = json!(["AAAAAAAAAAAAAAAAAAAAAA=="]); - let json2 = json!(["AAAAAAAAAAAAAAAAAAAAAA=="]); - let element1: Polynomial = Polynomial::from_c_array(&json1); - let element2: Polynomial = Polynomial::from_c_array(&json2); - - let sum = element2 + element1; - - assert_eq!(sum.to_c_array(), vec!["AAAAAAAAAAAAAAAAAAAAAA=="]); - } - - #[test] - fn test_field_add_short_to_long() { - let json1 = json!(["AAAAAAAAAAAAAAAAAAAAAA=="]); - let json2 = json!([ - "NeverGonnaGiveYouUpAAA==", - "NeverGonnaLetYouDownAA==", - "NeverGonnaRunAroundAAA==", - "AndDesertYouAAAAAAAAAA==" - ]); - let element1: Polynomial = Polynomial::from_c_array(&json1); - let element2: Polynomial = Polynomial::from_c_array(&json2); - - let sum = element2 + element1; - - assert_eq!( - sum.to_c_array(), - vec![ - "NeverGonnaGiveYouUpAAA==", - "NeverGonnaLetYouDownAA==", - "NeverGonnaRunAroundAAA==", - "AndDesertYouAAAAAAAAAA==" - ] - ); - } - - #[test] - fn test_field_mul_01() { - let json1 = json!([ - "JAAAAAAAAAAAAAAAAAAAAA==", - "wAAAAAAAAAAAAAAAAAAAAA==", - "ACAAAAAAAAAAAAAAAAAAAA==" - ]); - let json2 = json!(["0AAAAAAAAAAAAAAAAAAAAA==", "IQAAAAAAAAAAAAAAAAAAAA=="]); - let element1: Polynomial = Polynomial::from_c_array(&json1); - let element2: Polynomial = Polynomial::from_c_array(&json2); - - //eprintln!("{:?}", element1); - - let result = element1 * element2; - - assert_eq!( - result.to_c_array(), - vec![ - "MoAAAAAAAAAAAAAAAAAAAA==", - "sUgAAAAAAAAAAAAAAAAAAA==", - "MbQAAAAAAAAAAAAAAAAAAA==", - "AAhAAAAAAAAAAAAAAAAAAA==" - ] - ); - //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); - } - - #[test] - fn test_poly_mul_with_zero() { - let json1 = json!([ - "JAAAAAAAAAAAAAAAAAAAAA==", - "wAAAAAAAAAAAAAAAAAAAAA==", - "ACAAAAAAAAAAAAAAAAAAAA==" - ]); - let json2 = json!(["AAAAAAAAAAAAAAAAAAAAAA=="]); - let element1: Polynomial = Polynomial::from_c_array(&json1); - let element2: Polynomial = Polynomial::from_c_array(&json2); - - //eprintln!("{:?}", element1); - - let result = element1 * element2; - - assert_eq!(result.to_c_array(), vec!["AAAAAAAAAAAAAAAAAAAAAA=="]); - //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); - } - - #[test] - fn test_poly_pow_01() { - let json1 = json!([ - "JAAAAAAAAAAAAAAAAAAAAA==", - "wAAAAAAAAAAAAAAAAAAAAA==", - "ACAAAAAAAAAAAAAAAAAAAA==" - ]); - let element1: Polynomial = Polynomial::from_c_array(&json1); - - let result = element1.pow(3); - - assert_eq!( - result.to_c_array(), - vec![ - "AkkAAAAAAAAAAAAAAAAAAA==", - "DDAAAAAAAAAAAAAAAAAAAA==", - "LQIIAAAAAAAAAAAAAAAAAA==", - "8AAAAAAAAAAAAAAAAAAAAA==", - "ACgCQAAAAAAAAAAAAAAAAA==", - "AAAMAAAAAAAAAAAAAAAAAA==", - "AAAAAgAAAAAAAAAAAAAAAA==" - ] - ); - //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); - } - - #[test] - fn test_poly_pow_with_zero() { - let json1 = json!([ - "JAAAAAAAAAAAAAAAAAAAAA==", - "wAAAAAAAAAAAAAAAAAAAAA==", - "ACAAAAAAAAAAAAAAAAAAAA==" - ]); - let element1: Polynomial = Polynomial::from_c_array(&json1); - - let result = element1.pow(0); - - assert_eq!(result.to_c_array(), vec!["gAAAAAAAAAAAAAAAAAAAAA=="]); - //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); - } - - #[test] - fn test_field_pow_mod_01() { - let json1 = json!([ - "JAAAAAAAAAAAAAAAAAAAAA==", - "wAAAAAAAAAAAAAAAAAAAAA==", - "ACAAAAAAAAAAAAAAAAAAAA==" - ]); - let element1: Polynomial = Polynomial::from_c_array(&json1); - - let result = element1.pow(3); - - assert_eq!( - result.to_c_array(), - vec![ - "AkkAAAAAAAAAAAAAAAAAAA==", - "DDAAAAAAAAAAAAAAAAAAAA==", - "LQIIAAAAAAAAAAAAAAAAAA==", - "8AAAAAAAAAAAAAAAAAAAAA==", - "ACgCQAAAAAAAAAAAAAAAAA==", - "AAAMAAAAAAAAAAAAAAAAAA==", - "AAAAAgAAAAAAAAAAAAAAAA==" - ] - ); - //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); - } - - #[test] - fn test_field_pow_mod_with_zero() { - let json1 = json!([ - "JAAAAAAAAAAAAAAAAAAAAA==", - "wAAAAAAAAAAAAAAAAAAAAA==", - "ACAAAAAAAAAAAAAAAAAAAA==" - ]); - let element1: Polynomial = Polynomial::from_c_array(&json1); - - let result = element1.pow(0); - - assert_eq!(result.to_c_array(), vec!["gAAAAAAAAAAAAAAAAAAAAA=="]); - //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); - } - - #[test] - fn test_poly_div_01() { - let element1 = - FieldElement::new(BASE64_STANDARD.decode("JAAAAAAAAAAAAAAAAAAAAA==").unwrap()); - - let element2 = - FieldElement::new(BASE64_STANDARD.decode("wAAAAAAAAAAAAAAAAAAAAA==").unwrap()); - - let result = element1 / element2; - - assert_eq!(BASE64_STANDARD.encode(result), "OAAAAAAAAAAAAAAAAAAAAA=="); - } - - #[test] - fn test_field_poly_div_01() { - let json1 = json!([ - "JAAAAAAAAAAAAAAAAAAAAA==", - "wAAAAAAAAAAAAAAAAAAAAA==", - "ACAAAAAAAAAAAAAAAAAAAA==" - ]); - let json2 = json!(["0AAAAAAAAAAAAAAAAAAAAA==", "IQAAAAAAAAAAAAAAAAAAAA=="]); - let element1: Polynomial = Polynomial::from_c_array(&json1); - let element2: Polynomial = Polynomial::from_c_array(&json2); - - //eprintln!("{:?}", element1); - - println!("Beginning the new division"); - let (result, remainder) = element1.div(&element2); - - assert_eq!( - result.to_c_array(), - vec!["nAIAgCAIAgCAIAgCAIAgCg==", "m85znOc5znOc5znOc5znOQ=="] - ); - assert_eq!(remainder.to_c_array(), vec!["lQNA0DQNA0DQNA0DQNA0Dg=="]); - //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); - } - - #[test] - fn test_field_poly_div_larger_div() { - let json1 = json!([ - "JAAAAAAAAAAAAAAAAAAAAA==", - "wAAAAAAAAAAAAAAAAAAAAA==", - "ACAAAAAAAAAAAAAAAAAAAA==" - ]); - let json2 = json!(["0AAAAAAAAAAAAAAAAAAAAA==", "IQAAAAAAAAAAAAAAAAAAAA=="]); - let element1: Polynomial = Polynomial::from_c_array(&json1); - let element2: Polynomial = Polynomial::from_c_array(&json2); - - //eprintln!("{:?}", element1); - - println!("Beginning the new division"); - let (result, remainder) = element2.div(&element1); - - assert_eq!(result.to_c_array(), vec!["AAAAAAAAAAAAAAAAAAAAAA=="]); - assert_eq!( - remainder.to_c_array(), - vec!["0AAAAAAAAAAAAAAAAAAAAA==", "IQAAAAAAAAAAAAAAAAAAAA=="] - ); - //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); - } - - #[test] - fn test_field_poly_div_eqdeg() { - let json1 = json!(["JAAAAAAAAAAAAAAAAAAAAA==", "wAAAAAAAAAAAAAAAAAAAAA==",]); - let json2 = json!(["0AAAAAAAAAAAAAAAAAAAAA==", "IQAAAAAAAAAAAAAAAAAAAA=="]); - let element1: Polynomial = Polynomial::from_c_array(&json1); - let element2: Polynomial = Polynomial::from_c_array(&json2); - - let (result, remainder) = element2.div(&element1); - - eprintln!("{:02X?}", (&result, &remainder)); - - assert!(!result.is_zero()); - assert!(!remainder.is_zero()); - //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); - } - - #[test] - fn test_field_poly_div_eqdeg_02() { - let json1 = json!(["JAAAAAAAAAAAAAAAAAAAAA==", "wAAAAAAAAAAAAAAAAAAAAA==",]); - let json2 = json!(["KryptoanalyseAAAAAAAAA==", "DHBWMannheimAAAAAAAAAA=="]); - let element1: Polynomial = Polynomial::from_c_array(&json1); - let element2: Polynomial = Polynomial::from_c_array(&json2); - - let (result, remainder) = element2.div(&element1); - - eprintln!("{:02X?}", (&result, &remainder)); - - assert!(!result.is_zero()); - assert!(!remainder.is_zero()); - //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); - } - - #[test] - fn test_field_poly_powmod_01() { - let json1 = json!([ - "JAAAAAAAAAAAAAAAAAAAAA==", - "wAAAAAAAAAAAAAAAAAAAAA==", - "ACAAAAAAAAAAAAAAAAAAAA==" - ]); - let json2 = json!(["KryptoanalyseAAAAAAAAA==", "DHBWMannheimAAAAAAAAAA=="]); - let element1: Polynomial = Polynomial::from_c_array(&json1); - let modulus: Polynomial = Polynomial::from_c_array(&json2); - - let result = element1.pow_mod(1000, modulus); - - eprintln!("Result is: {:02X?}", result); - assert_eq!(result.to_c_array(), vec!["oNXl5P8xq2WpUTP92u25zg=="]); - } - - #[test] - fn test_field_poly_powmod_k1() { - let json1 = json!(["JAAAAAAAAAAAAAAAAAAAAA==",]); - let json2 = json!(["KryptoanalyseAAAAAAAAA==", "DHBWMannheimAAAAAAAAAA=="]); - let element1: Polynomial = Polynomial::from_c_array(&json1); - let modulus: Polynomial = Polynomial::from_c_array(&json2); - - let result = element1.pow_mod(1, modulus); - - eprintln!("Result is: {:02X?}", result); - assert_eq!(result.to_c_array(), vec!["JAAAAAAAAAAAAAAAAAAAAA=="]); - } - - #[test] - fn test_field_poly_powmod_k0_special() { - let json1 = json!(["NeverGonnaGiveYouUpAAA=="]); - let json2 = json!(["NeverGonnaGiveYouUpAAA=="]); - let element1: Polynomial = Polynomial::from_c_array(&json1); - let modulus: Polynomial = Polynomial::from_c_array(&json2); - - let result = element1.pow_mod(0, modulus); - - eprintln!("Result is: {:02X?}", result); - - assert_eq!(result.to_c_array(), vec!["gAAAAAAAAAAAAAAAAAAAAA=="]); - } - - #[test] - fn test_field_poly_powmod_k0() { - let json1 = json!(["JAAAAAAAAAAAAAAAAAAAAA==",]); - let json2 = json!(["KryptoanalyseAAAAAAAAA=="]); - let element1: Polynomial = Polynomial::from_c_array(&json1); - let modulus: Polynomial = Polynomial::from_c_array(&json2); - - let result = element1.pow_mod(0, modulus); - - eprintln!("Result is: {:02X?}", result); - assert_eq!(result.to_c_array(), vec!["gAAAAAAAAAAAAAAAAAAAAA=="]); - } - - #[test] - fn test_field_pow_mod_10mill() { - let json1 = json!([ - "JAAAAAAAAAAAAAAAAAAAAA==", - "wAAAAAAAAAAAAAAAAAAAAA==", - "ACAAAAAAAAAAAAAAAAAAAA==" - ]); - let json2 = json!(["KryptoanalyseAAAAAAAAA==", "DHBWMannheimAAAAAAAAAA=="]); - let element1: Polynomial = Polynomial::from_c_array(&json1); - let modulus: Polynomial = Polynomial::from_c_array(&json2); - - let result = element1.pow_mod(10000000, modulus); - - assert!(!result.is_zero()) - //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); - } } diff --git a/src/utils/poly.rs b/src/utils/poly.rs index 3866e49..99def36 100644 --- a/src/utils/poly.rs +++ b/src/utils/poly.rs @@ -1,8 +1,391 @@ use crate::utils::field::ByteArray; -use anyhow::{anyhow, Result}; use base64::prelude::*; use std::{str::FromStr, u128, u8, usize}; +use std::{ + cmp::Ordering, + mem::discriminant, + ops::{Add, BitXor, Div, Mul, Sub}, +}; + +use anyhow::{anyhow, Ok, Result}; +use serde_json::Value; + +use super::field::FieldElement; +use super::math::{reverse_bits_in_bytevec, xor_bytes}; + +#[derive(Debug, serde::Serialize)] +pub struct Polynomial { + polynomial: Vec, +} + +impl Polynomial { + pub const fn new(polynomial: Vec) -> Self { + Self { polynomial } + } + + pub fn from_c_array(array: &Value) -> Self { + let mut polynomial: Vec = vec![]; + let c_array: Vec = array + .as_array() + .expect("Input is not an array") + .iter() + .map(|x| { + x.as_str() + .expect("Array element is not a string") + .to_string() + }) + .collect(); + + eprintln!("{:?}", c_array); + + for coefficient in c_array { + polynomial.push(FieldElement::new( + BASE64_STANDARD + .decode(coefficient) + .expect("Error on poly decode:"), + )); + } + Self { polynomial } + } + + pub fn to_c_array(self) -> Vec { + let mut output: Vec = vec![]; + for coeff in self.polynomial { + output.push(BASE64_STANDARD.encode(coeff)); + } + + output + } + + pub fn pow(&self, mut exponent: u128) -> Polynomial { + if exponent == 0 { + return Polynomial::new(vec![FieldElement::new( + polynomial_2_block(vec![0], "gcm").unwrap(), + )]); + } + + let base = self.clone(); + let mut result = base.clone(); + exponent -= 1; + while exponent > 0 { + result = result * base.clone(); + exponent -= 1; + } + + result + } + + pub fn pow_mod(mut self, mut exponent: u128, modulus: Polynomial) -> Polynomial { + let mut result: Polynomial = Polynomial::new(vec![FieldElement::new( + polynomial_2_block(vec![0], "gcm").unwrap(), + )]); + + if exponent == 1 { + eprintln!("special case 1: {:02X?}", self.clone().div(&modulus).1); + + return self.div(&modulus).1; + } + + if exponent == 0 { + let result = Polynomial::new(vec![FieldElement::new( + polynomial_2_block(vec![0], "gcm").unwrap(), + )]); + + eprintln!("Returned value is: {:02X?}", result); + return result; + } + + //eprintln!("Initial result: {:?}", result); + while exponent > 0 { + //eprintln!("Current exponent: {:02X}", exponent); + if exponent & 1 == 1 { + let temp = &self * &result; + //eprintln!("After multiplication: {:?}", temp); + result = temp.div(&modulus).1; + //eprintln!("After mod: {:?}", result); + } + let temp_square = &self * &self; + //eprintln!("After squaring: {:?}", temp_square); + self = temp_square.div(&modulus).1; + //eprintln!("After mod: {:?}", self); + exponent >>= 1; + } + + eprintln!("result in powmod before reduction: {:02X?}", result); + + while !result.polynomial.is_empty() + && result + .polynomial + .last() + .unwrap() + .as_ref() + .iter() + .all(|&x| x == 0) + { + result.polynomial.pop(); + } + + eprintln!("result in powmod after reduction: {:02X?}", result); + + if result.is_empty() { + result = Polynomial::new(vec![FieldElement::new(vec![0; 16])]); + } + + result + } + + // Returns (quotient, remainder) + pub fn div(self, rhs: &Self) -> (Self, Self) { + // Div by zero check ommitted since data is guaranteed to be non 0 + + eprintln!("{:?}, {:?}", self.polynomial.len(), rhs.polynomial.len()); + + if self.polynomial.len() < rhs.polynomial.len() { + return (Polynomial::new(vec![FieldElement::new(vec![0; 16])]), self); + } + + let mut remainder = self.clone(); + let divisor = rhs; + let dividend_deg = remainder.polynomial.len() - 1; + let divisor_deg = divisor.polynomial.len() - 1; + + if dividend_deg < divisor_deg { + return ( + Polynomial::new(vec![FieldElement::new( + polynomial_2_block(vec![0; 16], "gcm").unwrap(), + )]), + remainder, + ); + } + + let mut quotient_coeffs = + vec![ + FieldElement::new(polynomial_2_block(vec![0; 16], "gcm").unwrap()); + dividend_deg - divisor_deg + 1 + ]; + + while remainder.polynomial.len() >= divisor.polynomial.len() { + let deg_diff = remainder.polynomial.len() - divisor.polynomial.len(); + + let leading_dividend = remainder.polynomial.last().unwrap(); + let leading_divisor = divisor.polynomial.last().unwrap(); + let quot_coeff = leading_dividend / leading_divisor; + + quotient_coeffs[deg_diff] = quot_coeff.clone(); + + let mut subtrahend = + vec![FieldElement::new(polynomial_2_block(vec![0; 16], "gcm").unwrap()); deg_diff]; + subtrahend.extend( + divisor + .polynomial + .iter() + .map(|x| x.clone() * quot_coeff.clone()), + ); + let subtrahend_poly = Polynomial::new(subtrahend); + + remainder = remainder + subtrahend_poly; + + while !remainder.polynomial.is_empty() + && remainder + .polynomial + .last() + .unwrap() + .as_ref() + .iter() + .all(|&x| x == 0) + { + remainder.polynomial.pop(); + } + } + + if remainder.is_empty() { + remainder = Polynomial::new(vec![FieldElement::new(vec![0; 16])]); + } + (Polynomial::new(quotient_coeffs), remainder) + } + + fn is_zero(&self) -> bool { + for field_element in &self.polynomial { + if !field_element.is_zero() { + return false; + } + } + true + } + + fn monic(mut self) -> Self { + let divident = self.polynomial.last().unwrap().clone(); + + for fieldelement in &mut self.polynomial.iter_mut() { + *fieldelement = fieldelement.clone() / divident.clone(); + } + + self + } +} + +impl Clone for Polynomial { + fn clone(&self) -> Self { + Polynomial { + polynomial: self.polynomial.clone(), + } + } +} + +impl Mul for Polynomial { + type Output = Self; + fn mul(self, rhs: Self) -> Self::Output { + if self.is_zero() || rhs.is_zero() { + return Polynomial::new(vec![FieldElement::new(vec![0; 16])]); + } + let mut polynomial: Vec = + vec![FieldElement::new(vec![0; 16]); self.polynomial.len() + rhs.polynomial.len() - 1]; + for i in 0..self.polynomial.len() { + for j in 0..rhs.polynomial.len() { + polynomial[i + j] = &polynomial[i + j] + + &(self.polynomial.get(i).unwrap() * rhs.polynomial.get(j).unwrap()); + } + } + Polynomial::new(polynomial) + } +} + +impl Mul for &Polynomial { + type Output = Polynomial; + fn mul(self, rhs: Self) -> Self::Output { + if self.is_zero() || rhs.is_zero() { + return Polynomial::new(vec![FieldElement::new(vec![0])]); + } + let mut polynomial: Vec = + vec![FieldElement::new(vec![0; 16]); self.polynomial.len() + rhs.polynomial.len() - 1]; + for i in 0..self.polynomial.len() { + for j in 0..rhs.polynomial.len() { + polynomial[i + j] = &polynomial[i + j] + + &(self.polynomial.get(i).unwrap() * rhs.polynomial.get(j).unwrap()); + } + } + Polynomial::new(polynomial) + } +} + +impl Add for Polynomial { + type Output = Self; + fn add(self, rhs: Self) -> Self::Output { + let mut polynomial: Vec; + + if self.polynomial.len() > rhs.polynomial.len() { + polynomial = self.polynomial.clone(); + for i in 0..rhs.polynomial.len() { + polynomial[i] = polynomial[i].clone() + rhs.polynomial[i].clone(); + } + } else { + polynomial = rhs.polynomial.clone(); + for i in 0..self.polynomial.len() { + polynomial[i] = polynomial[i].clone() + self.polynomial[i].clone(); + } + } + + while !polynomial.is_empty() && polynomial.last().unwrap().as_ref().iter().all(|&x| x == 0) + { + polynomial.pop(); + } + + if polynomial.is_empty() { + return Polynomial::new(vec![FieldElement::new(vec![0; 16])]); + } + + Polynomial::new(polynomial) + } +} + +trait IsEmpty { + fn is_empty(&self) -> bool; +} + +impl IsEmpty for Polynomial { + fn is_empty(&self) -> bool { + self.polynomial.is_empty() + } +} +impl AsRef<[FieldElement]> for Polynomial { + fn as_ref(&self) -> &[FieldElement] { + &self.polynomial + } +} + +impl PartialEq for Polynomial { + fn eq(&self, other: &Self) -> bool { + if self.polynomial.len() != other.polynomial.len() { + return false; + } + // Compare each coefficient + self.polynomial + .iter() + .zip(other.polynomial.iter()) + .all(|(a, b)| a == b) + } +} + +impl PartialOrd for Polynomial { + fn partial_cmp(&self, other: &Self) -> Option { + match other.polynomial.len().cmp(&self.polynomial.len()) { + Ordering::Equal => { + for (field_a, field_b) in + self.as_ref().iter().rev().zip(other.as_ref().iter().rev()) + { + eprintln!( + "Poly partord: {:02X?} {:02X?} ", + self.clone().to_c_array(), + other.clone().to_c_array() + ); + + match field_a + .reverse_bits() + .partial_cmp(&field_b.reverse_bits()) + .unwrap() + { + Ordering::Equal => continue, + other => return Some(other), + } + } + Some(Ordering::Equal) + } + other => Some(other.reverse()), + } + } +} + +impl Eq for Polynomial {} + +impl Ord for Polynomial { + fn cmp(&self, other: &Self) -> Ordering { + match other.polynomial.len().cmp(&self.polynomial.len()) { + Ordering::Equal => { + for (field_a, field_b) in + self.as_ref().iter().rev().zip(other.as_ref().iter().rev()) + { + match field_a.reverse_bits().cmp(&field_b.reverse_bits()) { + Ordering::Equal => continue, + other => return other, + } + } + Ordering::Equal + } + other => other.reverse(), + } + } +} + +pub fn sort_polynomial_array(mut polys: Vec) -> Result> { + // Algorithm to sort polynomials + // First sorting round + // Sorting by degree of polynomial + polys.sort(); + + Ok(polys) +} + pub const RED_POLY: u128 = 0x87000000_00000000_00000000_00000000; pub fn gfmul(poly_a: &Vec, poly_b: &Vec, semantic: &str) -> Result> { @@ -189,6 +572,7 @@ pub fn coefficient_to_binary(coefficients: Vec) -> u128 { mod tests { use crate::utils::poly::b64_2_num; use anyhow::Result; + use serde_json::json; // Note this useful idiom: importing names from outer (for mod tests) scope. use super::*; @@ -256,4 +640,437 @@ mod tests { Ok(()) } + + #[test] + fn test_field_add_03() { + let json1 = json!([ + "NeverGonnaGiveYouUpAAA==", + "NeverGonnaLetYouDownAA==", + "NeverGonnaRunAroundAAA==", + "AndDesertYouAAAAAAAAAA==" + ]); + let json2 = json!(["KryptoanalyseAAAAAAAAA==", "DHBWMannheimAAAAAAAAAA=="]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + let element2: Polynomial = Polynomial::from_c_array(&json2); + + let sum = element2 + element1; + + assert_eq!( + sum.to_c_array(), + vec![ + "H1d3GuyA9/0OxeYouUpAAA==", + "OZuIncPAGEp4tYouDownAA==", + "NeverGonnaRunAroundAAA==", + "AndDesertYouAAAAAAAAAA==" + ] + ); + } + + #[test] + fn test_field_add_multiple_zeros() { + let json1 = json!([ + "AAAAAAAAAAAAAAAAAAAAAA==", + "AAAAAAAAAAAAAAAAAAAAAA==", + "AAAAAAAAAAAAAAAAAAAAAA==", + "AAAAAAAAAAAAAAAAAAAAAA==" + ]); + let json2 = json!(["AAAAAAAAAAAAAAAAAAAAAA==", "AAAAAAAAAAAAAAAAAAAAAA=="]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + let element2: Polynomial = Polynomial::from_c_array(&json2); + + let sum = element2 + element1; + + assert_eq!(sum.to_c_array(), vec!["AAAAAAAAAAAAAAAAAAAAAA==",]); + } + + #[test] + fn test_field_add_same_element() { + let json1 = json!(["NeverGonnaGiveYouUpAAA=="]); + let json2 = json!(["NeverGonnaGiveYouUpAAA=="]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + let element2: Polynomial = Polynomial::from_c_array(&json2); + + let sum = element2 + element1; + + assert_eq!(sum.to_c_array(), vec!["AAAAAAAAAAAAAAAAAAAAAA==",]); + } + + #[test] + fn test_field_add_zero() { + let json1 = json!([ + "NeverGonnaGiveYouUpAAA==", + "NeverGonnaLetYouDownAA==", + "NeverGonnaRunAroundAAA==", + "AndDesertYouAAAAAAAAAA==" + ]); + let json2 = json!(["AAAAAAAAAAAAAAAAAAAAAA=="]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + let element2: Polynomial = Polynomial::from_c_array(&json2); + + let sum = element2 + element1; + + assert_eq!( + sum.to_c_array(), + vec![ + "NeverGonnaGiveYouUpAAA==", + "NeverGonnaLetYouDownAA==", + "NeverGonnaRunAroundAAA==", + "AndDesertYouAAAAAAAAAA==" + ] + ); + } + + #[test] + fn test_field_add_zero_to_zero() { + let json1 = json!(["AAAAAAAAAAAAAAAAAAAAAA=="]); + let json2 = json!(["AAAAAAAAAAAAAAAAAAAAAA=="]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + let element2: Polynomial = Polynomial::from_c_array(&json2); + + let sum = element2 + element1; + + assert_eq!(sum.to_c_array(), vec!["AAAAAAAAAAAAAAAAAAAAAA=="]); + } + + #[test] + fn test_field_add_short_to_long() { + let json1 = json!(["AAAAAAAAAAAAAAAAAAAAAA=="]); + let json2 = json!([ + "NeverGonnaGiveYouUpAAA==", + "NeverGonnaLetYouDownAA==", + "NeverGonnaRunAroundAAA==", + "AndDesertYouAAAAAAAAAA==" + ]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + let element2: Polynomial = Polynomial::from_c_array(&json2); + + let sum = element2 + element1; + + assert_eq!( + sum.to_c_array(), + vec![ + "NeverGonnaGiveYouUpAAA==", + "NeverGonnaLetYouDownAA==", + "NeverGonnaRunAroundAAA==", + "AndDesertYouAAAAAAAAAA==" + ] + ); + } + + #[test] + fn test_field_mul_01() { + let json1 = json!([ + "JAAAAAAAAAAAAAAAAAAAAA==", + "wAAAAAAAAAAAAAAAAAAAAA==", + "ACAAAAAAAAAAAAAAAAAAAA==" + ]); + let json2 = json!(["0AAAAAAAAAAAAAAAAAAAAA==", "IQAAAAAAAAAAAAAAAAAAAA=="]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + let element2: Polynomial = Polynomial::from_c_array(&json2); + + //eprintln!("{:?}", element1); + + let result = element1 * element2; + + assert_eq!( + result.to_c_array(), + vec![ + "MoAAAAAAAAAAAAAAAAAAAA==", + "sUgAAAAAAAAAAAAAAAAAAA==", + "MbQAAAAAAAAAAAAAAAAAAA==", + "AAhAAAAAAAAAAAAAAAAAAA==" + ] + ); + //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); + } + + #[test] + fn test_poly_mul_with_zero() { + let json1 = json!([ + "JAAAAAAAAAAAAAAAAAAAAA==", + "wAAAAAAAAAAAAAAAAAAAAA==", + "ACAAAAAAAAAAAAAAAAAAAA==" + ]); + let json2 = json!(["AAAAAAAAAAAAAAAAAAAAAA=="]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + let element2: Polynomial = Polynomial::from_c_array(&json2); + + //eprintln!("{:?}", element1); + + let result = element1 * element2; + + assert_eq!(result.to_c_array(), vec!["AAAAAAAAAAAAAAAAAAAAAA=="]); + //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); + } + + #[test] + fn test_poly_pow_01() { + let json1 = json!([ + "JAAAAAAAAAAAAAAAAAAAAA==", + "wAAAAAAAAAAAAAAAAAAAAA==", + "ACAAAAAAAAAAAAAAAAAAAA==" + ]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + + let result = element1.pow(3); + + assert_eq!( + result.to_c_array(), + vec![ + "AkkAAAAAAAAAAAAAAAAAAA==", + "DDAAAAAAAAAAAAAAAAAAAA==", + "LQIIAAAAAAAAAAAAAAAAAA==", + "8AAAAAAAAAAAAAAAAAAAAA==", + "ACgCQAAAAAAAAAAAAAAAAA==", + "AAAMAAAAAAAAAAAAAAAAAA==", + "AAAAAgAAAAAAAAAAAAAAAA==" + ] + ); + //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); + } + + #[test] + fn test_poly_pow_with_zero() { + let json1 = json!([ + "JAAAAAAAAAAAAAAAAAAAAA==", + "wAAAAAAAAAAAAAAAAAAAAA==", + "ACAAAAAAAAAAAAAAAAAAAA==" + ]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + + let result = element1.pow(0); + + assert_eq!(result.to_c_array(), vec!["gAAAAAAAAAAAAAAAAAAAAA=="]); + //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); + } + + #[test] + fn test_field_pow_mod_01() { + let json1 = json!([ + "JAAAAAAAAAAAAAAAAAAAAA==", + "wAAAAAAAAAAAAAAAAAAAAA==", + "ACAAAAAAAAAAAAAAAAAAAA==" + ]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + + let result = element1.pow(3); + + assert_eq!( + result.to_c_array(), + vec![ + "AkkAAAAAAAAAAAAAAAAAAA==", + "DDAAAAAAAAAAAAAAAAAAAA==", + "LQIIAAAAAAAAAAAAAAAAAA==", + "8AAAAAAAAAAAAAAAAAAAAA==", + "ACgCQAAAAAAAAAAAAAAAAA==", + "AAAMAAAAAAAAAAAAAAAAAA==", + "AAAAAgAAAAAAAAAAAAAAAA==" + ] + ); + //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); + } + + #[test] + fn test_field_pow_mod_with_zero() { + let json1 = json!([ + "JAAAAAAAAAAAAAAAAAAAAA==", + "wAAAAAAAAAAAAAAAAAAAAA==", + "ACAAAAAAAAAAAAAAAAAAAA==" + ]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + + let result = element1.pow(0); + + assert_eq!(result.to_c_array(), vec!["gAAAAAAAAAAAAAAAAAAAAA=="]); + //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); + } + + #[test] + fn test_poly_div_01() { + let element1 = + FieldElement::new(BASE64_STANDARD.decode("JAAAAAAAAAAAAAAAAAAAAA==").unwrap()); + + let element2 = + FieldElement::new(BASE64_STANDARD.decode("wAAAAAAAAAAAAAAAAAAAAA==").unwrap()); + + let result = element1 / element2; + + assert_eq!(BASE64_STANDARD.encode(result), "OAAAAAAAAAAAAAAAAAAAAA=="); + } + + #[test] + fn test_field_poly_div_01() { + let json1 = json!([ + "JAAAAAAAAAAAAAAAAAAAAA==", + "wAAAAAAAAAAAAAAAAAAAAA==", + "ACAAAAAAAAAAAAAAAAAAAA==" + ]); + let json2 = json!(["0AAAAAAAAAAAAAAAAAAAAA==", "IQAAAAAAAAAAAAAAAAAAAA=="]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + let element2: Polynomial = Polynomial::from_c_array(&json2); + + //eprintln!("{:?}", element1); + + println!("Beginning the new division"); + let (result, remainder) = element1.div(&element2); + + assert_eq!( + result.to_c_array(), + vec!["nAIAgCAIAgCAIAgCAIAgCg==", "m85znOc5znOc5znOc5znOQ=="] + ); + assert_eq!(remainder.to_c_array(), vec!["lQNA0DQNA0DQNA0DQNA0Dg=="]); + //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); + } + + #[test] + fn test_field_poly_div_larger_div() { + let json1 = json!([ + "JAAAAAAAAAAAAAAAAAAAAA==", + "wAAAAAAAAAAAAAAAAAAAAA==", + "ACAAAAAAAAAAAAAAAAAAAA==" + ]); + let json2 = json!(["0AAAAAAAAAAAAAAAAAAAAA==", "IQAAAAAAAAAAAAAAAAAAAA=="]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + let element2: Polynomial = Polynomial::from_c_array(&json2); + + //eprintln!("{:?}", element1); + + println!("Beginning the new division"); + let (result, remainder) = element2.div(&element1); + + assert_eq!(result.to_c_array(), vec!["AAAAAAAAAAAAAAAAAAAAAA=="]); + assert_eq!( + remainder.to_c_array(), + vec!["0AAAAAAAAAAAAAAAAAAAAA==", "IQAAAAAAAAAAAAAAAAAAAA=="] + ); + //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); + } + + #[test] + fn test_field_poly_div_eqdeg() { + let json1 = json!(["JAAAAAAAAAAAAAAAAAAAAA==", "wAAAAAAAAAAAAAAAAAAAAA==",]); + let json2 = json!(["0AAAAAAAAAAAAAAAAAAAAA==", "IQAAAAAAAAAAAAAAAAAAAA=="]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + let element2: Polynomial = Polynomial::from_c_array(&json2); + + let (result, remainder) = element2.div(&element1); + + eprintln!("{:02X?}", (&result, &remainder)); + + assert!(!result.is_zero()); + assert!(!remainder.is_zero()); + //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); + } + + #[test] + fn test_field_poly_div_eqdeg_02() { + let json1 = json!(["JAAAAAAAAAAAAAAAAAAAAA==", "wAAAAAAAAAAAAAAAAAAAAA==",]); + let json2 = json!(["KryptoanalyseAAAAAAAAA==", "DHBWMannheimAAAAAAAAAA=="]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + let element2: Polynomial = Polynomial::from_c_array(&json2); + + let (result, remainder) = element2.div(&element1); + + eprintln!("{:02X?}", (&result, &remainder)); + + assert!(!result.is_zero()); + assert!(!remainder.is_zero()); + //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); + } + + #[test] + fn test_field_poly_powmod_01() { + let json1 = json!([ + "JAAAAAAAAAAAAAAAAAAAAA==", + "wAAAAAAAAAAAAAAAAAAAAA==", + "ACAAAAAAAAAAAAAAAAAAAA==" + ]); + let json2 = json!(["KryptoanalyseAAAAAAAAA==", "DHBWMannheimAAAAAAAAAA=="]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + let modulus: Polynomial = Polynomial::from_c_array(&json2); + + let result = element1.pow_mod(1000, modulus); + + eprintln!("Result is: {:02X?}", result); + assert_eq!(result.to_c_array(), vec!["oNXl5P8xq2WpUTP92u25zg=="]); + } + + #[test] + fn test_field_poly_powmod_k1() { + let json1 = json!(["JAAAAAAAAAAAAAAAAAAAAA==",]); + let json2 = json!(["KryptoanalyseAAAAAAAAA==", "DHBWMannheimAAAAAAAAAA=="]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + let modulus: Polynomial = Polynomial::from_c_array(&json2); + + let result = element1.pow_mod(1, modulus); + + eprintln!("Result is: {:02X?}", result); + assert_eq!(result.to_c_array(), vec!["JAAAAAAAAAAAAAAAAAAAAA=="]); + } + + #[test] + fn test_field_poly_powmod_k0_special() { + let json1 = json!(["NeverGonnaGiveYouUpAAA=="]); + let json2 = json!(["NeverGonnaGiveYouUpAAA=="]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + let modulus: Polynomial = Polynomial::from_c_array(&json2); + + let result = element1.pow_mod(0, modulus); + + eprintln!("Result is: {:02X?}", result); + + assert_eq!(result.to_c_array(), vec!["gAAAAAAAAAAAAAAAAAAAAA=="]); + } + + #[test] + fn test_field_poly_powmod_k0() { + let json1 = json!(["JAAAAAAAAAAAAAAAAAAAAA==",]); + let json2 = json!(["KryptoanalyseAAAAAAAAA=="]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + let modulus: Polynomial = Polynomial::from_c_array(&json2); + + let result = element1.pow_mod(0, modulus); + + eprintln!("Result is: {:02X?}", result); + assert_eq!(result.to_c_array(), vec!["gAAAAAAAAAAAAAAAAAAAAA=="]); + } + + #[test] + fn test_field_pow_mod_10mill() { + let json1 = json!([ + "JAAAAAAAAAAAAAAAAAAAAA==", + "wAAAAAAAAAAAAAAAAAAAAA==", + "ACAAAAAAAAAAAAAAAAAAAA==" + ]); + let json2 = json!(["KryptoanalyseAAAAAAAAA==", "DHBWMannheimAAAAAAAAAA=="]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + let modulus: Polynomial = Polynomial::from_c_array(&json2); + + let result = element1.pow_mod(10000000, modulus); + + assert!(!result.is_zero()) + //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); + } + + #[test] + fn test_poly_monic() { + let json1 = json!([ + "NeverGonnaGiveYouUpAAA==", + "NeverGonnaLetYouDownAA==", + "NeverGonnaRunAroundAAA==", + "AndDesertYouAAAAAAAAAA==" + ]); + let expected = json!([ + "edY47onJ4MtCENDTHG/sZw==", + "oaXjCKnceBIxSavZ9eFT8w==", + "1Ial5rAJGOucIdUe3zh5bw==", + "gAAAAAAAAAAAAAAAAAAAAA==" + ]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + + let result = element1.monic(); + + assert_eq!(json!(result.to_c_array()), expected); + //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); + } } From 5e50ef6091f4c3a72586432757dfc063f701201e Mon Sep 17 00:00:00 2001 From: Alivecow Date: Fri, 22 Nov 2024 15:28:36 +0100 Subject: [PATCH 2/3] refactor: apply cargo recommended cleanups --- src/tasks/tasks01/pad_oracle.rs | 1 - src/utils/field.rs | 6 ++---- src/utils/poly.rs | 4 +--- 3 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/tasks/tasks01/pad_oracle.rs b/src/tasks/tasks01/pad_oracle.rs index 90e4295..4286e37 100644 --- a/src/tasks/tasks01/pad_oracle.rs +++ b/src/tasks/tasks01/pad_oracle.rs @@ -3,7 +3,6 @@ use base64::prelude::*; use serde_json::Value; use std::io::prelude::*; use std::net::TcpStream; -use std::time::Instant; use std::usize; pub fn padding_oracle(args: &Value) -> Result> { diff --git a/src/utils/field.rs b/src/utils/field.rs index 6894023..82234da 100644 --- a/src/utils/field.rs +++ b/src/utils/field.rs @@ -1,14 +1,12 @@ use base64::prelude::*; -use std::{str::FromStr, u128, u8, usize}; +use std::{u128, u8, usize}; use std::{ cmp::Ordering, - mem::discriminant, - ops::{Add, BitXor, Div, Mul, Sub}, + ops::{Add, BitXor, Div, Mul}, }; use anyhow::{anyhow, Ok, Result}; -use serde_json::Value; use super::poly::polynomial_2_block; use super::{ diff --git a/src/utils/poly.rs b/src/utils/poly.rs index 99def36..bb05366 100644 --- a/src/utils/poly.rs +++ b/src/utils/poly.rs @@ -4,15 +4,13 @@ use std::{str::FromStr, u128, u8, usize}; use std::{ cmp::Ordering, - mem::discriminant, - ops::{Add, BitXor, Div, Mul, Sub}, + ops::{Add, Div, Mul}, }; use anyhow::{anyhow, Ok, Result}; use serde_json::Value; use super::field::FieldElement; -use super::math::{reverse_bits_in_bytevec, xor_bytes}; #[derive(Debug, serde::Serialize)] pub struct Polynomial { From 6391912bc4fdb9bb67c829c588249ecc8405f595 Mon Sep 17 00:00:00 2001 From: Alivecow Date: Fri, 22 Nov 2024 15:47:59 +0100 Subject: [PATCH 3/3] feat: Add and improve poly monic function with testcases Make a polynomial monic by dividing all field elements with the leading element --- src/utils/poly.rs | 45 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 43 insertions(+), 2 deletions(-) diff --git a/src/utils/poly.rs b/src/utils/poly.rs index bb05366..e624361 100644 --- a/src/utils/poly.rs +++ b/src/utils/poly.rs @@ -219,6 +219,22 @@ impl Polynomial { *fieldelement = fieldelement.clone() / divident.clone(); } + while !self.polynomial.is_empty() + && self + .polynomial + .last() + .unwrap() + .as_ref() + .iter() + .all(|&x| x == 0) + { + self.polynomial.pop(); + } + + if self.is_empty() { + self = Polynomial::new(vec![FieldElement::new(vec![0; 16])]); + } + self } } @@ -1047,7 +1063,6 @@ mod tests { let result = element1.pow_mod(10000000, modulus); assert!(!result.is_zero()) - //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); } #[test] @@ -1069,6 +1084,32 @@ mod tests { let result = element1.monic(); assert_eq!(json!(result.to_c_array()), expected); - //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); + } + + #[test] + fn test_poly_monic_poly_zero() { + let json1 = json!(["AAAAAAAAAAAAAAAAAAAAAA=="]); + let expected = json!(["AAAAAAAAAAAAAAAAAAAAAA=="]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + + let result = element1.monic(); + + assert_eq!(json!(result.to_c_array()), expected); + } + + #[test] + fn test_poly_monic_poly_multiple_zero() { + let json1 = json!([ + "AAAAAAAAAAAAAAAAAAAAAA==", + "AAAAAAAAAAAAAAAAAAAAAA==", + "AAAAAAAAAAAAAAAAAAAAAA==", + "AAAAAAAAAAAAAAAAAAAAAA==" + ]); + let expected = json!(["AAAAAAAAAAAAAAAAAAAAAA=="]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + + let result = element1.monic(); + + assert_eq!(json!(result.to_c_array()), expected); } }