solve all previous levels

This commit is contained in:
2025-09-12 01:26:50 +02:00
parent 1a3f5bb015
commit eea37dcd31
12 changed files with 378 additions and 124 deletions

View File

@@ -11,6 +11,8 @@ reqwest = { version = "0.12.23", features = ["blocking"] }
rug = "1.28.0" rug = "1.28.0"
rand = "0.9.2" rand = "0.9.2"
tqdm = "0.8.0" tqdm = "0.8.0"
sha2 = "0.10.9"
percent-encoding = "2.3.2"
[lib] [lib]
name = "lib" name = "lib"

View File

@@ -1,125 +1,12 @@
#![allow(dead_code)]
use lazy_static::lazy_static;
use lib::submit; use lib::submit;
use std::fs::File; use lib::challenges::c7_weird_assembly_machine::f_n;
use std::io::{BufRead, BufReader};
use std::str::FromStr;
lazy_static!(
static ref DATA: Vec<u64> = {
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 N: u64 = 979607657800000055; const N: u64 = 979607657800000055;
const X: u64 = 10962444957429324784; const X: u64 = 10962444957429324784;
fn main() { fn main() {
fn sum(n: u64, k: u64) -> u64 { let (n, x) = f_n(N, X, 1_000_000_000_000_000_000u64 - N);
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();
println!("n = {n}"); println!("n = {n}");
println!("x = {x}"); println!("x = {x}");
} submit(n, x).unwrap();
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
}
} }

26
src/bin/main.rs Normal file
View File

@@ -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()));
}

View File

@@ -0,0 +1,3 @@
pub fn solve() -> (u64, u64) {
(10000, 4)
}

View File

@@ -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)
}

View File

@@ -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<u64> {
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);
}
}

View File

@@ -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)
}

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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<u64> = {
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
}
}

View File

@@ -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;

View File

@@ -1,4 +1,4 @@
use anyhow::{Result, anyhow}; use anyhow::{anyhow, Result};
use json::JsonValue; use json::JsonValue;
use std::fmt::Display; use std::fmt::Display;
use std::sync::mpsc; use std::sync::mpsc;
@@ -7,10 +7,17 @@ use std::thread;
use std::thread::JoinHandle; use std::thread::JoinHandle;
use std::time::Instant; use std::time::Instant;
pub mod challenges;
const USER_NAME: &str = "Jonah"; const USER_NAME: &str = "Jonah";
pub fn compute_async<T: Display + Send + 'static, R: Send + 'static>(mut function: impl FnMut(Sender<(T, T)>) -> R + Send + 'static ) -> R { pub fn compute_async<T1: Display + Send + 'static, T2: Display + Send + 'static, R: Send + 'static>(function: impl FnMut(Sender<(T1, T2)>) -> R + Send + 'static ) -> R {
let (tx, jh1) = spawn_submission_thread(); compute_async_with_name(USER_NAME, function)
}
pub fn compute_async_with_name<T1: Display + Send + 'static, T2: Display + Send + 'static, R: Send + 'static>(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 || { let jh2 = thread::spawn(move || {
function(tx) function(tx)
}); });
@@ -19,8 +26,8 @@ pub fn compute_async<T: Display + Send + 'static, R: Send + 'static>(mut functio
jh2.join().unwrap() jh2.join().unwrap()
} }
pub fn spawn_submission_thread<T: Display + Send + 'static>() -> (Sender<(T, T)>, JoinHandle<()>) { pub fn spawn_submission_thread<T1: Display + Send + 'static, T2: Display + Send + 'static>(name: &'static str) -> (Sender<(T1, T2)>, JoinHandle<()>) {
let (tx, rx) = mpsc::channel::<(T, T)>(); let (tx, rx) = mpsc::channel::<(T1, T2)>();
let handle = thread::spawn(move || { let handle = thread::spawn(move || {
let mut t = Instant::now(); let mut t = Instant::now();
for (n, x) in rx { for (n, x) in rx {
@@ -28,7 +35,7 @@ pub fn spawn_submission_thread<T: Display + Send + 'static>() -> (Sender<(T, T)>
println!("\nn = {n}\nx = {x}\nduration = {}", t2.duration_since(t).as_millis()); println!("\nn = {n}\nx = {x}\nduration = {}", t2.duration_since(t).as_millis());
t = t2; t = t2;
match submit(n, x) { match submit_with_name(name, n, x) {
Ok(_) => {} Ok(_) => {}
Err(err) => eprintln!("{:?}", err), Err(err) => eprintln!("{:?}", err),
}; };
@@ -37,8 +44,13 @@ pub fn spawn_submission_thread<T: Display + Send + 'static>() -> (Sender<(T, T)>
(tx, handle) (tx, handle)
} }
pub fn submit<T: Display + Send>(n: T, x: T) -> Result<Option<String>> { pub fn submit<T1: Display + Send, T2: Display + Send>(n: T1, x: T2) -> Result<Option<String>> {
let url = format!("https://button.qedaka.de/server.php?name={USER_NAME}&n={n}&x={x}"); submit_with_name(USER_NAME, n, x)
}
pub fn submit_with_name<T1: Display + Send, T2: Display + Send>(name: &str, n: T1, x: T2) -> Result<Option<String>> {
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()?; let body = reqwest::blocking::get(url)?.text()?;
match json::parse(&body)? { match json::parse(&body)? {
JsonValue::Object(obj) => { JsonValue::Object(obj) => {