diff --git a/Cargo.toml b/Cargo.toml index e127c7e..0d58d2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,9 +10,17 @@ base64 = "0.22" openssl = "0.10" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +num = "0.4" +rand = "0.8" +threadpool = "1.8" +num_cpus = "1.16.0" [source.crates-io] replace-with = "vendored-sources" [source.vendored-sources] directory = "vendor" + +[profile.profiling] +inherits = "release" +debug = true diff --git a/src/main.rs b/src/main.rs index 5816ecb..0bb3127 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,10 @@ use std::{ - env::{self, args}, + env::{self}, fs, }; +// TESTING 2 + use anyhow::Result; fn main() -> Result<()> { @@ -12,7 +14,7 @@ fn main() -> Result<()> { let json = fs::read_to_string(path_to_workload).unwrap(); let workload = kauma::utils::parse::parse_json(json)?; - let response = kauma::tasks::task_distrubute(&workload)?; + let response = kauma::tasks::task_distribute(&workload)?; println!("{}", serde_json::to_string(&response)?); Ok(()) diff --git a/src/tasks/mod.rs b/src/tasks/mod.rs index b024471..8a8b782 100644 --- a/src/tasks/mod.rs +++ b/src/tasks/mod.rs @@ -1,20 +1,22 @@ use base64::prelude::*; -use std::{collections::HashMap, env::args}; +use std::collections::HashMap; -use crate::utils::{ - ciphers::gcm_encrypt_aes, - parse::{Responses, Testcase, Testcases}, -}; +use crate::utils::parse::{Responses, Testcase, Testcases}; use tasks01::{ block2poly::block2poly, gcm::{gcm_decrypt, gcm_encrypt}, + gcm_crack::gcm_crack, gfmul::gfmul_task, pad_oracle::padding_oracle, - pfmath::{gfdiv, gfpoly_add, gfpoly_divmod, gfpoly_mul, gfpoly_pow, gfpoly_powmod}, + pfmath::{ + gfdiv, gfpoly_add, gfpoly_diff, gfpoly_divmod, gfpoly_factor_ddf, gfpoly_factor_edf, + gfpoly_factor_sff, gfpoly_gcd, gfpoly_make_monic, gfpoly_mul, gfpoly_pow, gfpoly_powmod, + gfpoly_sort, gfpoly_sqrt, + }, poly2block::poly2block, sea128::sea128, - xex::{self, fde_xex}, + xex::fde_xex, }; use anyhow::{anyhow, Result}; @@ -104,7 +106,7 @@ pub fn task_deploy(testcase: &Testcase) -> Result { } "gfdiv" => { let result = gfdiv(args)?; - let out = BASE64_STANDARD.encode(result); + let out = result.to_b64(); let json = json!({"q" : out}); Ok(json) @@ -121,6 +123,66 @@ pub fn task_deploy(testcase: &Testcase) -> Result { Ok(json) } + "gfpoly_sort" => { + let sorted_array = gfpoly_sort(args)?; + let mut result: Vec> = vec![]; + + for poly in sorted_array { + result.push(poly.to_c_array()); + } + + let json = json!({"sorted_polys" : json!(result)}); + + Ok(json) + } + "gfpoly_make_monic" => { + let result = gfpoly_make_monic(args)?; + let json = json!({"A*" : result.to_c_array()}); + + Ok(json) + } + "gfpoly_sqrt" => { + let result = gfpoly_sqrt(args)?; + let json = json!({"S" : result.to_c_array()}); + + Ok(json) + } + "gfpoly_diff" => { + let result = gfpoly_diff(args)?; + let json = json!({"F'" : result.to_c_array()}); + + Ok(json) + } + "gfpoly_gcd" => { + let result = gfpoly_gcd(args)?; + let json = json!({"G" : result.to_c_array()}); + + Ok(json) + } + "gfpoly_factor_sff" => { + let result = gfpoly_factor_sff(args)?; + let json = json!({"factors" : result}); + + Ok(json) + } + "gfpoly_factor_ddf" => { + let result = gfpoly_factor_ddf(args)?; + let json = json!({"factors" : result}); + + Ok(json) + } + "gfpoly_factor_edf" => { + let result = gfpoly_factor_edf(args)?; + let json = json!({"factors" : result}); + + Ok(json) + } + "gcm_crack" => { + let result = gcm_crack(args)?; + let json = json!(result); + + Ok(json) + } _ => Err(anyhow!( "Fatal. No compatible action found. Json data was {:?}. Arguments were; {:?}", @@ -130,16 +192,60 @@ pub fn task_deploy(testcase: &Testcase) -> Result { } } -pub fn task_distrubute(testcases: &Testcases) -> Result { +fn task_distribute_mt(testcases: &Testcases) -> Result { + eprintln!("USING MULTITHREADED"); + let mut responses: HashMap = HashMap::new(); + let pool = threadpool::ThreadPool::default(); + let (tx, rx) = std::sync::mpsc::channel(); + for (key, testcase) in testcases.testcases.clone() { + let tx = tx.clone(); + let testcase = testcase.clone(); + pool.execute(move || { + tx.send((key, task_deploy(&testcase))) + .expect("could not send return value of thread to main thread") + }); + } + + for _ in 0..testcases.testcases.len() { + let result = match rx.recv_timeout(std::time::Duration::from_secs(60 * 5)) { + Ok(r) => r, + Err(e) => { + eprintln!("! Job timed out: {e}"); + return Err(e.into()); + } + }; + match result.1 { + Ok(v) => { + let _ = responses.insert(result.0, v); + } + Err(e) => { + eprintln!("! failed to solve a challenge: {e:#}"); + continue; + } + } + } + + Ok(Responses { responses }) +} + +pub fn task_distribute_st(testcases: &Testcases) -> Result { + //eprintln!("USING SINGLETHREADED"); let mut responses: HashMap = HashMap::new(); for (id, testcase) in &testcases.testcases { responses.insert(id.to_owned(), task_deploy(testcase).unwrap()); } - Ok(Responses { - responses: responses, - }) + Ok(Responses { responses }) +} + +pub fn task_distribute(testcases: &Testcases) -> Result { + let cpus = num_cpus::get(); + if cpus > 1 { + task_distribute_mt(testcases) + } else { + task_distribute_st(testcases) + } } #[cfg(test)] @@ -172,7 +278,7 @@ mod tests { let expected = json!({ "responses": { "b856d760-023d-4b00-bad2-15d2b6da22fe": {"block": "ARIAAAAAAAAAAAAAAAAAgA=="}}}); assert_eq!( - serde_json::to_value(task_distrubute(&parsed)?).unwrap(), + serde_json::to_value(task_distribute(&parsed)?).unwrap(), serde_json::to_value(expected).unwrap() ); @@ -196,7 +302,7 @@ mod tests { }); assert_eq!( - serde_json::to_value(task_distrubute(&parsed)?).unwrap(), + serde_json::to_value(task_distribute(&parsed)?).unwrap(), serde_json::to_value(expected).unwrap() ); @@ -211,7 +317,7 @@ mod tests { let expected = json!({ "responses": { "b856d760-023d-4b00-bad2-15d2b6da22fe": {"product": "hSQAAAAAAAAAAAAAAAAAAA=="}}}); assert_eq!( - serde_json::to_value(task_distrubute(&parsed)?).unwrap(), + serde_json::to_value(task_distribute(&parsed)?).unwrap(), serde_json::to_value(expected).unwrap() ); @@ -229,7 +335,7 @@ mod tests { }}); assert_eq!( - serde_json::to_value(task_distrubute(&parsed)?).unwrap(), + serde_json::to_value(task_distribute(&parsed)?).unwrap(), serde_json::to_value(expected).unwrap() ); @@ -249,7 +355,7 @@ mod tests { }}}); assert_eq!( - serde_json::to_value(task_distrubute(&parsed)?).unwrap(), + serde_json::to_value(task_distribute(&parsed)?).unwrap(), serde_json::to_value(expected).unwrap() ); @@ -269,7 +375,7 @@ mod tests { }}}); assert_eq!( - serde_json::to_value(task_distrubute(&parsed)?).unwrap(), + serde_json::to_value(task_distribute(&parsed)?).unwrap(), serde_json::to_value(expected).unwrap() ); @@ -287,7 +393,7 @@ mod tests { }}}); assert_eq!( - serde_json::to_value(task_distrubute(&parsed)?).unwrap(), + serde_json::to_value(task_distribute(&parsed)?).unwrap(), serde_json::to_value(expected).unwrap() ); @@ -305,7 +411,7 @@ mod tests { }}}); assert_eq!( - serde_json::to_value(task_distrubute(&parsed)?).unwrap(), + serde_json::to_value(task_distribute(&parsed)?).unwrap(), serde_json::to_value(expected).unwrap() ); @@ -323,7 +429,7 @@ mod tests { }}}); assert_eq!( - serde_json::to_value(task_distrubute(&parsed)?).unwrap(), + serde_json::to_value(task_distribute(&parsed)?).unwrap(), serde_json::to_value(expected).unwrap() ); diff --git a/src/tasks/tasks01/block2poly.rs b/src/tasks/tasks01/block2poly.rs index dbdaf66..3377bf6 100644 --- a/src/tasks/tasks01/block2poly.rs +++ b/src/tasks/tasks01/block2poly.rs @@ -1,4 +1,4 @@ -use crate::utils::poly::{b64_2_num, block_2_polynomial, get_coefficients}; +use crate::utils::poly::block_2_polynomial; use anyhow::Result; use base64::prelude::*; use serde_json::Value; @@ -19,7 +19,6 @@ pub fn block2poly(val: &Value) -> Result> { #[cfg(test)] mod tests { use serde_json::json; - use std::str::FromStr; // Note this useful idiom: importing names from outer (for mod tests) scope. use super::*; diff --git a/src/tasks/tasks01/gcm_crack.rs b/src/tasks/tasks01/gcm_crack.rs new file mode 100644 index 0000000..09ccb2c --- /dev/null +++ b/src/tasks/tasks01/gcm_crack.rs @@ -0,0 +1,174 @@ + +use anyhow::{Ok, Result}; +use base64::{prelude::BASE64_STANDARD, Engine}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +use crate::utils::{ + ciphers::ghash, + dff::ddf, + edf::edf, + field::FieldElement, + math::{reverse_bits_in_bytevec, xor_bytes}, + poly::Polynomial, + sff::sff, +}; + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct CrackAnswer { + tag: String, + H: String, + mask: String, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +struct Message { + ciphertext: Vec, + ad: Vec, + tag: Vec, + l_field: Vec, +} + +fn parse_message(val: &Value) -> Result<(Message, Polynomial)> { + let ciphertext_text: String = serde_json::from_value(val["ciphertext"].clone())?; + let mut ciphertext_bytes: Vec = BASE64_STANDARD.decode(ciphertext_text)?; + let mut c_len: Vec = ((ciphertext_bytes.len() * 8) as u64).to_be_bytes().to_vec(); + + if ciphertext_bytes.len() % 16 != 0 { + ciphertext_bytes.append(vec![0u8; 16 - (ciphertext_bytes.len() % 16)].as_mut()); + } + + let ciphertext_chunks: Vec = ciphertext_bytes + .chunks(16) + .into_iter() + .map(|chunk| FieldElement::new(chunk.to_vec())) + .collect(); + + let ad_text: String = serde_json::from_value(val["associated_data"].clone())?; + let mut ad_bytes: Vec = BASE64_STANDARD.decode(ad_text)?; + let mut l_field: Vec = ((ad_bytes.len() * 8) as u64).to_be_bytes().to_vec(); + + if ad_bytes.len() % 16 != 0 || ad_bytes.is_empty() { + ad_bytes.append(vec![0u8; 16 - (ad_bytes.len() % 16)].as_mut()); + } + + let ad_chunks: Vec = ad_bytes + .chunks(16) + .into_iter() + .map(|chunk| FieldElement::new(chunk.to_vec())) + .collect(); + + let tag_text: String = serde_json::from_value(val["tag"].clone()).unwrap_or("".to_string()); + let tag_bytes: Vec = BASE64_STANDARD.decode(tag_text)?; + let tag_field: FieldElement = FieldElement::new(tag_bytes.clone()); + + l_field.append(c_len.as_mut()); + + // Combine all data + let mut combined: Vec = + Vec::with_capacity(ad_chunks.len() + ciphertext_chunks.len() + 1); + combined.extend(ad_chunks); + combined.extend(ciphertext_chunks.clone()); + combined.push(FieldElement::new(l_field.clone())); + combined.push(tag_field); + + combined.reverse(); + + let h_poly: Polynomial = Polynomial::new(combined); + + Ok(( + Message { + ciphertext: ciphertext_bytes, + ad: ad_bytes, + tag: tag_bytes, + l_field, + }, + h_poly, + )) +} + +pub fn gcm_crack(args: &Value) -> Result { + // Prepare first equation + let (m1_data, m1_h_poly) = parse_message(&args["m1"])?; + + let (_, m2_h_poly) = parse_message(&args["m2"])?; + + let (m3_data, _) = parse_message(&args["m3"])?; + + let combine_poly = m1_h_poly + m2_h_poly; + + let combine_sff = sff(combine_poly.monic()); + + let mut combine_ddf: Vec<(Polynomial, u128)> = vec![]; + for (factor, _) in combine_sff { + combine_ddf.extend(ddf(factor)); + } + + let mut combine_edf: Vec = vec![]; + for (factor, degree) in combine_ddf { + if degree == 1 { + combine_edf.extend(edf(factor, degree as u32)); + } + } + + let mut m3_auth_tag: Vec = vec![]; + let mut h_candidate: FieldElement = FieldElement::zero(); + let mut eky0: Vec = vec![]; + for candidate in combine_edf { + if candidate.degree() == 1 { + h_candidate = candidate.extract_component(0); + let m1_ghash = ghash( + reverse_bits_in_bytevec(h_candidate.to_vec()), + m1_data.ad.clone(), + m1_data.ciphertext.clone(), + m1_data.l_field.clone(), + ) + .unwrap(); + + eky0 = xor_bytes(&m1_data.tag, m1_ghash).unwrap(); + eprintln!("eky0: {:?}", BASE64_STANDARD.encode(eky0.clone())); + + let m3_ghash = ghash( + reverse_bits_in_bytevec(h_candidate.to_vec()), + m3_data.ad.clone(), + m3_data.ciphertext.clone(), + m3_data.l_field.clone(), + ) + .unwrap(); + + m3_auth_tag = xor_bytes(&eky0, m3_ghash).unwrap(); + eprintln!( + "M3 auth tag: {:02X?}", + BASE64_STANDARD.encode(m3_auth_tag.clone()) + ); + + if m3_auth_tag == m3_data.tag { + break; + } else { + eprintln!("H candidate not valid"); + } + } + } + + let (forgery_data, _) = parse_message(&args["forgery"])?; + + let forgery_ghash = ghash( + reverse_bits_in_bytevec(h_candidate.to_vec()), + forgery_data.ad.clone(), + forgery_data.ciphertext.clone(), + forgery_data.l_field.clone(), + ) + .unwrap(); + + let forgery_auth_tag = xor_bytes(&eky0, forgery_ghash).unwrap(); + + if eky0.is_empty() { + eky0 = vec![0; 16]; + } + + Ok(CrackAnswer { + tag: BASE64_STANDARD.encode(forgery_auth_tag), + H: h_candidate.to_b64(), + mask: BASE64_STANDARD.encode(eky0), + }) +} diff --git a/src/tasks/tasks01/gfmul.rs b/src/tasks/tasks01/gfmul.rs index 2c1d6b8..8bca55f 100644 --- a/src/tasks/tasks01/gfmul.rs +++ b/src/tasks/tasks01/gfmul.rs @@ -1,7 +1,4 @@ -use crate::utils::{ - field::ByteArray, - poly::{b64_2_num, coefficient_to_binary, gfmul}, -}; +use crate::utils::poly::gfmul; use anyhow::Result; use base64::prelude::*; @@ -24,7 +21,6 @@ pub fn gfmul_task(args: &Value) -> Result> { #[cfg(test)] mod tests { use serde_json::json; - use std::str::FromStr; // Note this useful idiom: importing names from outer (for mod tests) scope. use super::*; diff --git a/src/tasks/tasks01/mod.rs b/src/tasks/tasks01/mod.rs index 8200de5..64d24da 100644 --- a/src/tasks/tasks01/mod.rs +++ b/src/tasks/tasks01/mod.rs @@ -1,5 +1,6 @@ pub mod block2poly; pub mod gcm; +pub mod gcm_crack; pub mod gfmul; pub mod pad_oracle; pub mod pfmath; diff --git a/src/tasks/tasks01/pad_oracle.rs b/src/tasks/tasks01/pad_oracle.rs index 64eb2d1..234babf 100644 --- a/src/tasks/tasks01/pad_oracle.rs +++ b/src/tasks/tasks01/pad_oracle.rs @@ -3,8 +3,7 @@ use base64::prelude::*; use serde_json::Value; use std::io::prelude::*; use std::net::TcpStream; -use std::time::{Duration, Instant}; -use std::{thread, usize}; +use std::usize; pub fn padding_oracle(args: &Value) -> Result> { let hostname: String = serde_json::from_value(args["hostname"].clone())?; @@ -29,9 +28,8 @@ pub fn padding_oracle(args: &Value) -> Result> { let mut chunk_counter = 0; for chunk in &cipher_chunks { - let start = Instant::now(); - let mut stream = TcpStream::connect(format!("{}:{}", hostname, port))?; + stream.set_nodelay(true).expect("Error on no delay"); stream.set_nonblocking(false)?; // Track value sent to server @@ -42,7 +40,6 @@ pub fn padding_oracle(args: &Value) -> Result> { let q_block_count: u16 = 256; //Send the first ciphertext chunk - //eprintln!("Sending Ciphertext chunk: {:002X?}", chunk); stream.flush()?; stream.write_all(&chunk)?; stream.flush()?; @@ -52,24 +49,16 @@ pub fn padding_oracle(args: &Value) -> Result> { // FIXME: Assignment is redundant for now // TODO: Goal is to maybe add speed increase in the future let l_msg: [u8; 2] = q_block_count.to_le_bytes(); - //eprintln!("Sending l_msg: {:02X?}", l_msg); - //stream.write_all(&l_msg)?; - //stream.flush()?; - //eprintln!("L_msg sent"); // Generate attack blocks // TODO: Collect all and send in one - let mut payload: Vec = l_msg.to_vec(); - for j in 0..q_block_count { + let mut payload: Vec = Vec::with_capacity(2 + 16 * 265); + payload.extend(l_msg.to_vec()); + for _j in 0..q_block_count { // Next byte - //eprintln!("Sending attack block: {:02X?}", attack_counter); - - //thread::sleep(Duration::from_millis(1000)); payload.extend(&attack_counter); - //eprintln!("I in q builder {}", i); attack_counter[i as usize] += 1; } - //eprintln!("Time for qblocks: {:?}", start.elapsed()); stream.write_all(&payload)?; stream.flush()?; @@ -77,7 +66,6 @@ pub fn padding_oracle(args: &Value) -> Result> { // Read server response let mut server_q_resp = [0u8; 256]; stream.read_exact(&mut server_q_resp)?; - //eprintln!("{:02X?}", buf); // extract valid position let valid_val = server_q_resp @@ -87,7 +75,6 @@ pub fn padding_oracle(args: &Value) -> Result> { if valid_val == 0x00 { eprintln!("No valid found in main loop"); } - //eprintln!("Valid value found: {:02X?}", valid_val); // Craft next attack vector padding; 0x01, 0x02, ... attack_counter[i as usize] = valid_val; @@ -101,57 +88,35 @@ pub fn padding_oracle(args: &Value) -> Result> { l_msg_check.extend(check_q_block.as_slice()); stream.write_all(&l_msg_check)?; - //stream.write_all(&check_q_block)?; let mut buf = [0u8; 0x01]; stream.read(&mut buf)?; - //eprintln!("I = {}", i); - //eprintln!("Buffer from pad check: {:02X?}", buf); if buf == [0x01] { - //eprintln!("Valid padding"); } else { - //eprintln!("Invalid padding"); // Search for second hit - let valid_val = (255 + let valid_val = 255 - server_q_resp .iter() .rev() .position(|&r| r == 0x01) - .unwrap_or(0x00) as u8); + .unwrap_or(0x00) as u8; if valid_val == 0x00 { eprintln!("No valid found"); } - //eprintln!("Valid value found: {:02X?}", valid_val); // Craft next attack vector padding; 0x01, 0x02, ... attack_counter[i as usize] = valid_val; } } if chunk_counter + 1 < cipher_chunks.len() { - //eprintln!("XOR Next Ciph block"); plaintext.push( cipher_chunks[chunk_counter + 1][i] ^ (attack_counter[i as usize] ^ (15 - i as u8 + 1)), ); } else { - //seprintln!("XOR IV"); - plaintext.push(iv[i] ^ (attack_counter[i as usize] ^ (15 - i as u8 + 1))); } - //eprintln!("Attack counter after set: {:02X?}", attack_counter); let range = i; for pos in range..=15 { - //eprintln!("i is: {:02X?}", i); - //eprintln!("i + 1 is: {:02X?}", ((16 - i) as u8).to_le()); - /* - eprintln!( - "attack_counter[pos as usize]: {:02X?}", - attack_counter[pos as usize] - ); - eprintln!( - "attack_counter[pos as usize] ^ 0x02 {:02X?}", - attack_counter[pos as usize] ^ (15 - i as u8 + 1) - ); - */ let intermediate = attack_counter[pos as usize] ^ (15 - i as u8 + 1); attack_counter[pos as usize] = intermediate ^ ((15 - i as u8 + 1) + 1); @@ -160,13 +125,10 @@ pub fn padding_oracle(args: &Value) -> Result> { stream.flush()?; // Write plaintext - //eprintln!("{:02X?}", plaintext); } chunk_counter += 1; stream.flush()?; - // break; drop(stream); - //eprintln!("Time rest of calc: {:?}", start.elapsed()); } plaintext.reverse(); @@ -178,7 +140,6 @@ pub fn padding_oracle(args: &Value) -> Result> { #[cfg(test)] mod tests { use super::*; - use serde_json::json; #[test] fn test_connection() -> Result<()> { diff --git a/src/tasks/tasks01/pfmath.rs b/src/tasks/tasks01/pfmath.rs index 4ad3ac7..6830e1a 100644 --- a/src/tasks/tasks01/pfmath.rs +++ b/src/tasks/tasks01/pfmath.rs @@ -1,8 +1,16 @@ + use anyhow::Result; use base64::{prelude::BASE64_STANDARD, Engine}; use serde_json::Value; -use crate::utils::field::{FieldElement, Polynomial}; +use crate::utils::{ + self, + dff::ddf, + edf::edf, + field::FieldElement, + poly::{gcd, Polynomial}, + sff::{sff, Factors}, + }; pub fn gfpoly_add(args: &Value) -> Result { let poly_a = Polynomial::from_c_array(&args["A"].clone()); @@ -67,3 +75,208 @@ pub fn gfpoly_powmod(args: &Value) -> Result { Ok(result) } + +pub fn gfpoly_sort(args: &Value) -> Result> { + let poly_arrays: Vec = serde_json::from_value(args["polys"].clone())?; + let mut polys: Vec = vec![]; + + for array in poly_arrays { + polys.push(Polynomial::from_c_array(&array)); + } + + polys.sort(); + //polys.sort(); + Ok(polys) +} + +pub fn gfpoly_make_monic(args: &Value) -> Result { + let poly_a = Polynomial::from_c_array(&args["A"].clone()); + + let result = poly_a.monic(); + + Ok(result) +} + +pub fn gfpoly_sqrt(args: &Value) -> Result { + let poly_a = Polynomial::from_c_array(&args["Q"].clone()); + + let result = poly_a.sqrt(); + + Ok(result) +} + +pub fn gfpoly_diff(args: &Value) -> Result { + let poly_f = Polynomial::from_c_array(&args["F"].clone()); + + let result = poly_f.diff(); + + Ok(result) +} + +pub fn gfpoly_gcd(args: &Value) -> Result { + let poly_a = Polynomial::from_c_array(&args["A"].clone()); + let poly_b = Polynomial::from_c_array(&args["B"].clone()); + + let result = gcd(&poly_a.monic(), &poly_b.monic()); + + Ok(result) +} + +pub fn gfpoly_factor_sff(arsg: &Value) -> Result> { + let poly_f = Polynomial::from_c_array(&arsg["F"].clone()); + + let mut factors = sff(poly_f); + factors.sort(); + let mut result: Vec = vec![]; + + for (factor, exponent) in factors { + result.push(Factors { + factor: factor.to_c_array(), + exponent, + }); + } + + Ok(result) +} + +pub fn gfpoly_factor_ddf(arsg: &Value) -> Result> { + let poly_f = Polynomial::from_c_array(&arsg["F"].clone()); + + let mut factors = ddf(poly_f); + factors.sort(); + let mut result: Vec = vec![]; + + for (factor, degree) in factors { + result.push(utils::dff::Factors { + factor: factor.to_c_array(), + degree: degree as u32, + }); + } + + Ok(result) +} + +pub fn gfpoly_factor_edf(arsg: &Value) -> Result>> { + let poly_f = Polynomial::from_c_array(&arsg["F"].clone()); + let d: u32 = serde_json::from_value(arsg["d"].clone())?; + + let mut factors = edf(poly_f, d); + + factors.sort(); + + let mut result: Vec> = vec![]; + + for factor in factors { + result.push(factor.to_c_array()) + } + + Ok(result) +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json::json; + + #[test] + fn test_poly_sorting() { + let json1 = json!( + {"polys": [ + [ + "NeverGonnaGiveYouUpAAA==", + "NeverGonnaLetYouDownAA==", + "NeverGonnaRunAroundAAA==", + "AndDesertYouAAAAAAAAAA==" + ], + [ + "WereNoStrangersToLoveA==", + "YouKnowTheRulesAAAAAAA==", + "AndSoDoIAAAAAAAAAAAAAA==" + ], + [ + "NeverGonnaMakeYouCryAA==", + "NeverGonnaSayGoodbyeAA==", + "NeverGonnaTellALieAAAA==", + "AndHurtYouAAAAAAAAAAAA==" + ] + ]}); + + let expected = json!([ + [ + "WereNoStrangersToLoveA==", + "YouKnowTheRulesAAAAAAA==", + "AndSoDoIAAAAAAAAAAAAAA==" + ], + [ + "NeverGonnaMakeYouCryAA==", + "NeverGonnaSayGoodbyeAA==", + "NeverGonnaTellALieAAAA==", + "AndHurtYouAAAAAAAAAAAA==" + ], + [ + "NeverGonnaGiveYouUpAAA==", + "NeverGonnaLetYouDownAA==", + "NeverGonnaRunAroundAAA==", + "AndDesertYouAAAAAAAAAA==" + ] + ]); + + let sorted_array = gfpoly_sort(&json1).unwrap(); + let mut result: Vec> = vec![]; + for poly in sorted_array { + result.push(poly.to_c_array()); + } + + assert_eq!(json!(result), expected); + //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); + } + + #[test] + fn test_poly_sorting_02() { + let json1 = json!( + {"polys": [ + [ + "AQAAAAAAAAAAAAAAAAAAAA==", // 0x01 + "AgAAAAAAAAAAAAAAAAAAAA==", // 0x02 + "AwAAAAAAAAAAAAAAAAAAAA==" // 0x03 + ], + [ + "AQAAAAAAAAAAAAAAAAAAAA==", // 0x01 + "AgAAAAAAAAAAAAAAAAAAAA==", // 0x02 + "BAAAAAAAAAAAAAAAAAAAAA==" // 0x04 + ], + [ + "AQAAAAAAAAAAAAAAAAAAAA==", // 0x01 + "AgAAAAAAAAAAAAAAAAAAAA==" // 0x02 + ], + [ + "AQAAAAAAAAAAAAAAAAAAAA==", // 0x01 + "AwAAAAAAAAAAAAAAAAAAAA==" // 0x03 + ] + ],}); + + let expected = json!([ + ["AQAAAAAAAAAAAAAAAAAAAA==", "AgAAAAAAAAAAAAAAAAAAAA=="], + ["AQAAAAAAAAAAAAAAAAAAAA==", "AwAAAAAAAAAAAAAAAAAAAA=="], + [ + "AQAAAAAAAAAAAAAAAAAAAA==", + "AgAAAAAAAAAAAAAAAAAAAA==", + "BAAAAAAAAAAAAAAAAAAAAA==" + ], + [ + "AQAAAAAAAAAAAAAAAAAAAA==", + "AgAAAAAAAAAAAAAAAAAAAA==", + "AwAAAAAAAAAAAAAAAAAAAA==" + ] + ]); + + let sorted_array = gfpoly_sort(&json1).unwrap(); + let mut result: Vec> = vec![]; + for poly in sorted_array { + result.push(poly.to_c_array()); + } + + assert_eq!(json!(result), expected); + //assert_eq!(BASE64_STANDARD.encode(product), "MoAAAAAAAAAAAAAAAAAAAA=="); + } +} diff --git a/src/tasks/tasks01/poly2block.rs b/src/tasks/tasks01/poly2block.rs index 293d1c3..7557981 100644 --- a/src/tasks/tasks01/poly2block.rs +++ b/src/tasks/tasks01/poly2block.rs @@ -1,6 +1,5 @@ -use crate::utils::poly::{self, polynomial_2_block}; +use crate::utils::poly::polynomial_2_block; use anyhow::{Ok, Result}; -use base64::prelude::*; use serde_json::Value; pub fn poly2block(args: &Value) -> Result> { diff --git a/src/tasks/tasks01/sea128.rs b/src/tasks/tasks01/sea128.rs index 3f5c40d..2a6a7e2 100644 --- a/src/tasks/tasks01/sea128.rs +++ b/src/tasks/tasks01/sea128.rs @@ -6,19 +6,13 @@ use crate::utils::ciphers::{sea_128_decrypt, sea_128_encrypt}; pub fn sea128(args: &Value) -> Result { let key_string: String = serde_json::from_value(args["key"].clone())?; - //let key: &[u8] = b64_2_num(key_string)?.to_ne_bytes(); let key = BASE64_STANDARD.decode(key_string)?; - //eprintln!("{:?}", key); let input_string: String = serde_json::from_value(args["input"].clone())?; - //let plaintexts: &[u8] = &b64_2_num(plaintexts_string)?.to_ne_bytes(); let input = BASE64_STANDARD.decode(input_string)?; - let xor_val: u128 = 0xc0ffeec0ffeec0ffeec0ffeec0ffee11; let mode: String = serde_json::from_value(args["mode"].clone())?; match mode.as_str() { "encrypt" => { - //eprintln!("{:?}", plaintexts); - let output = BASE64_STANDARD.encode(sea_128_encrypt(&key, &input)?); Ok(output) @@ -34,7 +28,6 @@ pub fn sea128(args: &Value) -> Result { #[cfg(test)] mod tests { - use std::fs; use anyhow::Result; use serde_json::json; diff --git a/src/utils/ciphers.rs b/src/utils/ciphers.rs index 333ec13..0b558af 100644 --- a/src/utils/ciphers.rs +++ b/src/utils/ciphers.rs @@ -1,8 +1,5 @@ -use std::{io::BufRead, process::Output}; - -use crate::utils::{field::ByteArray, math::reverse_bits_in_bytevec, poly::gfmul}; +use crate::utils::{field::ByteArray, poly::gfmul}; use anyhow::Result; -use base64::prelude::*; use openssl::symm::{Cipher, Crypter, Mode}; use super::math::xor_bytes; @@ -40,7 +37,6 @@ pub fn aes_128_decrypt(key: &Vec, input: &Vec) -> Result> { let mut bytes: [u8; 16] = [0u8; 16]; bytes.copy_from_slice(&plaintext); - let number: u128 = ::from_be_bytes(bytes); Ok(plaintext) } @@ -122,10 +118,8 @@ pub fn gcm_encrypt_aes( let mut counter: u32 = 1; nonce.append(counter.to_be_bytes().to_vec().as_mut()); //nonce.append(0u8.to_le_bytes().to_vec().as_mut()); - eprintln!("{:001X?}", nonce); let auth_tag_xor = aes_128_encrypt(&key, &nonce)?; - eprintln!("Y0 {:001X?}", auth_tag_xor); let auth_key_h = aes_128_encrypt(&key, &0u128.to_be_bytes().to_vec())?; @@ -136,8 +130,6 @@ pub fn gcm_encrypt_aes( nonce.drain(12..); nonce.append(counter.to_be_bytes().to_vec().as_mut()); - eprintln!("{:001X?}", nonce); - let inter1 = aes_128_encrypt(&key, &nonce)?; let mut inter2 = xor_bytes(&inter1, chunk.clone())?; @@ -154,7 +146,6 @@ pub fn gcm_encrypt_aes( &ghash(auth_key_h.clone(), ad, ciphertext.clone(), l_field.clone())?, auth_tag_xor, )?; - eprintln!("aes auth tag: {:001X?}", &auth_tag); Ok((ciphertext, auth_tag, l_field, auth_key_h)) } @@ -170,8 +161,6 @@ pub fn gcm_decrypt_aes( let mut counter: u32 = 1; nonce.append(counter.to_be_bytes().to_vec().as_mut()); - //nonce.append(0u8.to_le_bytes().to_vec().as_mut()); - eprintln!("{:001X?}", nonce); let auth_tag_xor = aes_128_encrypt(&key, &nonce)?; @@ -184,8 +173,6 @@ pub fn gcm_decrypt_aes( nonce.drain(12..); nonce.append(counter.to_be_bytes().to_vec().as_mut()); - eprintln!("{:001X?}", nonce); - let inter1 = aes_128_encrypt(&key, &nonce)?; let mut inter2 = xor_bytes(&inter1, chunk.clone())?; @@ -204,7 +191,6 @@ pub fn gcm_decrypt_aes( )?; let valid = auth_tag == tag; - eprintln!("aes auth tag: {:001X?}", auth_tag); Ok((plaintext, valid)) } @@ -220,7 +206,6 @@ pub fn gcm_encrypt_sea( let mut counter: u32 = 1; nonce.append(counter.to_be_bytes().to_vec().as_mut()); //nonce.append(0u8.to_le_bytes().to_vec().as_mut()); - eprintln!("{:001X?}", nonce); let auth_tag_xor = sea_128_encrypt(&key, &nonce)?; @@ -233,8 +218,6 @@ pub fn gcm_encrypt_sea( nonce.drain(12..); nonce.append(counter.to_be_bytes().to_vec().as_mut()); - eprintln!("{:001X?}", nonce); - let inter1 = sea_128_encrypt(&key, &nonce)?; let mut inter2 = xor_bytes(&inter1, chunk.clone())?; @@ -266,8 +249,6 @@ pub fn gcm_decrypt_sea( let mut counter: u32 = 1; nonce.append(counter.to_be_bytes().to_vec().as_mut()); - //nonce.append(0u8.to_le_bytes().to_vec().as_mut()); - eprintln!("Nonce 1: {:001X?}", nonce); let auth_tag_xor = sea_128_encrypt(&key, &nonce)?; @@ -275,17 +256,11 @@ pub fn gcm_decrypt_sea( let plaintext_chunks: Vec> = ciphertext.chunks(16).map(|x| x.to_vec()).collect(); - eprintln!("{:?}", plaintext_chunks); - counter = 2; for chunk in plaintext_chunks { - eprintln!("Inside loop"); - nonce.drain(12..); nonce.append(counter.to_be_bytes().to_vec().as_mut()); - eprintln!("Nonce 2: {:001X?}", nonce); - let inter1 = sea_128_encrypt(&key, &nonce)?; let mut inter2 = xor_bytes(&inter1, chunk.clone())?; @@ -298,15 +273,11 @@ pub fn gcm_decrypt_sea( let mut c_len: Vec = ((plaintext.len() * 8) as u64).to_be_bytes().to_vec(); l_field.append(c_len.as_mut()); - eprintln!("Ciphertext: {}", BASE64_STANDARD.encode(&ciphertext)); - let auth_tag = xor_bytes( &ghash(auth_key_h.clone(), ad, ciphertext.clone(), l_field.clone())?, auth_tag_xor, )?; - eprintln!("sea dec auth tag: {}", BASE64_STANDARD.encode(&auth_tag)); - let valid = auth_tag == tag; Ok((plaintext, valid)) @@ -320,10 +291,6 @@ pub fn ghash( ) -> Result> { let output: Vec = vec![0; 16]; - eprintln!("{:?}", ad.len() as u8); - eprintln!("{:?}", (ad.len() % 16) as u8); - eprintln!("{:001X?}", ad); - if ad.len() % 16 != 0 || ad.is_empty() { ad.append(vec![0u8; 16 - (ad.len() % 16)].as_mut()); } @@ -332,20 +299,12 @@ pub fn ghash( ciphertext.append(vec![0u8; 16 - (ciphertext.len() % 16)].as_mut()); } - eprintln!("{:001X?}", ad); - eprintln!("{:001X?}", ciphertext); - let mut ad_chunks = ad.chunks(16); - eprintln!("Ad chunks before first next {:001X?}", ad_chunks); - let inter1 = xor_bytes(&output, ad_chunks.next().unwrap().to_vec())?; let mut inter_loop = gfmul(&inter1, &auth_key_h, "gcm")?; - eprintln!("Ad chunks after first next {:001X?}", ad_chunks); for chunk in ad_chunks { - eprintln!("Inside ad chunk loop"); - eprintln!("Ad chunk in loop {:001X?}", chunk); let inter2 = xor_bytes(&inter_loop, chunk.to_vec())?; inter_loop = gfmul(&inter2, &auth_key_h, "gcm")?; } @@ -360,18 +319,9 @@ pub fn ghash( let inter4 = xor_bytes(&inter_loop, l_field)?; inter_loop = gfmul(&inter4, &auth_key_h, "gcm")?; - eprintln!("GHASH auth tag: {:001X?}", inter_loop); - Ok(inter_loop) } -/* -* let mut bytes: [u8; 16] = [0u8; 16]; - bytes.copy_from_slice(&ciphertext); - let number: u128 = ::from_be_bytes(bytes); - -* */ - #[cfg(test)] mod tests { use super::*; diff --git a/src/utils/dff.rs b/src/utils/dff.rs new file mode 100644 index 0000000..21dde69 --- /dev/null +++ b/src/utils/dff.rs @@ -0,0 +1,81 @@ +use std::usize; + +use num::{pow::Pow, BigUint, FromPrimitive}; +use serde::{Deserialize, Serialize}; + +use super::poly::{gcd, Polynomial}; + +#[derive(Debug, Serialize, Deserialize)] +pub struct Factors { + pub factor: Vec, + pub degree: u32, +} + +pub fn ddf(f: Polynomial) -> Vec<(Polynomial, u128)> { + let q = BigUint::pow(&BigUint::from_u8(2).unwrap(), 128); + + let mut z: Vec<(Polynomial, u128)> = vec![]; + let mut d: u128 = 1; + let mut f_star = f.clone(); + + let one_cmp = Polynomial::one(); + + while f_star.degree() as u128 >= (2 * d) { + let h = Polynomial::x().bpow_mod(q.clone().pow(d), &f_star.clone()) + Polynomial::x(); + + let g = gcd(&h, &f_star); + if g != one_cmp { + z.push((g.clone(), d)); + f_star = f_star.div(&g).0; + } + + d += 1; + } + + if f_star != one_cmp { + z.push((f_star.clone(), f_star.degree() as u128)); + } else if z.len() == 0 { + z.push((f.clone(), 1)); + } + + z +} + +#[cfg(test)] +mod tests { + + use serde_json::json; + + // Note this useful idiom: importing names from outer (for mod tests) scope. + use super::*; + + #[test] + fn test_dff_sheet() { + let json_f = json!([ + "tpkgAAAAAAAAAAAAAAAAAA==", + "m6MQAAAAAAAAAAAAAAAAAA==", + "8roAAAAAAAAAAAAAAAAAAA==", + "3dUAAAAAAAAAAAAAAAAAAA==", + "FwAAAAAAAAAAAAAAAAAAAA==", + "/kAAAAAAAAAAAAAAAAAAAA==", + "a4AAAAAAAAAAAAAAAAAAAA==", + "gAAAAAAAAAAAAAAAAAAAAA==" + ]); + let poly_f = Polynomial::from_c_array(&json_f); + + let mut factors = ddf(poly_f); + factors.sort(); + let mut result: Vec = vec![]; + + for (factor, degree) in factors { + result.push(Factors { + factor: factor.to_c_array(), + degree: degree as u32, + }); + } + + println!("Result: {:?}", result); + let _bit_indices: Vec = vec![0]; + assert!(false) + } +} diff --git a/src/utils/edf.rs b/src/utils/edf.rs new file mode 100644 index 0000000..dfb59cf --- /dev/null +++ b/src/utils/edf.rs @@ -0,0 +1,86 @@ +use num::{BigUint, FromPrimitive, One}; +use rand::Rng; + +use super::poly::{gcd, Polynomial}; + +pub fn edf(f: Polynomial, d: u32) -> Vec { + let q = BigUint::pow(&BigUint::from_u8(2).unwrap(), 128); + let n: u32 = (f.degree() as u32) / (d); + let mut z: Vec = vec![f.clone()]; + let one_cmp = Polynomial::one(); + + while (z.len() as u32) < n { + let h = Polynomial::rand(&rand::thread_rng().gen_range(1..=f.degree())); + + let exponent = (q.pow(d) - BigUint::one()) / BigUint::from_u8(3).unwrap(); + + let g = h.bpow_mod(exponent, &f) + Polynomial::one(); + + for i in (0..z.len()).rev() { + if z[i].degree() as u32 > d { + let j = gcd(&z[i], &g); + if j != one_cmp && j != z[i] { + let intemediate = z[i].div(&j).0; + z.remove(i); + z.push(j.clone()); + z.push(intemediate); + } + } + } + } + + z +} + +#[cfg(test)] +mod tests { + + use serde_json::json; + + // Note this useful idiom: importing names from outer (for mod tests) scope. + use super::*; + + #[test] + fn test_edf_sheet() { + let json_f = json!([ + "mmAAAAAAAAAAAAAAAAAAAA==", + "AbAAAAAAAAAAAAAAAAAAAA==", + "zgAAAAAAAAAAAAAAAAAAAA==", + "FwAAAAAAAAAAAAAAAAAAAA==", + "AAAAAAAAAAAAAAAAAAAAAA==", + "wAAAAAAAAAAAAAAAAAAAAA==", + "gAAAAAAAAAAAAAAAAAAAAA==" + ]); + let d = 3; + let poly_f = Polynomial::from_c_array(&json_f); + + let mut factors = edf(poly_f, d); + factors.sort(); + + let mut result: Vec> = vec![]; + + for factor in factors { + result.push(factor.to_c_array()) + } + + println!("Result: {:?}", result); + + assert_eq!( + result, + vec![ + [ + "iwAAAAAAAAAAAAAAAAAAAA==", + "CAAAAAAAAAAAAAAAAAAAAA==", + "AAAAAAAAAAAAAAAAAAAAAA==", + "gAAAAAAAAAAAAAAAAAAAAA==" + ], + [ + "kAAAAAAAAAAAAAAAAAAAAA==", + "CAAAAAAAAAAAAAAAAAAAAA==", + "wAAAAAAAAAAAAAAAAAAAAA==", + "gAAAAAAAAAAAAAAAAAAAAA==" + ] + ] + ) + } +} diff --git a/src/utils/field.rs b/src/utils/field.rs index fac51f2..739b466 100644 --- a/src/utils/field.rs +++ b/src/utils/field.rs @@ -1,259 +1,52 @@ +use base64::prelude::*; +use std::{u128, u8, usize}; + use std::{ - env::args, - ops::{Add, BitXor, Div, Mul, Rem, Sub}, - result, + cmp::Ordering, + ops::{Add, BitXor, Div, Mul}, }; use anyhow::{anyhow, Ok, Result}; -use base64::prelude::*; -use serde_json::Value; -use crate::{tasks::tasks01::poly2block::poly2block, utils::poly::polynomial_2_block}; +use super::{ + math::{reverse_bits_in_bytevec, xor_bytes}, + poly::gfmul, +}; -use super::{math::xor_bytes, poly::gfmul}; - -#[derive(Debug)] -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(vec![0])]); - } - - 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(), - )]); - - //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; - } - 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 - - 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(); - } - } - - (Polynomial::new(quotient_coeffs), remainder) - } -} - -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 { - 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 { - 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(); - } - } - - Polynomial::new(polynomial) - } -} - -// Helper implementation for subtraction -impl Sub for &FieldElement { - type Output = FieldElement; - - fn sub(self, rhs: Self) -> FieldElement { - // In a field of characteristic 2, addition and subtraction are the same operation (XOR) - self + rhs - } -} - -// Helper trait for checking emptiness -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 - } -} - -#[derive(Debug)] +#[derive(Debug, serde::Serialize, serde::Deserialize)] pub struct FieldElement { field_element: Vec, } impl FieldElement { pub const IRREDUCIBLE_POLYNOMIAL: [u8; 17] = [ - 87, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 01, + 0x87, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 0x01, ]; - pub const fn new(field_element: Vec) -> Self { + pub fn rand() -> Self { + let rand_field: [u8; 16] = rand::random(); + FieldElement::new_no_convert(rand_field.to_vec()) + } + + pub fn zero() -> Self { + FieldElement::new_no_convert(vec![0; 16]) + } + + pub fn one() -> Self { + FieldElement::new_no_convert(vec![0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) + } + + pub fn to_vec(&self) -> Vec { + self.field_element.clone() + } + + pub fn new(field_element: Vec) -> Self { + Self { + field_element: reverse_bits_in_bytevec(field_element), + } + } + + pub fn new_no_convert(field_element: Vec) -> Self { Self { field_element } } @@ -262,43 +55,60 @@ impl FieldElement { } pub fn to_b64(&self) -> String { - BASE64_STANDARD.encode(&self.field_element) + BASE64_STANDARD.encode(reverse_bits_in_bytevec(self.field_element.to_owned())) } - pub fn pow(&self, mut exponent: u128) -> FieldElement { - if exponent == 0 { - // Return polynomial with coefficient 1 - return FieldElement::new(vec![1]); + pub fn pow(mut self, mut exponent: u128) -> FieldElement { + let mut result: FieldElement = FieldElement::one(); + + if exponent == 1 { + return self; } - let base = self.clone(); - let mut result = base.clone(); - exponent -= 1; // Subtract 1 because we already set result to base + if exponent == 0 { + let result = FieldElement::one(); + + return result; + } while exponent > 0 { - result = result * base.clone(); - exponent -= 1; + if exponent & 1 == 1 { + let temp = &self * &result; + + result = temp + } + let temp_square = &self * &self; + + self = temp_square; + exponent >>= 1; } result } pub fn inv(mut self) -> Self { - let mut inverser: u128 = 0xfffffffffffffffffffffffffffffffe; - let mut inverse: Vec = polynomial_2_block(vec![0], "gcm").unwrap(); - //eprintln!("Inverse start {:02X?}", inverse); + const INVERSER_START: u128 = 0xfffffffffffffffffffffffffffffffe; + + let mut inverser = INVERSER_START; + let mut inverse: Vec = vec![0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; while inverser > 0 { - //eprintln!("{:02X}", inverser); if inverser & 1 == 1 { - inverse = gfmul(&self.field_element, &inverse, "gcm").unwrap(); + inverse = gfmul(&self.field_element, &inverse, "xex").unwrap(); } inverser >>= 1; - self.field_element = gfmul(&self.field_element, &self.field_element, "gcm") + self.field_element = gfmul(&self.field_element, &self.field_element, "xex") .expect("Error in sqrmul sqr"); } - //eprintln!("Inverse rhs {:?}", inverse); - FieldElement::new(inverse) + FieldElement::new_no_convert(inverse) + } + + pub fn is_zero(&self) -> bool { + self.field_element.iter().all(|&x| x == 0x00) + } + + pub fn reverse_bits(&self) -> Self { + FieldElement::new_no_convert(reverse_bits_in_bytevec(self.field_element.clone())) } } @@ -306,8 +116,8 @@ impl Mul for FieldElement { type Output = Self; fn mul(self, rhs: Self) -> Self::Output { - FieldElement::new( - gfmul(&self.field_element, &rhs.field_element, "gcm") + FieldElement::new_no_convert( + gfmul(&self.field_element, &rhs.field_element, "xex") .expect("Error during multiplication"), ) } @@ -317,8 +127,8 @@ impl Mul for &FieldElement { type Output = FieldElement; fn mul(self, rhs: &FieldElement) -> FieldElement { - FieldElement::new( - gfmul(&self.field_element, &rhs.field_element, "gcm") + FieldElement::new_no_convert( + gfmul(&self.field_element, &rhs.field_element, "xex") .expect("Error during multiplication"), ) } @@ -327,7 +137,7 @@ impl Mul for &FieldElement { impl Add for FieldElement { type Output = Self; fn add(self, rhs: Self) -> Self::Output { - FieldElement::new( + FieldElement::new_no_convert( xor_bytes(&self.field_element, rhs.field_element).expect("Error in poly add"), ) } @@ -336,7 +146,7 @@ impl Add for FieldElement { impl Add for &FieldElement { type Output = FieldElement; fn add(self, rhs: Self) -> Self::Output { - FieldElement::new( + FieldElement::new_no_convert( xor_bytes(&self.field_element, rhs.field_element.clone()).expect("Error in poly add"), ) } @@ -365,18 +175,15 @@ impl BitXor for FieldElement { .zip(rhs.field_element.iter()) .map(|(&x1, &x2)| x1 ^ x2) .collect(); - FieldElement::new(result) + FieldElement::new_no_convert(result) } } impl Div for FieldElement { type Output = Self; fn div(self, rhs: Self) -> Self::Output { - eprintln!("RHS in div{:02X?}", &rhs); - let inverse = rhs.inv(); - eprintln!("Inverse in div{:02X?}", inverse); - self.clone() * inverse + self * inverse } } @@ -384,41 +191,49 @@ impl Div for &FieldElement { type Output = FieldElement; fn div(self, rhs: Self) -> Self::Output { - // First clone and invert the divisor (rhs) - let rhs_inv = rhs.clone().inv(); - // Multiply original number by the inverse - self.clone() * rhs_inv + self.clone() * rhs.clone().inv() } } -/* -impl Rem for FieldElement { - type Output = Self; - fn rem(self, rhs: Self) -> Self::Output { - let result: FieldElement = self.field_element; - - while self.field_element[15] != 0x00 { - self.field_element +impl PartialOrd for FieldElement { + fn partial_cmp(&self, other: &Self) -> Option { + for (byte_a, byte_b) in self.as_ref().iter().rev().zip(other.as_ref().iter().rev()) { + if byte_a > byte_b { + return Some(Ordering::Greater); + } else if byte_a < byte_b { + return Some(Ordering::Less); + } else { + continue; + } } - todo!(); + Some(Ordering::Equal) } } -*/ -/* -impl BitXor for FieldElement { - fn bitxor(self, rhs: Self) -> Self::Output { - FieldElement - } -} -*/ -/* -impl From> for FieldElement { - fn from(item: Vec) -> Self { - FieldElement { bytes: item } +impl PartialEq for FieldElement { + fn eq(&self, other: &Self) -> bool { + self.field_element == other.field_element + } +} + +impl Eq for FieldElement { + // add code here +} + +impl Ord for FieldElement { + fn cmp(&self, other: &Self) -> Ordering { + for (byte_a, byte_b) in self.as_ref().iter().rev().zip(other.as_ref().iter().rev()) { + if byte_a > byte_b { + return Ordering::Greater; + } else if byte_a < byte_b { + return Ordering::Less; + } else { + continue; + } + } + Ordering::Equal } } -*/ #[derive(Debug)] pub struct ByteArray(pub Vec); @@ -522,15 +337,12 @@ impl ByteArray { #[cfg(test)] mod tests { use super::*; - use base64::prelude::*; - use serde_json::json; - use std::fs; #[test] fn test_byte_array_shift1() { let mut byte_array: ByteArray = ByteArray(vec![0x00, 0x01]); let shifted_array: ByteArray = ByteArray(vec![0x00, 0x02]); - byte_array.left_shift("xex"); + byte_array.left_shift("xex").unwrap(); assert_eq!(byte_array.0, shifted_array.0); } @@ -539,7 +351,7 @@ mod tests { fn test_byte_array_shift2() { let mut byte_array: ByteArray = ByteArray(vec![0xFF, 0x00]); let shifted_array: ByteArray = ByteArray(vec![0xFE, 0x01]); - byte_array.left_shift("xex"); + byte_array.left_shift("xex").unwrap(); assert_eq!( byte_array.0, shifted_array.0, @@ -552,7 +364,7 @@ mod tests { fn test_byte_array_shift1_gcm() { let mut byte_array: ByteArray = ByteArray(vec![0xFF, 0x00]); let shifted_array: ByteArray = ByteArray(vec![0x7F, 0x80]); - byte_array.left_shift("gcm"); + byte_array.left_shift("gcm").unwrap(); assert_eq!( byte_array.0, shifted_array.0, @@ -565,7 +377,7 @@ mod tests { fn test_byte_array_shift1_right_gcm() { let mut byte_array: ByteArray = ByteArray(vec![0xFF, 0x00]); let shifted_array: ByteArray = ByteArray(vec![0xFE, 0x00]); - byte_array.right_shift("gcm"); + byte_array.right_shift("gcm").unwrap(); assert_eq!( byte_array.0, shifted_array.0, @@ -578,7 +390,7 @@ mod tests { fn test_byte_array_shift_right() { let mut byte_array: ByteArray = ByteArray(vec![0x02]); let shifted_array: ByteArray = ByteArray(vec![0x01]); - byte_array.right_shift("xex"); + byte_array.right_shift("xex").unwrap(); assert_eq!( byte_array.0, shifted_array.0, @@ -627,7 +439,7 @@ mod tests { FieldElement::new(BASE64_STANDARD.decode("KryptoanalyseAAAAAAAAA==").unwrap()); let sum = element2 + element1; - assert_eq!(BASE64_STANDARD.encode(sum), "H1d3GuyA9/0OxeYouUpAAA=="); + assert_eq!(sum.to_b64(), "H1d3GuyA9/0OxeYouUpAAA=="); } #[test] @@ -638,115 +450,11 @@ mod tests { FieldElement::new(BASE64_STANDARD.decode("DHBWMannheimAAAAAAAAAA==").unwrap()); let sum = element2 + element1; - assert_eq!(BASE64_STANDARD.encode(sum), "OZuIncPAGEp4tYouDownAA=="); + assert_eq!(sum.to_b64(), "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_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_field_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_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_poly_div_01() { + fn test_field_div_01() { let element1 = FieldElement::new(BASE64_STANDARD.decode("JAAAAAAAAAAAAAAAAAAAAA==").unwrap()); @@ -755,47 +463,6 @@ mod tests { 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_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!["XrEhmKuat+Glt5zZWtMo6g=="]); + assert_eq!(result.to_b64(), "OAAAAAAAAAAAAAAAAAAAAA=="); } } diff --git a/src/utils/math.rs b/src/utils/math.rs index cf87e0c..c1809e2 100644 --- a/src/utils/math.rs +++ b/src/utils/math.rs @@ -1,7 +1,5 @@ -use anyhow::{anyhow, Ok, Result}; -use base64::Engine; +use anyhow::{Ok, Result}; -use super::poly::gfmul; pub fn xor_bytes(vec1: &Vec, mut vec2: Vec) -> Result> { for (byte1, byte2) in vec1.iter().zip(vec2.iter_mut()) { diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 298415b..35fb781 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -1,6 +1,9 @@ pub mod ciphers; +pub mod dff; +pub mod edf; pub mod field; pub mod math; pub mod net; pub mod parse; pub mod poly; +pub mod sff; diff --git a/src/utils/parse.rs b/src/utils/parse.rs index 5cc1781..4b71b29 100644 --- a/src/utils/parse.rs +++ b/src/utils/parse.rs @@ -8,13 +8,13 @@ pub struct Testcases { pub testcases: HashMap, } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct Testcase { pub action: String, pub arguments: Value, } -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Serialize, Deserialize, Clone)] pub struct Responses { pub responses: HashMap, } @@ -28,8 +28,6 @@ pub fn parse_json(json: String) -> Result { mod tests { use std::fs; - use serde_json::json; - // Note this useful idiom: importing names from outer (for mod tests) scope. use super::*; diff --git a/src/utils/poly.rs b/src/utils/poly.rs index 6425577..6a61853 100644 --- a/src/utils/poly.rs +++ b/src/utils/poly.rs @@ -1,28 +1,567 @@ use crate::utils::field::ByteArray; -use anyhow::{anyhow, Result}; use base64::prelude::*; -use serde_json::Value; + +use num::traits::FromBytes; +use num::{BigUint, One, Zero}; + use std::{str::FromStr, u128, u8, usize}; -use super::{field, math::reverse_bits_in_bytevec}; +use std::{ + cmp::Ordering, + ops::{Add, Mul}, +}; + +use anyhow::{anyhow, Ok, Result}; +use serde_json::Value; + +use super::field::FieldElement; + +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub struct Polynomial { + polynomial: Vec, +} + +impl Polynomial { + pub const fn new(polynomial: Vec) -> Self { + Self { polynomial } + } + + pub fn degree(&self) -> usize { + self.polynomial.len() - 1 + } + + pub fn empty() -> Polynomial { + Polynomial::new(vec![]) + } + + pub fn one() -> Self { + Polynomial::new(vec![FieldElement::one()]) + } + + pub fn x() -> Self { + Polynomial::new(vec![ + FieldElement::new(vec![0; 16]), + FieldElement::new(polynomial_2_block(vec![0], "xex").unwrap()), + ]) + } + + pub fn rand(rng_cap: &usize) -> Self { + let mut rand_poly: Vec = Vec::with_capacity(rng_cap.to_owned()); + for _i in 0..rng_cap.to_owned() { + rand_poly.push(FieldElement::rand()); + } + + Polynomial::new(rand_poly) + } + + pub fn zero() -> Self { + Polynomial::new(vec![FieldElement::zero()]) + } + + 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(); + + 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(coeff.to_b64()); + } + + output + } + + pub fn pow(mut self, mut exponent: u128) -> Polynomial { + let mut result: Polynomial = Polynomial::new(vec![FieldElement::new( + polynomial_2_block(vec![0], "gcm").unwrap(), + )]); + + if exponent == 1 { + return self; + } + + if exponent == 0 { + let result = Polynomial::new(vec![FieldElement::new( + polynomial_2_block(vec![0], "gcm").unwrap(), + )]); + + return result; + } + + while exponent > 0 { + if exponent & 1 == 1 { + let temp = &self * &result; + + result = temp + } + let temp_square = &self * &self; + + self = temp_square; + exponent >>= 1; + } + + while !result.polynomial.is_empty() + && result + .polynomial + .last() + .unwrap() + .as_ref() + .iter() + .all(|&x| x == 0) + { + result.polynomial.pop(); + } + + if result.is_empty() { + result = Polynomial::zero(); + } + + result + } + + pub fn bpow_mod(mut self, mut exponent: BigUint, modulus: &Polynomial) -> Polynomial { + let mut result: Polynomial = Polynomial::new(vec![FieldElement::new( + polynomial_2_block(vec![0], "gcm").unwrap(), + )]); + + if exponent == BigUint::one() { + return self.div(&modulus).1; + } + + if exponent == BigUint::zero() { + let result = Polynomial::new(vec![FieldElement::new( + polynomial_2_block(vec![0], "gcm").unwrap(), + )]); + + return result; + } + + while &exponent > &BigUint::zero() { + if &exponent & BigUint::one() == BigUint::one() { + let temp = &self * &result; + result = temp.div(&modulus).1; + } + let temp_square = &self * &self; + self = temp_square.div(&modulus).1; + exponent >>= 1; + } + + while !result.polynomial.is_empty() + && result + .polynomial + .last() + .unwrap() + .as_ref() + .iter() + .all(|&x| x == 0) + { + result.polynomial.pop(); + } + + if result.is_empty() { + result = Polynomial::zero(); + } + + 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 { + return self.div(&modulus).1; + } + + if exponent == 0 { + let result = Polynomial::new(vec![FieldElement::one()]); + + return result; + } + + while exponent > 0 { + if exponent & 1 == 1 { + let temp = &self * &result; + result = temp.div(&modulus).1; + } + let temp_square = &self * &self; + self = temp_square.div(&modulus).1; + exponent >>= 1; + } + + while !result.polynomial.is_empty() + && result + .polynomial + .last() + .unwrap() + .as_ref() + .iter() + .all(|&x| x == 0) + { + result.polynomial.pop(); + } + + if result.is_empty() { + result = Polynomial::zero(); + } + + result + } + + pub fn div(&self, rhs: &Self) -> (Self, Self) { + if self.polynomial.len() < rhs.polynomial.len() { + return (Polynomial::new(vec![FieldElement::zero()]), self.clone()); + } + + 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::zero()]), remainder); + } + + let mut quotient_coeffs = vec![FieldElement::zero(); 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 pos; + for (i, divisor_coeff) in divisor.polynomial.iter().enumerate() { + pos = deg_diff + i; + let a: &FieldElement = &remainder.polynomial[pos]; + let c: &FieldElement = "_coeff; + remainder.polynomial[pos] = a + &(divisor_coeff * c); + } + + while !remainder.polynomial.is_empty() && remainder.polynomial.last().unwrap().is_zero() + { + remainder.polynomial.pop(); + } + } + + if remainder.is_empty() { + remainder = Polynomial::zero(); + } + + (Polynomial::new(quotient_coeffs), remainder) + } + + fn is_zero(&self) -> bool { + for field_element in &self.polynomial { + if !field_element.is_zero() { + return false; + } + } + true + } + + pub 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(); + } + + 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 + } + + pub fn sqrt(self) -> Self { + let mut result = vec![]; + + for (position, element) in self.polynomial.iter().enumerate() { + if position % 2 == 0 { + result.push(element.clone().pow(2u128.pow(127))); + } + } + + Polynomial::new(result) + } + + pub fn diff(mut self) -> Self { + // Pop first element + // Check if the polynomial is 1 or less. In this case, output would be [] without check + // Output should be [0; 16] however + if self.polynomial.len() > 1 { + self.polynomial.remove(0); + } else { + return Polynomial::new(vec![FieldElement::new(vec![0; 16])]); + } + + for (position, element) in self.polynomial.iter_mut().enumerate() { + // Set all uneven degrees to 0, as they were the even degrees before + // As we are in GF128, this means they become 0 after mul with even number + if position % 2 == 1 { + *element = FieldElement::new(vec![0; 16]); + } + } + + 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 + } + + pub fn extract_component(&self, i: u32) -> FieldElement { + self.polynomial[i as usize].clone() + } +} + +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::zero(); + } + let mut polynomial: Vec = + vec![FieldElement::zero(); 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::zero(); + } + let mut polynomial: Vec = + vec![FieldElement::zero(); 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::zero()]); + } + + 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()) + { + match field_a + //.reverse_bits() + .partial_cmp(&field_b) + .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) + { + Ordering::Equal => continue, + other => return other, + } + } + Ordering::Equal + } + other => other.reverse(), + } + } +} + +pub fn gcd(a: &Polynomial, b: &Polynomial) -> Polynomial { + if a.is_zero() { + return b.clone(); + } + if b.is_zero() { + return a.clone(); + } + + if a.degree() > b.degree() { + return gcd(b, a); + } + + let (_, remainder) = b.div(a); + + if remainder.is_zero() { + return a.clone().monic(); + } + + gcd(&remainder, a) +} + +pub fn non_monic_gcd(a: &Polynomial, b: &Polynomial) -> Polynomial { + if a.is_zero() { + return b.clone(); + } + + let b = b.div(&a).1; + return non_monic_gcd(&b, a); +} + +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> { - let mut red_poly_bytes: ByteArray = ByteArray(RED_POLY.to_be_bytes().to_vec()); - red_poly_bytes.0.push(0x01); + let red_poly_bytes: ByteArray = ByteArray(RED_POLY.to_be_bytes().to_vec()); - let mut poly1: ByteArray = ByteArray(poly_a.to_owned()); - poly1.0.push(0x00); + let mut poly1: ByteArray = ByteArray(poly_a.to_vec()); - let mut poly2: ByteArray = ByteArray(poly_b.to_owned()); - poly2.0.push(0x00); + let mut poly2: ByteArray = ByteArray(poly_b.to_vec()); if semantic == "gcm" { poly1.reverse_bits_in_bytevec(); poly2.reverse_bits_in_bytevec(); } - let mut result: ByteArray = ByteArray(vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + let mut result: ByteArray = ByteArray(vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); if poly2.LSB_is_one() { result.xor_byte_arrays(&poly1); @@ -30,9 +569,9 @@ pub fn gfmul(poly_a: &Vec, poly_b: &Vec, semantic: &str) -> Result, poly_b: &Vec, semantic: &str) -> Result) -> Result> { pub fn get_alpha_rep(num: u128) -> String { let powers: Vec = get_coefficients(num); - //println!("{:?}", powers); - let mut alpha_rep = String::new(); if powers.len() == 1 { @@ -92,7 +629,6 @@ pub fn b64_2_num(string: &String) -> Result { pub fn get_coefficients(num: u128) -> Vec { let mut powers: Vec = vec![]; for shift in 0..128 { - //println!("{:?}", ((num >> shift) & 1)); if ((num >> shift) & 1) == 1 { powers.push(shift); } @@ -172,7 +708,7 @@ pub fn coefficients_to_byte_arr_xex(coeffs: Vec) -> Vec { let mut byte_array: Vec = vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; for coeff in coeffs { let block_num = coeff / 8; - byte_array[usize::from(block_num)] |= (1 << (coeff % 7)); + byte_array[usize::from(block_num)] |= 1 << (coeff % 7); } byte_array @@ -189,31 +725,12 @@ pub fn coefficient_to_binary(coefficients: Vec) -> u128 { #[cfg(test)] mod tests { - use crate::utils::poly::b64_2_num; + use crate::utils::poly::{b64_2_num, gcd}; use anyhow::Result; + use serde_json::json; // Note this useful idiom: importing names from outer (for mod tests) scope. use super::*; - /* - * TODO: Consider removing - #[test] - fn coefficients_to_byte_arr_xex_test1() { - let coefficients: Vec = vec![0]; - let byte_array = vec![ - 01, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, - ]; - assert_eq!(coefficients_to_byte_arr_xex(coefficients), byte_array) - } - - #[test] - fn coefficients_to_byte_arr_xex_test2() { - let coefficients: Vec = vec![127, 12, 9, 0]; - let byte_array = vec![ - 01, 12, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 00, 80, - ]; - assert_eq!(coefficients_to_byte_arr_xex(coefficients), byte_array) - } - */ #[test] fn byte_indices_0x01() { let byte: u8 = 0x01; @@ -238,7 +755,7 @@ mod tests { #[test] fn coeff_to_binary() { let coefficients: Vec = vec![12, 127, 9, 0]; - let b64: &str = "ARIAAAAAAAAAAAAAAAAAgA=="; + let _b64: &str = "ARIAAAAAAAAAAAAAAAAAgA=="; let calculated_num: u128 = coefficient_to_binary(coefficients); assert_eq!( BASE64_STANDARD.encode(calculated_num.to_ne_bytes()), @@ -258,4 +775,588 @@ 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_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()) + } + + #[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); + } + + #[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); + } + + #[test] + fn test_poly_poly_sqrt() { + let json1 = json!([ + "5TxUxLHO1lHE/rSFquKIAg==", + "AAAAAAAAAAAAAAAAAAAAAA==", + "0DEUJYdHlmd4X7nzzIdcCA==", + "AAAAAAAAAAAAAAAAAAAAAA==", + "PKUa1+JHTxHE8y3LbuKIIA==", + "AAAAAAAAAAAAAAAAAAAAAA==", + "Ds96KiAKKoigKoiKiiKAiA==" + ]); + let expected = json!([ + "NeverGonnaGiveYouUpAAA==", + "NeverGonnaLetYouDownAA==", + "NeverGonnaRunAroundAAA==", + "AndDesertYouAAAAAAAAAA==" + ]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + eprintln!("Starting poly sqrt"); + + let result = element1.sqrt(); + + assert_eq!(json!(result.to_c_array()), expected); + } + + #[test] + fn test_poly_diff() { + let json1 = json!([ + "IJustWannaTellYouAAAAA==", + "HowImFeelingAAAAAAAAAA==", + "GottaMakeYouAAAAAAAAAA==", + "UnderstaaaaaaaaaaaaanQ==" + ]); + let expected = json!([ + "HowImFeelingAAAAAAAAAA==", + "AAAAAAAAAAAAAAAAAAAAAA==", + "UnderstaaaaaaaaaaaaanQ==" + ]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + eprintln!("Starting poly sqrt"); + + let result = element1.diff(); + + assert_eq!(json!(result.to_c_array()), expected); + } + + #[test] + fn test_poly_diff_len1() { + let json1 = json!(["IJustWannaTellYouAAAAA==",]); + let expected = json!(["AAAAAAAAAAAAAAAAAAAAAA==",]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + eprintln!("Starting poly sqrt"); + + let result = element1.diff(); + + assert_eq!(json!(result.to_c_array()), expected); + } + + #[test] + fn test_poly_diff_multi_zero() { + let json1 = json!([ + "AAAAAAAAAAAAAAAAAAAAAA==", + "AAAAAAAAAAAAAAAAAAAAAA==", + "AAAAAAAAAAAAAAAAAAAAAA==", + "AAAAAAAAAAAAAAAAAAAAAA==", + "AAAAAAAAAAAAAAAAAAAAAA==", + ]); + let expected = json!(["AAAAAAAAAAAAAAAAAAAAAA==",]); + let element1: Polynomial = Polynomial::from_c_array(&json1); + + let result = element1.diff(); + + assert_eq!(json!(result.to_c_array()), expected); + } + + #[test] + fn test_poly_gcd() { + let a = json!([ + "DNWpXnnY24XecPa7a8vrEA==", + "I8uYpCbsiPaVvUznuv1IcA==", + "wsbiU432ARWuO93He3vbvA==", + "zp0g3o8iNz7Y+8oUxw1vJw==", + "J0GekE3uendpN6WUAuJ4AA==", + "wACd0e6u1ii4AAAAAAAAAA==", + "ACAAAAAAAAAAAAAAAAAAAA==" + ]); + let b = json!([ + "I20VjJmlSnRSe88gaDiLRQ==", + "0Cw5HxJm/pfybJoQDf7/4w==", + "8ByrMMf+vVj5r3YXUNCJ1g==", + "rEU/f2UZRXqmZ6V7EPKfBA==", + "LfdALhvCrdhhGZWl9l9DSg==", + "KSUKhN0n6/DZmHPozd1prw==", + "DQrRkuA9Zx279wAAAAAAAA==", + "AhCEAAAAAAAAAAAAAAAAAA==" + ]); + let expected = json!([ + "NeverGonnaMakeYouCryAA==", + "NeverGonnaSayGoodbyeAA==", + "NeverGonnaTellALieAAAA==", + "AndHurtYouAAAAAAAAAAAA==", + "gAAAAAAAAAAAAAAAAAAAAA==" + ]); + + let a: Polynomial = Polynomial::from_c_array(&a); + let b: Polynomial = Polynomial::from_c_array(&b); + + let result = gcd(&a.monic(), &b.monic()); + + assert_eq!(json!(result.to_c_array()), expected); + } + + #[test] + fn test_poly_gcd_zero() { + let a = json!(["AAAAAAAAAAAAAAAAAAAAAA==",]); + let b = json!(["AAAAAAAAAAAAAAAAAAAAAA=="]); + let expected = json!(["AAAAAAAAAAAAAAAAAAAAAA=="]); + + let a: Polynomial = Polynomial::from_c_array(&a); + let b: Polynomial = Polynomial::from_c_array(&b); + + let result = gcd(&a.monic(), &b.monic()); + + assert_eq!(json!(result.to_c_array()), expected); + } + + #[test] + fn test_poly_gcd_stress() { + eprintln!("{:?}", Polynomial::one()); + + let poly1 = Polynomial::rand(&(500 as usize)); + let poly2 = Polynomial::rand(&(500 as usize)); + + let result = gcd(&poly1.monic(), &poly2.monic()); + + eprintln!("{:02X?}", result.to_c_array()); + assert!(true); + } } diff --git a/src/utils/sff.rs b/src/utils/sff.rs new file mode 100644 index 0000000..de2bef6 --- /dev/null +++ b/src/utils/sff.rs @@ -0,0 +1,92 @@ +use serde::{Deserialize, Serialize}; + +use crate::utils::{ + field::FieldElement, + poly::{gcd, polynomial_2_block}, +}; + +use super::poly::Polynomial; + +#[derive(Debug, Serialize, Deserialize)] +pub struct Factors { + pub factor: Vec, + pub exponent: u128, +} + +pub fn sff(mut f: Polynomial) -> Vec<(Polynomial, u128)> { + let mut c = gcd(&f, &f.clone().diff()); + f = f.div(&c).0; + let mut z: Vec<(Polynomial, u128)> = vec![]; + let mut e: u128 = 1; + + let one_element = Polynomial::new(vec![FieldElement::new( + polynomial_2_block(vec![0], "gcm").unwrap(), + )]); + + while f != one_element { + let y = gcd(&f, &c); + if f != y { + z.push(((f.div(&y).0), e)); + } + + f = y.clone(); + c = c.div(&y).0; + e += 1; + } + + if c != one_element { + let r = sff(c.sqrt()); + for (f_star, e_star) in r { + z.push((f_star, 2 * e_star)); + } + } + + z +} + +#[cfg(test)] +mod tests { + + use serde_json::json; + // Note this useful idiom: importing names from outer (for mod tests) scope. + use super::*; + + #[test] + fn byte_indices_0x01() { + let json_f = json!([ + "vL77UwAAAAAAAAAAAAAAAA==", + "mEHchYAAAAAAAAAAAAAAAA==", + "9WJa0MAAAAAAAAAAAAAAAA==", + "akHfwWAAAAAAAAAAAAAAAA==", + "E12o/QAAAAAAAAAAAAAAAA==", + "vKJ/FgAAAAAAAAAAAAAAAA==", + "yctWwAAAAAAAAAAAAAAAAA==", + "c1BXYAAAAAAAAAAAAAAAAA==", + "o0AtAAAAAAAAAAAAAAAAAA==", + "AbP2AAAAAAAAAAAAAAAAAA==", + "k2YAAAAAAAAAAAAAAAAAAA==", + "vBYAAAAAAAAAAAAAAAAAAA==", + "dSAAAAAAAAAAAAAAAAAAAA==", + "69gAAAAAAAAAAAAAAAAAAA==", + "VkAAAAAAAAAAAAAAAAAAAA==", + "a4AAAAAAAAAAAAAAAAAAAA==", + "gAAAAAAAAAAAAAAAAAAAAA==" + ]); + let poly_f = Polynomial::from_c_array(&json_f); + + let mut factors = sff(poly_f); + factors.sort(); + let mut result: Vec = vec![]; + + for (factor, exponent) in factors { + result.push(Factors { + factor: factor.to_c_array(), + exponent, + }); + } + + println!("{:?}", result); + let _bit_indices: Vec = vec![0]; + assert!(false) + } +} diff --git a/test_json/poly_algs.json b/test_json/poly_algs.json new file mode 100644 index 0000000..b4a687e --- /dev/null +++ b/test_json/poly_algs.json @@ -0,0 +1,29 @@ +{ + "testcases": { + "b856d760-023d-4b00-bad2-15d2b6da22fe": { + +"action": "gfpoly_sort", +"arguments": { +"polys": [ +[ +"NeverGonnaGiveYouUpAAA==", +"NeverGonnaLetYouDownAA==", +"NeverGonnaRunAroundAAA==", +"AndDesertYouAAAAAAAAAA==" +], +[ +"WereNoStrangersToLoveA==", +"YouKnowTheRulesAAAAAAA==", +"AndSoDoIAAAAAAAAAAAAAA==" +], +[ +"NeverGonnaMakeYouCryAA==", +"NeverGonnaSayGoodbyeAA==", +"NeverGonnaTellALieAAAA==", +"AndHurtYouAAAAAAAAAAAA==" +] +] +} +} + } +} diff --git a/test_json/sandbox.json b/test_json/sandbox.json new file mode 100644 index 0000000..e3f5e1f --- /dev/null +++ b/test_json/sandbox.json @@ -0,0 +1,29 @@ +{ + "testcases": { + "gcm_crack1": { + "action": "gcm_crack", + "arguments": { + "nonce": "4gF+BtR3ku/PUQci", + "m1": { + "ciphertext": "CGOkZDnJEt24aVV8mqQq+P4pouVDWhAYj0SN5MDAgg==", + "associated_data": "TmFjaHJpY2h0IDE=", + "tag": "GC9neV3aZLnmznTIWqCC4A==" + }, + "m2": { + "ciphertext": "FnWyLSTfRrO8Y1MuhLIs6A==", + "associated_data": "", + "tag": "gb2ph1vzwU85/FsUg51t3Q==" + }, + "m3": { + "ciphertext": "CGOkZDnJEt25aV58iaMt6O8+8chKVh0Eg1XFxA==", + "associated_data": "TmFjaHJpY2h0IDM=", + "tag": "+/aDjsAzTseDLuM4jt5Q6Q==" + }, + "forgery": { + "ciphertext": "AXe/ZQ==", + "associated_data": "" + } + } + } + } +}