Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 63561f368e | |||
| 49d6fdff9d | |||
| f5d3828cb4 | |||
| 997efb0ad4 | |||
| 7f33c43169 | |||
| 81fea4865e | |||
| eea37dcd31 | |||
| 1a3f5bb015 | |||
| 2ed82171af | |||
| 02f3bfffce | |||
| 013f22d9c7 | |||
| b3dfd161ef | |||
| f83e3ceb9d | |||
| 9ead71c245 | |||
| bf033f67f6 | |||
| dbd8588585 | |||
| 0d878dc96d | |||
| 06ead89143 | |||
| 51722fcecc | |||
| 8cf5a8a9b4 | |||
| d03584e8b6 | |||
| be7161afc6 |
+3
-1
@@ -6,8 +6,10 @@ edition = "2024"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.99"
|
anyhow = "1.0.99"
|
||||||
json = "0.12.4"
|
json = "0.12.4"
|
||||||
|
lazy_static = "1.5.0"
|
||||||
reqwest = { version = "0.12.23", features = ["blocking"] }
|
reqwest = { version = "0.12.23", features = ["blocking"] }
|
||||||
rug = { version = "1.28.0", features = ["integer"], default-features = false }
|
rug = "1.28.0"
|
||||||
|
rand = "0.9.2"
|
||||||
tqdm = "0.8.0"
|
tqdm = "0.8.0"
|
||||||
sha2 = "0.10.9"
|
sha2 = "0.10.9"
|
||||||
percent-encoding = "2.3.2"
|
percent-encoding = "2.3.2"
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
# button
|
|
||||||
|
|
||||||
This repository contains code for solving the challenges from [button.qedaka.de](button.qedaka.de). There are eight
|
|
||||||
challenges in total:
|
|
||||||
- [01_welcome](./js/01_welcome.js)
|
|
||||||
- [02_these_numbers_are_big](./js/02_these_numbers_are_big.js)
|
|
||||||
- [03_are_you_still_doing_this_by_hand](./js/03_are_you_still_doing_this_by_hand.js)
|
|
||||||
- [04_broken_proof_of_work](./js/04_broken_proof_of_work.js)
|
|
||||||
- [05_what_the_bf](./js/05_what_the_bf.js)
|
|
||||||
- [06_automation_is_not_enough](./js/06_automation_is_not_enough.js)
|
|
||||||
- [07_weird_assembly_machine](./js/07_weird_assembly_machine.js)
|
|
||||||
- [08_revisit_everything](./js/08_revisit_everything.js)
|
|
||||||
|
|
||||||
Challenges one through four are trivial to solve. For challenges five through eight there is one binary each which
|
|
||||||
demonstrates an approach to a solution.
|
|
||||||
|
|
||||||
One additional binary for solving the whole puzzle from start to finish is provided.
|
|
||||||
|
|
||||||
@@ -14,7 +14,6 @@ fn main() {
|
|||||||
println!("x = {x}");
|
println!("x = {x}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to find a cycle in [`f_n`] using Brent's algorithm.
|
|
||||||
fn main_cycle_detection() {
|
fn main_cycle_detection() {
|
||||||
compute_async(|tx| {
|
compute_async(|tx| {
|
||||||
// brent's algorithm
|
// brent's algorithm
|
||||||
@@ -70,19 +69,20 @@ fn main_cycle_detection() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// The deobfuscated function `f`
|
|
||||||
fn f(mut x: u128) -> u128 {
|
|
||||||
const A: u128 = 909_090_909_091u128; // (10 * b + 1) / 11
|
const A: u128 = 909_090_909_091u128; // (10 * b + 1) / 11
|
||||||
const B: u128 = 1_000_000_000_000u128; // 10^12
|
const B: u128 = 1_000_000_000_000u128; // 10^12
|
||||||
const C: u128 = 999_999_999_989u128; // b - 11
|
const C: u128 = 999_999_999_989u128; // b - 11
|
||||||
const D: u128 = 999_999_999_999u128; // b - 1
|
const D: u128 = 999_999_999_999u128; // b - 1
|
||||||
|
fn f(mut x: u128) -> u128 {
|
||||||
x = x * A % B;
|
x = x * A % B;
|
||||||
x = (x * C + D) / B;
|
x = (x * C + D) / B;
|
||||||
x
|
x
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes `f(f(...f(X0)...))` (where [`f`] is applied `n` times) using data produces by [`main_cycle_detection`]
|
|
||||||
|
const MU: u128 = 0;
|
||||||
|
const LAM: u128 = 249_999_999_997;
|
||||||
|
/// Computes `f(f(...f(X0)...))` where `f` is applied `n` times.
|
||||||
fn f_n(n: u128) -> u128 {
|
fn f_n(n: u128) -> u128 {
|
||||||
let n = n % LAM;
|
let n = n % LAM;
|
||||||
|
|
||||||
@@ -101,13 +101,6 @@ fn f_n(n: u128) -> u128 {
|
|||||||
value
|
value
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The offset of the cycle of [`f_n`] as returned by [`main_cycle_detection`].
|
|
||||||
const MU: u128 = 0;
|
|
||||||
|
|
||||||
/// The length of the cycle of [`f_n`] as returned by [`main_cycle_detection`].
|
|
||||||
const LAM: u128 = 249_999_999_997;
|
|
||||||
|
|
||||||
/// In- and output values of [`f_n`] as returned by [`main_cycle_detection`].
|
|
||||||
const F_DATA: &[(u128, u128)] = &[
|
const F_DATA: &[(u128, u128)] = &[
|
||||||
(11538000000, 540610237213),
|
(11538000000, 540610237213),
|
||||||
(11539000000, 525319061659),
|
(11539000000, 525319061659),
|
||||||
|
|||||||
@@ -3,34 +3,38 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufRead, BufReader};
|
use std::io::{BufRead, BufReader};
|
||||||
|
use lazy_static::lazy_static;
|
||||||
use rug::ops::MulFrom;
|
use rug::ops::MulFrom;
|
||||||
use rug::{Assign, Integer};
|
use rug::{Assign, Integer};
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::LazyLock;
|
|
||||||
use lib::submit;
|
use lib::submit;
|
||||||
|
|
||||||
static N0: LazyLock<Integer> = LazyLock::new(|| Integer::from(1001997000002u128));
|
lazy_static!(
|
||||||
static X0: LazyLock<Integer> = LazyLock::new(|| Integer::from_str("13361120425250501347832030920224855036595311511513374827901659942687569213067904382419070310529480239935839308518100143939024253857202176158254361885679515473530816156355117821922648901555956036125537445852483998567339002752976575910942962150").unwrap());
|
static ref N0: Integer = Integer::from(1001997000002u128);
|
||||||
|
static ref X0: Integer = Integer::from_str("13361120425250501347832030920224855036595311511513374827901659942687569213067904382419070310529480239935839308518100143939024253857202176158254361885679515473530816156355117821922648901555956036125537445852483998567339002752976575910942962150").unwrap();
|
||||||
|
|
||||||
static N1: LazyLock<Integer> = LazyLock::new(|| Integer::from(1774734677598263u128));
|
static ref N1: Integer = Integer::from(1774734677598263u128);
|
||||||
static X1: LazyLock<Integer> = LazyLock::new(|| Integer::from_str("11593323295292067533341930289979269834079920106030434522240627836294015987043679078861672344892723053626369715841527508395668434915559610809835295347647318767117730544084796074700752732601302352244011354650441946234192592199510139121367920997").unwrap());
|
static ref X1: Integer = Integer::from_str("11593323295292067533341930289979269834079920106030434522240627836294015987043679078861672344892723053626369715841527508395668434915559610809835295347647318767117730544084796074700752732601302352244011354650441946234192592199510139121367920997").unwrap();
|
||||||
|
|
||||||
static M: LazyLock<Integer> = LazyLock::new(|| Integer::from_str("14004392365098131090160062970945115111185775413941111064876648140973294115502980816410773368597517292734034227298996122159833675150497554142801209096513652073059992938078366061434391648276904643753267405058183481162693381822800709938988762923").unwrap());
|
static ref N2: Integer = Integer::from(10000000000000000u128);
|
||||||
static E: LazyLock<Integer> = LazyLock::new(|| Integer::from(65537));
|
static ref X2: Integer = Integer::from_str("12451812012967875768280645960359102621677777894853024330321329610110355503343897740935595925071894025774585740051400274576363979250507927352038651542641174781860822343081975931661658111525566916416897092390763978119448659635732847002032508677").unwrap();
|
||||||
|
|
||||||
static A: LazyLock<Integer> = LazyLock::new(|| Integer::from_str("1466928606874115117499939299261").unwrap());
|
static ref M: Integer = Integer::from_str("14004392365098131090160062970945115111185775413941111064876648140973294115502980816410773368597517292734034227298996122159833675150497554142801209096513652073059992938078366061434391648276904643753267405058183481162693381822800709938988762923").unwrap();
|
||||||
static B: LazyLock<Integer> = LazyLock::new(|| Integer::from_str("49119078231137394008451554322").unwrap());
|
static ref E: Integer = Integer::from(65537);
|
||||||
|
|
||||||
|
static ref A: Integer = Integer::from_str("1466928606874115117499939299261").unwrap();
|
||||||
|
static ref B: Integer = Integer::from_str("49119078231137394008451554322").unwrap();
|
||||||
|
);
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let f = faulhaber_formula_from_file("res/06_faulhaber_coefficient_65537.log").unwrap();
|
let f = faulhaber_equation_from_file("res/06_faulhaber_coefficient_65537.log").unwrap();
|
||||||
|
|
||||||
let n: Integer = Integer::from(10000000000000000u128);
|
let n: Integer = Integer::from(10000000000000000u128);
|
||||||
let x = (X1.clone() + f(n.clone()) - f(N1.clone())).modulo(&M);
|
let x = (X1.clone() + f(n.clone()) - f(N1.clone())).modulo(&M);
|
||||||
println!("{:?}", x);
|
println!("{:?}", x);
|
||||||
println!("{:?}", submit(n, x).unwrap());
|
println!("{:?}", submit(n, x).unwrap());
|
||||||
|
|
||||||
// Use the submission server as an oracle to find the `n` at which `x` needs to be doubles.
|
|
||||||
// let (mut low, mut high) = (
|
// let (mut low, mut high) = (
|
||||||
// Integer::from(1774734677598262u128),
|
// Integer::from(1774734677598262u128),
|
||||||
// Integer::from(1774734677598263u128),
|
// Integer::from(1774734677598263u128),
|
||||||
@@ -51,17 +55,19 @@ fn main() {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes one step of the challenge.
|
fn step(mut n: Integer, mut x: Integer, mut temp1: Integer, mut temp2: Integer) -> (Integer, Integer, Integer, Integer) {
|
||||||
fn step(mut n: Integer, mut x: Integer) -> (Integer, Integer) {
|
|
||||||
n += 1;
|
n += 1;
|
||||||
|
|
||||||
let b: &Integer = &B;
|
let b: &Integer = &B;
|
||||||
|
|
||||||
// a = pow(n, e, m)
|
// a = pow(n, e, m)
|
||||||
let a = n.clone().pow_mod(&E, &M).unwrap();
|
temp1.assign(&n);
|
||||||
|
let a = temp1.pow_mod(&E, &M).unwrap();
|
||||||
|
|
||||||
// if (a % A == b) {
|
// if (a % A == b) {
|
||||||
if a.clone().modulo(&A).eq(b) {
|
temp2.assign(&a);
|
||||||
|
let c = temp2.modulo(&A);
|
||||||
|
if c.eq(b) {
|
||||||
// x += x
|
// x += x
|
||||||
x *= 2;
|
x *= 2;
|
||||||
}
|
}
|
||||||
@@ -70,18 +76,19 @@ fn step(mut n: Integer, mut x: Integer) -> (Integer, Integer) {
|
|||||||
// x %= m
|
// x %= m
|
||||||
x = x.add(&a).modulo(&M);
|
x = x.add(&a).modulo(&M);
|
||||||
|
|
||||||
(n, x)
|
(n, x, a, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn faulhaber_formula(n: usize) -> impl Fn(Integer) -> Integer {
|
|
||||||
|
fn faulhaber_equation(n: usize) -> impl Fn(Integer) -> Integer {
|
||||||
let coefficients = faulhaber_triangle(n);
|
let coefficients = faulhaber_triangle(n);
|
||||||
for (i, coeff) in coefficients.iter().enumerate() {
|
for (i, coeff) in coefficients.iter().enumerate() {
|
||||||
println!("{i} = {coeff}");
|
println!("{i} = {coeff}");
|
||||||
}
|
}
|
||||||
faulhaber_formula_from_coefficients(coefficients)
|
faulhaber_equation_from_coefficients(coefficients)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn faulhaber_formula_from_file(path: &str) -> Result<impl Fn(Integer) -> Integer> {
|
fn faulhaber_equation_from_file(path: &str) -> Result<impl Fn(Integer) -> Integer> {
|
||||||
let mut coefficients = Vec::new();
|
let mut coefficients = Vec::new();
|
||||||
|
|
||||||
let file = File::open(path)?;
|
let file = File::open(path)?;
|
||||||
@@ -96,10 +103,10 @@ fn faulhaber_formula_from_file(path: &str) -> Result<impl Fn(Integer) -> Integer
|
|||||||
sum.modulo_mut(&M);
|
sum.modulo_mut(&M);
|
||||||
println!("{:?}", sum);
|
println!("{:?}", sum);
|
||||||
|
|
||||||
Ok(faulhaber_formula_from_coefficients(coefficients))
|
Ok(faulhaber_equation_from_coefficients(coefficients))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn faulhaber_formula_from_coefficients(coefficients: Vec<Integer>) -> impl Fn(Integer) -> Integer {
|
fn faulhaber_equation_from_coefficients(coefficients: Vec<Integer>) -> impl Fn(Integer) -> Integer {
|
||||||
move |x| {
|
move |x| {
|
||||||
let mut result = Integer::from(0);
|
let mut result = Integer::from(0);
|
||||||
let mut temp = Integer::from(0);
|
let mut temp = Integer::from(0);
|
||||||
@@ -120,7 +127,6 @@ fn faulhaber_formula_from_coefficients(coefficients: Vec<Integer>) -> impl Fn(In
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the coefficients of the Faulhaber's formula.
|
|
||||||
fn faulhaber_triangle(n: usize) -> Vec<Integer> {
|
fn faulhaber_triangle(n: usize) -> Vec<Integer> {
|
||||||
let neg1 = Integer::from(-1);
|
let neg1 = Integer::from(-1);
|
||||||
let mut inv = Vec::with_capacity(n + 10);
|
let mut inv = Vec::with_capacity(n + 10);
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
use lib::submit;
|
use lib::submit;
|
||||||
use lib::challenges::c7_weird_assembly_machine::h_n;
|
use lib::challenges::c7_weird_assembly_machine::f_n;
|
||||||
|
|
||||||
const N: u64 = 979607657800000055;
|
const N: u64 = 979607657800000055;
|
||||||
const X: u64 = 10962444957429324784;
|
const X: u64 = 10962444957429324784;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let (n, x) = h_n(N, X, 1_000_000_000_000_000_000u64 - N);
|
let (n, x) = f_n(N, X, 1_000_000_000_000_000_000u64 - N);
|
||||||
println!("n = {n}");
|
println!("n = {n}");
|
||||||
println!("x = {x}");
|
println!("x = {x}");
|
||||||
submit(n, x).unwrap();
|
submit(n, x).unwrap();
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
#![allow(dead_code)]
|
#![allow(dead_code)]
|
||||||
use std::sync::LazyLock;
|
// You can change the color of your name without changing your name.
|
||||||
|
|
||||||
|
use lazy_static::lazy_static;
|
||||||
use lib::submit_with_name;
|
use lib::submit_with_name;
|
||||||
use rug::ops::DivRounding;
|
use rug::ops::{DivRounding, Pow};
|
||||||
use rug::Integer;
|
use rug::Integer;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
|
||||||
// You can change the color of your name without changing your name.
|
lazy_static!(
|
||||||
static M: LazyLock<Vec<Integer>> = LazyLock::new(|| vec![
|
static ref M: Vec<Integer> = vec![
|
||||||
Integer::from_str("1434008120931012805118743381511953470053626771934922366720474361817092344508461315782084314493561729943207476618986862630642339876124303277669871276872966561372584096756184146218943438497504108129008248947186295903702650936563195517405177267").unwrap(),
|
Integer::from_str("1434008120931012805118743381511953470053626771934922366720474361817092344508461315782084314493561729943207476618986862630642339876124303277669871276872966561372584096756184146218943438497504108129008248947186295903702650936563195517405177267").unwrap(),
|
||||||
Integer::from_str("2279983661166952569412337967792106681853682761140508555222469060830820310854240357968620360297575902950280777825697828457195462861233847516393870602678279643129330544204145040751369969379909048248974150190225328726111083312867874886821021103").unwrap(),
|
Integer::from_str("2279983661166952569412337967792106681853682761140508555222469060830820310854240357968620360297575902950280777825697828457195462861233847516393870602678279643129330544204145040751369969379909048248974150190225328726111083312867874886821021103").unwrap(),
|
||||||
Integer::from_str("2403618920217682814630057320815015451780244245370783386150600183266752801851444036459202928614238339117073052233115617730895326577436837775969446809467396763885076993639257102975158794586432834588823770619549927566204909745661463923650207527").unwrap(),
|
Integer::from_str("2403618920217682814630057320815015451780244245370783386150600183266752801851444036459202928614238339117073052233115617730895326577436837775969446809467396763885076993639257102975158794586432834588823770619549927566204909745661463923650207527").unwrap(),
|
||||||
@@ -49,16 +51,16 @@ static M: LazyLock<Vec<Integer>> = LazyLock::new(|| vec![
|
|||||||
Integer::from_str("2861034394438211841574954026003099819138101239247590122220350015475642835378420417008259980687528330087930738069620032709655292858712710050922359392413494086067180601383341612168193292772028605966992134213209023470256124404157207490432001519").unwrap(),
|
Integer::from_str("2861034394438211841574954026003099819138101239247590122220350015475642835378420417008259980687528330087930738069620032709655292858712710050922359392413494086067180601383341612168193292772028605966992134213209023470256124404157207490432001519").unwrap(),
|
||||||
Integer::from_str("2192496740130688243467014868961425982524426805724142867736885035473886629020046845749143690992453345556925544037271383038390660805714030629830845497904446979103911346917405936472233104694103049940390437540539269358666128436739707024829933171").unwrap(),
|
Integer::from_str("2192496740130688243467014868961425982524426805724142867736885035473886629020046845749143690992453345556925544037271383038390660805714030629830845497904446979103911346917405936472233104694103049940390437540539269358666128436739707024829933171").unwrap(),
|
||||||
Integer::from_str("4729254672091433598483706976591610165407510022326154887172965802144851945337220063633854456109688411742113721031379206359782182729020553179365019549633309936476652959201812418790254033614677768930428905990768941807243900642422321011756634063").unwrap(),
|
Integer::from_str("4729254672091433598483706976591610165407510022326154887172965802144851945337220063633854456109688411742113721031379206359782182729020553179365019549633309936476652959201812418790254033614677768930428905990768941807243900642422321011756634063").unwrap(),
|
||||||
]);
|
];
|
||||||
|
|
||||||
static E: LazyLock<Integer> = LazyLock::new(|| Integer::from(65537));
|
static ref E: Integer = Integer::from(65537);
|
||||||
|
static ref E_100: Integer = Integer::from(65537).pow(100);
|
||||||
|
static ref E_1000: Integer = Integer::from(65537).pow(1000);
|
||||||
|
|
||||||
/// the first prime factor of [`M[30]`](M)
|
static ref P: Integer = Integer::from_str("2134638905903015345595412931439525422327695207079839833349799642610037970639957457078422305821013930668706217301787851463").unwrap();
|
||||||
static P: LazyLock<Integer> = LazyLock::new(|| Integer::from_str("2134638905903015345595412931439525422327695207079839833349799642610037970639957457078422305821013930668706217301787851463").unwrap());
|
static ref Q: Integer = Integer::from_str("2134638905903015345595412931439525422327695207079839833349799642610037970639957457078422305821013930668706217301787851473").unwrap();
|
||||||
/// the second prime factor of [`M[30]`](M)
|
static ref PHI: Integer = Integer::from_str("4556683258594822402855414380362620295231673046713752880933967889771646856051745784462468117575177892006513392693685616565666555545842363207724851343853529903674824524238732001458342230627654145983386115997227846421784693186847971068054052064").unwrap();
|
||||||
static Q: LazyLock<Integer> = LazyLock::new(|| Integer::from_str("2134638905903015345595412931439525422327695207079839833349799642610037970639957457078422305821013930668706217301787851473").unwrap());
|
);
|
||||||
/// [`φ(M[30])`](M) where `φ` is Euler's totient function
|
|
||||||
static PHI: LazyLock<Integer> = LazyLock::new(|| Integer::from_str("4556683258594822402855414380362620295231673046713752880933967889771646856051745784462468117575177892006513392693685616565666555545842363207724851343853529903674824524238732001458342230627654145983386115997227846421784693186847971068054052064").unwrap());
|
|
||||||
|
|
||||||
const LIMIT: u128 = 100_000_000_000_000_000_000;
|
const LIMIT: u128 = 100_000_000_000_000_000_000;
|
||||||
const NAME: &str = " Jonah";
|
const NAME: &str = " Jonah";
|
||||||
@@ -66,8 +68,8 @@ const N: u128 = 1000000000000000000;
|
|||||||
const X: &str = "3595876711108608978";
|
const X: &str = "3595876711108608978";
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
debug_assert_eq!(M[30].clone(), P.clone() * Q.clone());
|
assert_eq!(M[30].clone(), P.clone() * Q.clone());
|
||||||
debug_assert_eq!(PHI.clone(), (P.clone() - 1) * (Q.clone() - 1));
|
assert_eq!(PHI.clone(), (P.clone() - 1) * (Q.clone() - 1));
|
||||||
|
|
||||||
let truth = Integer::from(42);
|
let truth = Integer::from(42);
|
||||||
let k = Integer::from(LIMIT - N) * 100;
|
let k = Integer::from(LIMIT - N) * 100;
|
||||||
|
|||||||
+1
-1
@@ -9,8 +9,8 @@ fn main() -> ExitCode {
|
|||||||
eprintln!("Usage: main NAME");
|
eprintln!("Usage: main NAME");
|
||||||
return ExitCode::FAILURE;
|
return ExitCode::FAILURE;
|
||||||
}
|
}
|
||||||
let mut name = args[1].clone();
|
|
||||||
|
|
||||||
|
let mut name = args[1].clone();
|
||||||
loop {
|
loop {
|
||||||
println!("\nAttempting to solve for \"{}\"", &name);
|
println!("\nAttempting to solve for \"{}\"", &name);
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
use std::sync::LazyLock;
|
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
use rug::Integer;
|
use rug::Integer;
|
||||||
use rug::integer::Order;
|
use rug::integer::Order;
|
||||||
use sha2::{Sha256, Digest};
|
use sha2::{Sha256, Digest};
|
||||||
|
|
||||||
static M: LazyLock<Integer> = LazyLock::new(|| Integer::from_str("14004392365098131090160062970945115111185775413941111064876648140973294115502980816410773368597517292734034227298996122159833675150497554142801209096513652073059992938078366061434391648276904643753267405058183481162693381822800709938988762923").unwrap());
|
lazy_static!(
|
||||||
static E: LazyLock<Integer> = LazyLock::new(|| Integer::from(65537));
|
static ref M: Integer = Integer::from_str("14004392365098131090160062970945115111185775413941111064876648140973294115502980816410773368597517292734034227298996122159833675150497554142801209096513652073059992938078366061434391648276904643753267405058183481162693381822800709938988762923").unwrap();
|
||||||
|
static ref E: Integer = Integer::from(65537);
|
||||||
|
);
|
||||||
|
|
||||||
pub fn solve(name: &str) -> (u64, Integer) {
|
pub fn solve(name: &str) -> (u64, Integer) {
|
||||||
let mut x = sha256(name);
|
let mut x = sha256(name);
|
||||||
|
|||||||
@@ -1,44 +1,24 @@
|
|||||||
|
use lazy_static::lazy_static;
|
||||||
use rug::Integer;
|
use rug::Integer;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::io::{stdout, Write};
|
||||||
use std::io::Write;
|
|
||||||
use std::sync::LazyLock;
|
|
||||||
use tqdm::tqdm;
|
use tqdm::tqdm;
|
||||||
|
|
||||||
/// the base of the discrete logarithm
|
|
||||||
const G: u64 = 42;
|
|
||||||
/// the stride value of the Baby-Step-Giant-Step algorithm, controlling the space-time-tradeoff
|
|
||||||
const S: u64 = 5341666;
|
|
||||||
/// the modul of the discrete logarithm
|
|
||||||
const P: u64 = 12345679943u64;
|
const P: u64 = 12345679943u64;
|
||||||
|
|
||||||
/// the precomputed baby steps
|
lazy_static!(
|
||||||
static BABY_STEPS: LazyLock<Vec<u64>> = LazyLock::new(|| {
|
static ref BABY_STEPS: Vec<u64> = std::fs::read("res/03_baby_steps.bin").unwrap()
|
||||||
let path = "res/03_baby_steps.bin";
|
|
||||||
if !std::fs::exists(path).unwrap() {
|
|
||||||
precompute_baby_steps(G, P, S, &mut File::create(path).unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::fs::read(path).unwrap()
|
|
||||||
.chunks_exact(8)
|
.chunks_exact(8)
|
||||||
.map(|chunk| u64::from_be_bytes(chunk.try_into().unwrap()))
|
.map(|chunk| u64::from_be_bytes(chunk.try_into().unwrap()))
|
||||||
.collect()
|
.collect();
|
||||||
});
|
|
||||||
|
|
||||||
/// the precomputed giant steps
|
static ref GIANT_STEPS: HashMap<u64, usize> = std::fs::read("res/03_giant_steps.bin").unwrap()
|
||||||
static GIANT_STEPS: LazyLock<HashMap<u64, usize>> = LazyLock::new(|| {
|
|
||||||
let path = "res/03_giant_steps.bin";
|
|
||||||
if !std::fs::exists(path).unwrap() {
|
|
||||||
precompute_giant_steps(G, P, S, &mut File::create(path).unwrap());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::fs::read(path).unwrap()
|
|
||||||
.chunks_exact(8)
|
.chunks_exact(8)
|
||||||
.map(|chunk| u64::from_be_bytes(chunk.try_into().unwrap()))
|
.map(|chunk| u64::from_be_bytes(chunk.try_into().unwrap()))
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map(|(idx, step)| (step, idx))
|
.map(|(idx, step)| (step, idx))
|
||||||
.collect()
|
.collect();
|
||||||
});
|
);
|
||||||
|
|
||||||
pub fn solve(n: u64, x: Integer) -> (u64, Integer) {
|
pub fn solve(n: u64, x: Integer) -> (u64, Integer) {
|
||||||
let x = x.modulo(&Integer::from(P - 1)).to_u64().unwrap();
|
let x = x.modulo(&Integer::from(P - 1)).to_u64().unwrap();
|
||||||
@@ -53,8 +33,6 @@ pub fn solve(n: u64, x: Integer) -> (u64, Integer) {
|
|||||||
(n, Integer::from(x))
|
(n, Integer::from(x))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Quickly computes the discrete logarithm of `b` to the base [`G`] modulo [`M`] using the Baby-Step-Giant-Step
|
|
||||||
/// algorithm with precomputed steps
|
|
||||||
fn log42_mod_p(b: u64) -> Option<u64> {
|
fn log42_mod_p(b: u64) -> Option<u64> {
|
||||||
if b % P == 1 {
|
if b % P == 1 {
|
||||||
return Some(0);
|
return Some(0);
|
||||||
@@ -73,33 +51,36 @@ fn log42_mod_p(b: u64) -> Option<u64> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Precomputes the giant steps for use in the Baby-Step-Giant-Step algorithm for a fixed base `g` and modul `m` using a
|
pub fn precompute() {
|
||||||
/// stride of `s`.
|
let g = 42u64;
|
||||||
fn precompute_giant_steps(g: u64, m: u64, s: u64, out: &mut impl Write) {
|
let m = P;
|
||||||
|
let s = 5341666;
|
||||||
|
precompute_giant_steps(g, m, s);
|
||||||
|
precompute_baby_steps(g, m, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn precompute_giant_steps(g: u64, m: u64, s: u64) {
|
||||||
let g = g as u128;
|
let g = g as u128;
|
||||||
let m = m as u128;
|
let m = m as u128;
|
||||||
let mut a = 1u128;
|
let mut a = 1u128;
|
||||||
for _ in tqdm(0..s) {
|
for _ in tqdm(0..s) {
|
||||||
out.write_all(&(a as u64).to_be_bytes()).unwrap();
|
stdout().write_all(&(a as u64).to_be_bytes()).unwrap();
|
||||||
a *= g;
|
a *= g;
|
||||||
a %= m;
|
a %= m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Precomputes the baby steps for use in the Baby-Step-Giant-Step algorithm for a fixed base `g` and modul `m` using a
|
fn precompute_baby_steps(g: u64, m: u64, s: u64) {
|
||||||
/// stride of `s`.
|
|
||||||
fn precompute_baby_steps(g: u64, m: u64, s: u64, out: &mut impl Write) {
|
|
||||||
let gs = pow(g, s, m) as u128;
|
let gs = pow(g, s, m) as u128;
|
||||||
let m= m as u128;
|
let m= m as u128;
|
||||||
let mut a = gs;
|
let mut a = gs;
|
||||||
for _ in tqdm(1..=(m as u64 / s + 1)) {
|
for _ in tqdm(1..=(m as u64 / s + 1)) {
|
||||||
out.write_all(&(a as u64).to_be_bytes()).unwrap();
|
stdout().write_all(&(a as u64).to_be_bytes()).unwrap();
|
||||||
a *= gs;
|
a *= gs;
|
||||||
a %= m;
|
a %= m;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the discrete logarithm of `b` to the base `g` modulo `m` using the Baby-Step-Giant-Step algorithm.
|
|
||||||
fn log(g: u64, b: u64, m: u64) -> Option<u64> {
|
fn log(g: u64, b: u64, m: u64) -> Option<u64> {
|
||||||
let g: u128 = g as u128;
|
let g: u128 = g as u128;
|
||||||
let b: u128 = b as u128;
|
let b: u128 = b as u128;
|
||||||
@@ -133,7 +114,6 @@ fn log(g: u64, b: u64, m: u64) -> Option<u64> {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the `k`-th power of `a` modulo `m`.
|
|
||||||
fn pow(a: u64, mut k: u64, m: u64) -> u64 {
|
fn pow(a: u64, mut k: u64, m: u64) -> u64 {
|
||||||
let mut a: u128 = a as u128;
|
let mut a: u128 = a as u128;
|
||||||
let m: u128 = m as u128;
|
let m: u128 = m as u128;
|
||||||
|
|||||||
@@ -21,12 +21,12 @@ pub fn solve(n: u64, x: Integer) -> (u64, Integer) {
|
|||||||
(LIMIT, x * b % &M)
|
(LIMIT, x * b % &M)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn f(mut x: u128) -> u128 {
|
|
||||||
const A: u128 = 909_090_909_091u128; // (10 * b + 1) / 11
|
const A: u128 = 909_090_909_091u128; // (10 * b + 1) / 11
|
||||||
const B: u128 = 1_000_000_000_000u128; // 10^12
|
const B: u128 = 1_000_000_000_000u128; // 10^12
|
||||||
const C: u128 = 999_999_999_989u128; // b - 11
|
const C: u128 = 999_999_999_989u128; // b - 11
|
||||||
const D: u128 = 999_999_999_999u128; // b - 1
|
const D: u128 = 999_999_999_999u128; // b - 1
|
||||||
|
fn f(mut x: u128) -> u128 {
|
||||||
x = x * A % B;
|
x = x * A % B;
|
||||||
x = (x * C + D) / B;
|
x = (x * C + D) / B;
|
||||||
x
|
x
|
||||||
|
|||||||
@@ -1,21 +1,26 @@
|
|||||||
|
use lazy_static::lazy_static;
|
||||||
use rug::Integer;
|
use rug::Integer;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::LazyLock;
|
|
||||||
|
|
||||||
const START: u64 = 1_000_000_000_000u64;
|
const START: u64 = 1_000_000_000_000u64;
|
||||||
const LIMIT: u64 = 10_000_000_000_000_000u64;
|
const LIMIT: u64 = 10_000_000_000_000_000u64;
|
||||||
|
|
||||||
static M: LazyLock<Integer> = LazyLock::new(|| Integer::from_str("14004392365098131090160062970945115111185775413941111064876648140973294115502980816410773368597517292734034227298996122159833675150497554142801209096513652073059992938078366061434391648276904643753267405058183481162693381822800709938988762923").unwrap());
|
lazy_static!(
|
||||||
static A: LazyLock<Integer> = LazyLock::new(|| Integer::from_str("10729297455904899337681752672816753703351288544833760635567859176397566160330812285369370751389224534974913042757043771146367160829669925123791471756026119030734890865062863499420767799283504416995775836275660636668989077836006690621539265605").unwrap());
|
static ref M: Integer = Integer::from_str("14004392365098131090160062970945115111185775413941111064876648140973294115502980816410773368597517292734034227298996122159833675150497554142801209096513652073059992938078366061434391648276904643753267405058183481162693381822800709938988762923").unwrap();
|
||||||
static B: LazyLock<Integer> = LazyLock::new(|| Integer::from_str("4997609466256208183077203585670710326160976219126614124062259398288517298185253986607627790890962248558793881836308854443463332741665631247256917127102588793451033551034614994254514161235462726178612824897626185944163885786520174491419225456").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) {
|
pub fn solve(n: u64, x: Integer) -> (u64, Integer) {
|
||||||
assert_eq!(n, START);
|
assert_eq!(n, START);
|
||||||
|
let m: &Integer = &M;
|
||||||
|
let a: &Integer = &A;
|
||||||
|
let b: &Integer = &B;
|
||||||
|
|
||||||
let mut x = x;
|
let mut x = x;
|
||||||
x = (x + &*A) % &*M;
|
x = (x + a) % m;
|
||||||
x = x * 2 % &*M;
|
x = x * 2 % m;
|
||||||
x = (x + &*B) % &*M;
|
x = (x + b) % m;
|
||||||
|
|
||||||
(LIMIT, x)
|
(LIMIT, x)
|
||||||
}
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufRead, BufReader};
|
use std::io::{BufRead, BufReader};
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::LazyLock;
|
use lazy_static::lazy_static;
|
||||||
use rug::Integer;
|
use rug::Integer;
|
||||||
|
|
||||||
static DATA: LazyLock<Vec<u64>> = LazyLock::new(|| {
|
lazy_static!(
|
||||||
|
static ref DATA: Vec<u64> = {
|
||||||
let file = File::open("./res/07_weird_assembly_machine.data");
|
let file = File::open("./res/07_weird_assembly_machine.data");
|
||||||
let lines = BufReader::new(file.unwrap()).lines();
|
let lines = BufReader::new(file.unwrap()).lines();
|
||||||
|
|
||||||
@@ -13,21 +14,19 @@ static DATA: LazyLock<Vec<u64>> = LazyLock::new(|| {
|
|||||||
data.push(u64::from_str(&line.unwrap()).unwrap());
|
data.push(u64::from_str(&line.unwrap()).unwrap());
|
||||||
}
|
}
|
||||||
data
|
data
|
||||||
});
|
};
|
||||||
|
);
|
||||||
|
|
||||||
const LIMIT: u64 = 1_000_000_000_000_000_000u64;
|
const LIMIT: u64 = 1_000_000_000_000_000_000u64;
|
||||||
|
|
||||||
pub fn solve(n: u64, x: Integer) -> (u64, Integer) {
|
pub fn solve(n: u64, x: Integer) -> (u64, Integer) {
|
||||||
let x = x.to_u64_wrapping();
|
let x = x.to_u64_wrapping();
|
||||||
let (n, x) = h_n(n, x, LIMIT - n);
|
let (n, x) = f_n(n, x, LIMIT - n);
|
||||||
(n, Integer::from(x))
|
(n, Integer::from(x))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn h(x: u64, n: u64) -> u64 {
|
|
||||||
g(sub(f(x), n))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn h_n(mut n: u64, mut x: u64, k: u64) -> (u64, u64) {
|
pub fn f_n(mut n: u64, mut x: u64, k: u64) -> (u64, u64) {
|
||||||
n += 1;
|
n += 1;
|
||||||
x = sub(f(x), n);
|
x = sub(f(x), n);
|
||||||
|
|
||||||
@@ -46,28 +45,6 @@ pub fn h_n(mut n: u64, mut x: u64, k: u64) -> (u64, u64) {
|
|||||||
(n, x)
|
(n, x)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn f(x: u64) -> u64 {
|
|
||||||
evaluate(x, &DATA[..128])
|
|
||||||
}
|
|
||||||
|
|
||||||
fn g(x: u64) -> u64 {
|
|
||||||
evaluate(x, &DATA[128..])
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Quickly computes [`f`](f)([`g`](g)(x)).
|
|
||||||
fn fg(x: u64) -> u64 {
|
|
||||||
!x.rotate_left(17)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computes [`fg`](fg)(...[`fg`](fg)(x)...) where [`fg`] is applied `n` times.
|
|
||||||
fn fg_n(mut x: u64, n: u64) -> u64 {
|
|
||||||
for _ in 0..n%64 {
|
|
||||||
x = fg(x);
|
|
||||||
}
|
|
||||||
x
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computes the sum from `i = 1` to `k` over `fg^(k-i)(n + i)`.
|
|
||||||
fn fg_sum(n: u64, k: u64) -> u64 {
|
fn fg_sum(n: u64, k: u64) -> u64 {
|
||||||
let mut sum = 0u64;
|
let mut sum = 0u64;
|
||||||
for i in 1..=k {
|
for i in 1..=k {
|
||||||
@@ -76,7 +53,6 @@ fn fg_sum(n: u64, k: u64) -> u64 {
|
|||||||
sum
|
sum
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Quickly computes `fg_sum` when `k` is divisible by `192`.
|
|
||||||
fn fast_fg_sum(n: u64, k: u64) -> u64 {
|
fn fast_fg_sum(n: u64, k: u64) -> u64 {
|
||||||
debug_assert!(k % 192 == 0);
|
debug_assert!(k % 192 == 0);
|
||||||
let mut result = fg_sum(n, 0);
|
let mut result = fg_sum(n, 0);
|
||||||
@@ -84,13 +60,12 @@ fn fast_fg_sum(n: u64, k: u64) -> u64 {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Evaluates a polynomial over `GF(2)[X] / (X^64 + 1)`
|
fn f(x: u64) -> u64 {
|
||||||
fn evaluate(x: u64, data: &[u64]) -> u64 {
|
evaluate(x, &DATA[..128], &DATA[..128])
|
||||||
let mut out = 0;
|
|
||||||
for i in 0..data.len() {
|
|
||||||
out = xor_mul(out, x) ^ data[i];
|
|
||||||
}
|
}
|
||||||
out
|
|
||||||
|
fn g(x: u64) -> u64 {
|
||||||
|
evaluate(x, &DATA[128..], &DATA[128..])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add(a: u64, b: u64) -> u64 {
|
fn add(a: u64, b: u64) -> u64 {
|
||||||
@@ -105,6 +80,27 @@ fn sub(x: u64, mut n: u64) -> u64 {
|
|||||||
x.wrapping_sub(n)
|
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")))]
|
#[cfg(not(all(target_arch = "x86_64", target_feature = "pclmulqdq")))]
|
||||||
fn xor_mul(a: u64, mut b: u64) -> u64 {
|
fn xor_mul(a: u64, mut b: u64) -> u64 {
|
||||||
let mut x: u64 = 0;
|
let mut x: u64 = 0;
|
||||||
|
|||||||
@@ -1,24 +1,26 @@
|
|||||||
use rug::ops::DivRounding;
|
use rug::ops::DivRounding;
|
||||||
use rug::Integer;
|
use rug::Integer;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::LazyLock;
|
|
||||||
|
|
||||||
static PHI: LazyLock<Integer> = LazyLock::new(|| Integer::from_str("4556683258594822402855414380362620295231673046713752880933967889771646856051745784462468117575177892006513392693685616565666555545842363207724851343853529903674824524238732001458342230627654145983386115997227846421784693186847971068054052064").unwrap());
|
const PHI: &str = "4556683258594822402855414380362620295231673046713752880933967889771646856051745784462468117575177892006513392693685616565666555545842363207724851343853529903674824524238732001458342230627654145983386115997227846421784693186847971068054052064";
|
||||||
static M: LazyLock<Integer> = LazyLock::new(|| Integer::from_str("4556683258594822402855414380362620295231673046713752880933967889771646856051745784462468117575177892006513392693685616569935833357648393898915677206732580748330214938398411668157941515847730087263301030154072458063812554524260405671629754999").unwrap());
|
const M: &str = "4556683258594822402855414380362620295231673046713752880933967889771646856051745784462468117575177892006513392693685616569935833357648393898915677206732580748330214938398411668157941515847730087263301030154072458063812554524260405671629754999";
|
||||||
static E: LazyLock<Integer> = LazyLock::new(|| Integer::from(65537));
|
const E: u64 = 65537;
|
||||||
static TRUTH: LazyLock<Integer> = LazyLock::new(|| Integer::from(42));
|
|
||||||
const LIMIT: u128 = 100_000_000_000_000_000_000;
|
const LIMIT: u128 = 100_000_000_000_000_000_000;
|
||||||
|
|
||||||
pub fn solve(n: u64, x: Integer) -> Result<(u128, Integer), u32> {
|
pub fn solve(n: u64, x: Integer) -> Result<(u128, Integer), u32> {
|
||||||
|
let truth = Integer::from(42);
|
||||||
|
let phi = Integer::from_str(PHI).unwrap();
|
||||||
|
let m = Integer::from_str(M).unwrap();
|
||||||
|
|
||||||
let k = Integer::from(LIMIT - n as u128) * 100;
|
let k = Integer::from(LIMIT - n as u128) * 100;
|
||||||
let e = E.clone().pow_mod(&k, &PHI).unwrap();
|
let e = Integer::from(E).pow_mod(&k, &phi).unwrap();
|
||||||
let w: u32 = x.clone().modulo(&TRUTH).try_into().unwrap();
|
let w: u32 = x.clone().modulo(&truth).try_into().unwrap();
|
||||||
if w != 30 {
|
if w != 30 {
|
||||||
return Err(w);
|
return Err(w);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut y = x.clone().div_floor(&*TRUTH);
|
let mut y = x.clone().div_floor(&truth);
|
||||||
y = y.pow_mod(&e, &M).unwrap();
|
y = y.pow_mod(&e, &m).unwrap();
|
||||||
|
|
||||||
let x: Integer = y * 42 + w;
|
let x: Integer = y * 42 + w;
|
||||||
Ok((LIMIT, x))
|
Ok((LIMIT, x))
|
||||||
|
|||||||
Reference in New Issue
Block a user