From eea37dcd31b800d8d5b1b0d7f274d3cdba92480f Mon Sep 17 00:00:00 2001 From: jbb01 <32650546+jbb01@users.noreply.github.com> Date: Fri, 12 Sep 2025 01:26:50 +0200 Subject: [PATCH] solve all previous levels --- Cargo.toml | 2 + src/bin/07_weird_assembly_machine.rs | 119 +--------------- src/bin/main.rs | 26 ++++ src/lib/challenges/c1_welcome.rs | 3 + .../challenges/c2_these_numbers_are_big.rs | 26 ++++ .../c3_are_you_still_doing_this_by_hand.rs | 87 ++++++++++++ src/lib/challenges/c4_broken_proof_of_work.rs | 17 +++ src/lib/challenges/c5_what_the_bf.rs | 33 +++++ .../challenges/c6_automation_is_not_enough.rs | 26 ++++ .../challenges/c7_weird_assembly_machine.rs | 128 ++++++++++++++++++ src/lib/challenges/mod.rs | 7 + src/lib/lib.rs | 28 ++-- 12 files changed, 378 insertions(+), 124 deletions(-) create mode 100644 src/bin/main.rs create mode 100644 src/lib/challenges/c1_welcome.rs create mode 100644 src/lib/challenges/c2_these_numbers_are_big.rs create mode 100644 src/lib/challenges/c3_are_you_still_doing_this_by_hand.rs create mode 100644 src/lib/challenges/c4_broken_proof_of_work.rs create mode 100644 src/lib/challenges/c5_what_the_bf.rs create mode 100644 src/lib/challenges/c6_automation_is_not_enough.rs create mode 100644 src/lib/challenges/c7_weird_assembly_machine.rs create mode 100644 src/lib/challenges/mod.rs diff --git a/Cargo.toml b/Cargo.toml index ad0933f..3e7d7fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,8 @@ reqwest = { version = "0.12.23", features = ["blocking"] } rug = "1.28.0" rand = "0.9.2" tqdm = "0.8.0" +sha2 = "0.10.9" +percent-encoding = "2.3.2" [lib] name = "lib" diff --git a/src/bin/07_weird_assembly_machine.rs b/src/bin/07_weird_assembly_machine.rs index a9ee322..618a1db 100644 --- a/src/bin/07_weird_assembly_machine.rs +++ b/src/bin/07_weird_assembly_machine.rs @@ -1,125 +1,12 @@ -#![allow(dead_code)] - -use lazy_static::lazy_static; use lib::submit; -use std::fs::File; -use std::io::{BufRead, BufReader}; -use std::str::FromStr; - -lazy_static!( - static ref DATA: Vec = { - let file = File::open("./res/07_weird_assembly_machine.data"); - let lines = BufReader::new(file.unwrap()).lines(); - - let mut data = Vec::new(); - for line in lines { - data.push(u64::from_str(&line.unwrap()).unwrap()); - } - data - }; -); +use lib::challenges::c7_weird_assembly_machine::f_n; const N: u64 = 979607657800000055; const X: u64 = 10962444957429324784; fn main() { - fn sum(n: u64, k: u64) -> u64 { - let mut sum = 0u64; - for i in 1..=k { - sum = add(sum, fg_n(n + i, k - i)); - } - sum - } - - fn fast_sum(n: u64, k: u64) -> u64 { - debug_assert!(k % 192 == 0); - let mut result = sum(n, 0); - result = add(result, ((13556435138434861179u128 * (k / 192) as u128) % (u64::MAX as u128)) as u64); - result - } - - let mut n = N; - let mut x = X; - - n += 1; - x = sub(f(x), n); - - let k = (1_000_000_000_000_000_000u64 - n) / 192 * 192; - let sum = fast_sum(n , k); - x = sub(fg_n(x, k), sum); - n += k; - - x = g(x); - - submit(n, x).unwrap(); + let (n, x) = f_n(N, X, 1_000_000_000_000_000_000u64 - N); println!("n = {n}"); println!("x = {x}"); -} - -fn f(x: u64) -> u64 { - evaluate(x, &DATA[..128], &DATA[..128]) -} - -fn g(x: u64) -> u64 { - evaluate(x, &DATA[128..], &DATA[128..]) -} - -fn add(a: u64, b: u64) -> u64 { - let (result, overflow) = a.overflowing_add(b); - result + overflow as u64 -} - -fn sub(x: u64, mut n: u64) -> u64 { - if x <= n { - n += 1; - } - x.wrapping_sub(n) -} - -fn fg(x: u64) -> u64 { - !x.rotate_left(17) - // evaluate(x, FG_DATA_EVEN, FG_DATA_ODD) -} - -fn fg_n(mut x: u64, n: u64) -> u64 { - for _ in 0..n%64 { - x = fg(x); - } - x -} - -fn evaluate(x: u64, data_even: &[u64], data_odd: &[u64]) -> u64 { - let data = if x.count_ones() % 2 == 0 { data_even } else { data_odd }; - - let mut out = 0; - for i in 0..data.len() { - out = xor_mul(out, x) ^ data[i]; - } - out -} - -#[cfg(not(all(target_arch = "x86_64", target_feature = "pclmulqdq")))] -fn xor_mul(a: u64, mut b: u64) -> u64 { - let mut x: u64 = 0; - while b != 0 { - let c = b.trailing_zeros(); - b = b ^ 1u64.rotate_left(c); - x = x ^ a.rotate_left(c); - } - x -} - -#[cfg(all(target_arch = "x86_64", target_feature = "pclmulqdq"))] -fn xor_mul(a: u64, b: u64) -> u64 { - use std::arch::x86_64::*; - unsafe { - let a_vec = _mm_set_epi64x(0, a as i64); - let b_vec = _mm_set_epi64x(0, b as i64); - let result = _mm_clmulepi64_si128(a_vec, b_vec, 0x00); - - // Extract both 64-bit halves and XOR them - let low = _mm_extract_epi64(result, 0) as u64; - let high = _mm_extract_epi64(result, 1) as u64; - low ^ high - } + submit(n, x).unwrap(); } \ No newline at end of file diff --git a/src/bin/main.rs b/src/bin/main.rs new file mode 100644 index 0000000..ab219a3 --- /dev/null +++ b/src/bin/main.rs @@ -0,0 +1,26 @@ +use lib::submit_with_name; + +fn main() { + let name = "((ο)=>((o)=>o(((o(((ο*o([!+[]+!+"; + + let (n, x) = lib::challenges::c1_welcome::solve(); + println!("n = {:?}\nx = {:?}\n{:?}\n", n, x, submit_with_name(name, n, x)); + + let (n, x) = lib::challenges::c2_these_numbers_are_big::solve(name); + println!("n = {:?}\nx = {:?}\n{:?}\n", n, x, submit_with_name(name, n, x.clone())); + + let (n, x) = lib::challenges::c3_are_you_still_doing_this_by_hand::solve(n, x); + println!("n = {:?}\nx = {:?}\n{:?}\n", n, x, submit_with_name(name, n, x.clone())); + + let (n, x) = lib::challenges::c4_broken_proof_of_work::solve(n, x); + println!("n = {:?}\nx = {:?}\n{:?}\n", n, x, submit_with_name(name, n, x.clone())); + + let (n, x) = lib::challenges::c5_what_the_bf::solve(n, x); + println!("n = {:?}\nx = {:?}\n{:?}\n", n, x, submit_with_name(name, n, x.clone())); + + let (n, x) = lib::challenges::c6_automation_is_not_enough::solve(n, x); + println!("n = {:?}\nx = {:?}\n{:?}\n", n, x, submit_with_name(name, n, x.clone())); + + let (n, x) = lib::challenges::c7_weird_assembly_machine::solve(n, x); + println!("n = {:?}\nx = {:?}\n{:?}\n", n, x, submit_with_name(name, n, x.clone())); +} \ No newline at end of file diff --git a/src/lib/challenges/c1_welcome.rs b/src/lib/challenges/c1_welcome.rs new file mode 100644 index 0000000..e85bbaa --- /dev/null +++ b/src/lib/challenges/c1_welcome.rs @@ -0,0 +1,3 @@ +pub fn solve() -> (u64, u64) { + (10000, 4) +} \ No newline at end of file diff --git a/src/lib/challenges/c2_these_numbers_are_big.rs b/src/lib/challenges/c2_these_numbers_are_big.rs new file mode 100644 index 0000000..2dfe91b --- /dev/null +++ b/src/lib/challenges/c2_these_numbers_are_big.rs @@ -0,0 +1,26 @@ +use std::str::FromStr; +use lazy_static::lazy_static; +use rug::Integer; +use rug::integer::Order; +use sha2::{Sha256, Digest}; + +lazy_static!( + static ref M: Integer = Integer::from_str("14004392365098131090160062970945115111185775413941111064876648140973294115502980816410773368597517292734034227298996122159833675150497554142801209096513652073059992938078366061434391648276904643753267405058183481162693381822800709938988762923").unwrap(); + static ref E: Integer = Integer::from(65537); +); + +pub fn solve(name: &str) -> (u64, Integer) { + let mut x = sha256(name); + println!("sha256 = {x}"); + x += 4; + for _ in tqdm::tqdm(0..10_000) { + for _ in 0..100 { + x.pow_mod_mut(&E, &M).unwrap(); + } + } + (20_000, x) +} + +pub fn sha256(name: &str) -> Integer { + Integer::from_digits(Sha256::digest(name).as_slice(), Order::MsfBe) +} \ No newline at end of file diff --git a/src/lib/challenges/c3_are_you_still_doing_this_by_hand.rs b/src/lib/challenges/c3_are_you_still_doing_this_by_hand.rs new file mode 100644 index 0000000..5237bde --- /dev/null +++ b/src/lib/challenges/c3_are_you_still_doing_this_by_hand.rs @@ -0,0 +1,87 @@ +use rug::Integer; +use std::collections::HashMap; +use tqdm::tqdm; + +const P: u64 = 12345679943u64; + +pub fn solve(n: u64, x: Integer) -> (u64, Integer) { + let x = x.modulo(&Integer::from(P - 1)).to_u64().unwrap(); + + let mut n = n; + let mut x = x.clone(); + for _ in tqdm(0..10_000) { + n += 1; + x = log(42, 1 + (x + n) % (P - 1), P).unwrap(); + } + + (n, Integer::from(x)) +} + +fn log(g: u64, b: u64, m: u64) -> Option { + let g: u128 = g as u128; + let b: u128 = b as u128; + let m: u128 = m as u128; + + let s = m.isqrt() + 1; + let mut r = HashMap::new(); + + let mut a = b % m; + if a == 1 { + return Some(0); + } + + for i in 0..s { + r.insert(a, i); + a *= g; + a %= m; + } + + let gs = pow(g as u64, s as u64, m as u64) as u128; + a = gs; + for j in 1..=s { + if let Some(i) = r.get(&a) { + return Some((j * s - i) as u64); + } + + a *= gs; + a %= m; + } + + None +} + +fn pow(a: u64, mut k: u64, m: u64) -> u64 { + let mut a: u128 = a as u128; + let m: u128 = m as u128; + let mut b = 1u128; + while k != 0 { + if k % 2 == 1 { + b *= a; + b %= m; + } + a *= a; + a %= m; + + k >>= 1; + } + b as u64 +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn log_test() { + assert_eq!(log(3, 12, 23), Some(4)); + assert_eq!(log(2, 3, 5), Some(3)); + + log(42, 3816393254, 12345679943); + } + + #[test] + fn pow_test() { + assert_eq!(pow(2, 3, 5), 3); + assert_eq!(pow(3, 4, 23), 12); + } +} \ No newline at end of file diff --git a/src/lib/challenges/c4_broken_proof_of_work.rs b/src/lib/challenges/c4_broken_proof_of_work.rs new file mode 100644 index 0000000..7bbd299 --- /dev/null +++ b/src/lib/challenges/c4_broken_proof_of_work.rs @@ -0,0 +1,17 @@ +use rug::Integer; + +const LIMIT: u64 = 100_000_000; + +pub fn solve(n: u64, x: Integer) -> (u64, Integer) { + let k = LIMIT - n; + + let mut x = x + (k / 4) * 1_640_000; + for _ in 0..k%4 { + for _ in 0..10000 { + x += 41; + x ^= 42; + } + } + + (LIMIT, x) +} \ No newline at end of file diff --git a/src/lib/challenges/c5_what_the_bf.rs b/src/lib/challenges/c5_what_the_bf.rs new file mode 100644 index 0000000..30ea4df --- /dev/null +++ b/src/lib/challenges/c5_what_the_bf.rs @@ -0,0 +1,33 @@ +use rug::{Assign, Integer}; + +const LIMIT: u64 = 1_000_000_000_000u64; +const M: u64 = 1_000_000_000_000u64 - 11; + +// x_{n+1} = 1/11 * x mod (10^12 - 11) + + +pub fn solve(n: u64, x: Integer) -> (u64, Integer) { + let k = LIMIT - n - 1; + + let mut x = x; + for _ in 0..100 { + let y = x.to_u128().unwrap(); + x.assign(f(y)); + } + + let a = Integer::from(11).pow_mod(&Integer::from(-1), &Integer::from(M)).unwrap(); + let b = a.pow_mod(&Integer::from(100 * k), &Integer::from(M)).unwrap(); + + (LIMIT, x * b % &M) +} + + +const A: u128 = 909_090_909_091u128; // (10 * b + 1) / 11 +const B: u128 = 1_000_000_000_000u128; // 10^12 +const C: u128 = 999_999_999_989u128; // b - 11 +const D: u128 = 999_999_999_999u128; // b - 1 +fn f(mut x: u128) -> u128 { + x = x * A % B; + x = (x * C + D) / B; + x +} \ No newline at end of file diff --git a/src/lib/challenges/c6_automation_is_not_enough.rs b/src/lib/challenges/c6_automation_is_not_enough.rs new file mode 100644 index 0000000..593c8ae --- /dev/null +++ b/src/lib/challenges/c6_automation_is_not_enough.rs @@ -0,0 +1,26 @@ +use lazy_static::lazy_static; +use rug::Integer; +use std::str::FromStr; + +const START: u64 = 1_000_000_000_000u64; +const LIMIT: u64 = 10_000_000_000_000_000u64; + +lazy_static!( + static ref M: Integer = Integer::from_str("14004392365098131090160062970945115111185775413941111064876648140973294115502980816410773368597517292734034227298996122159833675150497554142801209096513652073059992938078366061434391648276904643753267405058183481162693381822800709938988762923").unwrap(); + static ref A: Integer = Integer::from_str("10729297455904899337681752672816753703351288544833760635567859176397566160330812285369370751389224534974913042757043771146367160829669925123791471756026119030734890865062863499420767799283504416995775836275660636668989077836006690621539265605").unwrap(); + static ref B: Integer = Integer::from_str("4997609466256208183077203585670710326160976219126614124062259398288517298185253986607627790890962248558793881836308854443463332741665631247256917127102588793451033551034614994254514161235462726178612824897626185944163885786520174491419225456").unwrap(); +); + +pub fn solve(n: u64, x: Integer) -> (u64, Integer) { + assert_eq!(n, START); + let m: &Integer = &M; + let a: &Integer = &A; + let b: &Integer = &B; + + let mut x = x; + x = (x + a) % m; + x = x * 2 % m; + x = (x + b) % m; + + (LIMIT, x) +} \ No newline at end of file diff --git a/src/lib/challenges/c7_weird_assembly_machine.rs b/src/lib/challenges/c7_weird_assembly_machine.rs new file mode 100644 index 0000000..2433b7a --- /dev/null +++ b/src/lib/challenges/c7_weird_assembly_machine.rs @@ -0,0 +1,128 @@ +use std::fs::File; +use std::io::{BufRead, BufReader}; +use std::str::FromStr; +use lazy_static::lazy_static; +use rug::Integer; + +lazy_static!( + static ref DATA: Vec = { + let file = File::open("./res/07_weird_assembly_machine.data"); + let lines = BufReader::new(file.unwrap()).lines(); + + let mut data = Vec::new(); + for line in lines { + data.push(u64::from_str(&line.unwrap()).unwrap()); + } + data + }; +); + +const LIMIT: u64 = 1_000_000_000_000_000_000u64; + +pub fn solve(n: u64, x: Integer) -> (u64, Integer) { + let x = x.to_u64_wrapping(); + let (n, x) = f_n(n, x, LIMIT - n); + (n, Integer::from(x)) +} + + +pub fn f_n(mut n: u64, mut x: u64, k: u64) -> (u64, u64) { + n += 1; + x = sub(f(x), n); + + let fast_k = (k - 1) / 192 * 192; + let sum = fast_fg_sum(n , fast_k); + x = sub(fg_n(x, fast_k), sum); + n += fast_k; + + let remaining = (k - 1) - fast_k; + let sum = fg_sum(n, remaining); + x = sub(fg_n(x, remaining), sum); + n += remaining; + + x = g(x); + + (n, x) +} + +fn fg_sum(n: u64, k: u64) -> u64 { + let mut sum = 0u64; + for i in 1..=k { + sum = add(sum, fg_n(n + i, k - i)); + } + sum +} + +fn fast_fg_sum(n: u64, k: u64) -> u64 { + debug_assert!(k % 192 == 0); + let mut result = fg_sum(n, 0); + result = add(result, ((13556435138434861179u128 * (k / 192) as u128) % (u64::MAX as u128)) as u64); + result +} + +fn f(x: u64) -> u64 { + evaluate(x, &DATA[..128], &DATA[..128]) +} + +fn g(x: u64) -> u64 { + evaluate(x, &DATA[128..], &DATA[128..]) +} + +fn add(a: u64, b: u64) -> u64 { + let (result, overflow) = a.overflowing_add(b); + result + overflow as u64 +} + +fn sub(x: u64, mut n: u64) -> u64 { + if x <= n { + n += 1; + } + x.wrapping_sub(n) +} + +fn fg(x: u64) -> u64 { + !x.rotate_left(17) +} + +fn fg_n(mut x: u64, n: u64) -> u64 { + for _ in 0..n%64 { + x = fg(x); + } + x +} + +fn evaluate(x: u64, data_even: &[u64], data_odd: &[u64]) -> u64 { + let data = if x.count_ones() % 2 == 0 { data_even } else { data_odd }; + + let mut out = 0; + for i in 0..data.len() { + out = xor_mul(out, x) ^ data[i]; + } + out +} + +#[cfg(not(all(target_arch = "x86_64", target_feature = "pclmulqdq")))] +fn xor_mul(a: u64, mut b: u64) -> u64 { + let mut x: u64 = 0; + while b != 0 { + let c = b.trailing_zeros(); + b = b ^ 1u64.rotate_left(c); + x = x ^ a.rotate_left(c); + } + x +} + +#[cfg(all(target_arch = "x86_64", target_feature = "pclmulqdq"))] +fn xor_mul(a: u64, b: u64) -> u64 { + use std::arch::x86_64::*; + unsafe { + let a_vec = _mm_set_epi64x(0, a as i64); + let b_vec = _mm_set_epi64x(0, b as i64); + let result = _mm_clmulepi64_si128(a_vec, b_vec, 0x00); + + // Extract both 64-bit halves and XOR them + let low = _mm_extract_epi64(result, 0) as u64; + let high = _mm_extract_epi64(result, 1) as u64; + low ^ high + } +} \ No newline at end of file diff --git a/src/lib/challenges/mod.rs b/src/lib/challenges/mod.rs new file mode 100644 index 0000000..316df95 --- /dev/null +++ b/src/lib/challenges/mod.rs @@ -0,0 +1,7 @@ +pub mod c1_welcome; +pub mod c2_these_numbers_are_big; +pub mod c3_are_you_still_doing_this_by_hand; +pub mod c4_broken_proof_of_work; +pub mod c5_what_the_bf; +pub mod c6_automation_is_not_enough; +pub mod c7_weird_assembly_machine; \ No newline at end of file diff --git a/src/lib/lib.rs b/src/lib/lib.rs index 50b0639..b944857 100644 --- a/src/lib/lib.rs +++ b/src/lib/lib.rs @@ -1,4 +1,4 @@ -use anyhow::{Result, anyhow}; +use anyhow::{anyhow, Result}; use json::JsonValue; use std::fmt::Display; use std::sync::mpsc; @@ -7,10 +7,17 @@ use std::thread; use std::thread::JoinHandle; use std::time::Instant; +pub mod challenges; + const USER_NAME: &str = "Jonah"; -pub fn compute_async(mut function: impl FnMut(Sender<(T, T)>) -> R + Send + 'static ) -> R { - let (tx, jh1) = spawn_submission_thread(); +pub fn compute_async(function: impl FnMut(Sender<(T1, T2)>) -> R + Send + 'static ) -> R { + compute_async_with_name(USER_NAME, function) +} + + +pub fn compute_async_with_name(name: &'static str, mut function: impl FnMut(Sender<(T1, T2)>) -> R + Send + 'static ) -> R { + let (tx, jh1) = spawn_submission_thread(name); let jh2 = thread::spawn(move || { function(tx) }); @@ -19,8 +26,8 @@ pub fn compute_async(mut functio jh2.join().unwrap() } -pub fn spawn_submission_thread() -> (Sender<(T, T)>, JoinHandle<()>) { - let (tx, rx) = mpsc::channel::<(T, T)>(); +pub fn spawn_submission_thread(name: &'static str) -> (Sender<(T1, T2)>, JoinHandle<()>) { + let (tx, rx) = mpsc::channel::<(T1, T2)>(); let handle = thread::spawn(move || { let mut t = Instant::now(); for (n, x) in rx { @@ -28,7 +35,7 @@ pub fn spawn_submission_thread() -> (Sender<(T, T)> println!("\nn = {n}\nx = {x}\nduration = {}", t2.duration_since(t).as_millis()); t = t2; - match submit(n, x) { + match submit_with_name(name, n, x) { Ok(_) => {} Err(err) => eprintln!("{:?}", err), }; @@ -37,8 +44,13 @@ pub fn spawn_submission_thread() -> (Sender<(T, T)> (tx, handle) } -pub fn submit(n: T, x: T) -> Result> { - let url = format!("https://button.qedaka.de/server.php?name={USER_NAME}&n={n}&x={x}"); +pub fn submit(n: T1, x: T2) -> Result> { + submit_with_name(USER_NAME, n, x) +} + +pub fn submit_with_name(name: &str, n: T1, x: T2) -> Result> { + let name = percent_encoding::percent_encode(name.as_bytes(), percent_encoding::NON_ALPHANUMERIC); + let url = format!("https://button.qedaka.de/server.php?name={}&n={n}&x={x}", name); let body = reqwest::blocking::get(url)?.text()?; match json::parse(&body)? { JsonValue::Object(obj) => {