improve performance of challenge 03 by precomputing giant steps

This commit is contained in:
2025-09-12 17:01:56 +02:00
parent 7f33c43169
commit 997efb0ad4
6 changed files with 69 additions and 5 deletions

BIN
res/03_baby_steps.bin Normal file

Binary file not shown.

BIN
res/03_giant_steps.bin Normal file

Binary file not shown.

View File

@@ -1,7 +1,7 @@
use lib::submit_with_name;
fn main() {
let name = "((ο)=>((o)=>o(((o(((ο*o([!+[]+!+";
let name = "Яана";
let (n, x) = lib::challenges::c1_welcome::solve();
println!("n = {:?}\nx = {:?}\n{:?}\n", n, x, submit_with_name(name, n, x));

View File

@@ -11,9 +11,8 @@ lazy_static!(
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..10_000 {
for _ in 0..100 {
x.pow_mod_mut(&E, &M).unwrap();
}

View File

@@ -1,22 +1,86 @@
use lazy_static::lazy_static;
use rug::Integer;
use std::collections::HashMap;
use std::io::{stdout, Write};
use tqdm::tqdm;
const P: u64 = 12345679943u64;
lazy_static!(
static ref BABY_STEPS: Vec<u64> = std::fs::read("res/03_baby_steps.bin").unwrap()
.chunks_exact(8)
.map(|chunk| u64::from_be_bytes(chunk.try_into().unwrap()))
.collect();
static ref GIANT_STEPS: HashMap<u64, usize> = std::fs::read("res/03_giant_steps.bin").unwrap()
.chunks_exact(8)
.map(|chunk| u64::from_be_bytes(chunk.try_into().unwrap()))
.enumerate()
.map(|(idx, step)| (step, idx))
.collect();
);
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) {
for _ in 0..10_000 {
n += 1;
x = log(42, 1 + (x + n) % (P - 1), P).unwrap();
x = log42_mod_p(1 + (x + n) % (P - 1)).unwrap();
}
(n, Integer::from(x))
}
fn log42_mod_p(b: u64) -> Option<u64> {
if b % P == 1 {
return Some(0);
}
let inv = pow(b, P - 2, P) as u128;
let s = GIANT_STEPS.len();
for j in 1..=BABY_STEPS.len() {
let baby_step = BABY_STEPS[j - 1] as u128;
let search = ((baby_step * inv) % P as u128) as u64;
if let Some(i) = GIANT_STEPS.get(&search) {
return Some((j * s - i) as u64);
}
}
None
}
pub fn precompute() {
let g = 42u64;
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 m = m as u128;
let mut a = 1u128;
for _ in tqdm(0..s) {
stdout().write_all(&(a as u64).to_be_bytes()).unwrap();
a *= g;
a %= m;
}
}
fn precompute_baby_steps(g: u64, m: u64, s: u64) {
let gs = pow(g, s, m) as u128;
let m= m as u128;
let mut a = gs;
for _ in tqdm(1..=(m as u64 / s + 1)) {
stdout().write_all(&(a as u64).to_be_bytes()).unwrap();
a *= gs;
a %= m;
}
}
fn log(g: u64, b: u64, m: u64) -> Option<u64> {
let g: u128 = g as u128;
let b: u128 = b as u128;

View File

@@ -1,3 +1,4 @@
#![allow(dead_code)]
use anyhow::{anyhow, Result};
use json::JsonValue;
use std::fmt::Display;