use quipu::api::Options;
use quipu::dictionaries::ascii94;
use quipu::hackerbot;
use quipu::kdf::KdfParams;
use quipu::lab::engine::{run, LabReport};
use quipu::lab::forge::ForgeAttack;
use quipu::lab::guard::all_defenses_intact;
use quipu::lab::leak::LeakAttack;
use quipu::lab::stream_attack::StreamAttack;
use quipu::pqsign;
#[cfg(feature = "slh")]
use quipu::lab::forge_triple::ForgeTripleAttack;
#[cfg(feature = "honey")]
use quipu::lab::honey_attack::HoneyAttack;
#[cfg(feature = "honey")]
use quipu::lab::honey_fuzz::HoneyFuzz;
fn scale() -> usize {
std::env::var("QUIPU_REDTEAM_SCALE")
.ok()
.and_then(|v| v.parse::<usize>().ok())
.filter(|&s| s >= 1)
.unwrap_or(1)
}
fn cheap() -> KdfParams {
KdfParams {
mem_kib: 64,
iterations: 1,
parallelism: 1,
}
}
struct Row {
name: &'static str,
kind: &'static str,
attempts: usize,
breaches: usize,
details: Vec<String>,
}
fn from_lab(r: &LabReport, kind: &'static str) -> Row {
Row {
name: r.name,
kind,
attempts: r.attempts,
breaches: r.breaches.len(),
details: r.breaches.clone(),
}
}
fn from_bot(r: &hackerbot::AttackReport, kind: &'static str) -> Row {
Row {
name: r.name,
kind,
attempts: r.attempts,
breaches: r.breaches,
details: Vec::new(),
}
}
fn main() {
println!("╔══════════════════════════════════════════════════════════════╗");
println!("║ QUIPU RED-TEAM · simulación integral de ataques ║");
println!("╚══════════════════════════════════════════════════════════════╝\n");
let k = scale();
let surfaces: Vec<&str> = ["leak", "forge", "stream", "tamper", "trunc", "unique", "sig-forge"]
.into_iter()
.chain(cfg!(feature = "slh").then_some("triple(slh)"))
.chain(cfg!(feature = "honey").then_some("honey"))
.chain(cfg!(feature = "honey").then_some("honey-fuzz"))
.collect();
println!("Superficies activas: {}", surfaces.join(" · "));
if k > 1 {
println!("Modo SOAK: presupuesto ×{k}");
}
println!();
let defenses = all_defenses_intact();
println!(
"[0] Defensas antihacker (ct_eq / is_sane / wipe): {}",
if defenses { "INTACTAS ✔" } else { "¡DEBILITADAS! ✘" }
);
println!();
let dict = ascii94();
let opts = Options {
pepper: b"",
kdf_params: cheap(),
codebook_id: 0,
};
let data = b"acta confidencial del red-team: el tesoro esta bajo el arbol viejo";
let (vk, sk) = pqsign::generate_keypair();
let mut rows: Vec<Row> = Vec::new();
rows.extend([
from_lab(&run(&mut LeakAttack::new(), 20_260_701, 128 * k), "adaptativo"),
from_lab(&run(&mut ForgeAttack::new(), 1337, 120 * k), "adaptativo"),
from_lab(&run(&mut StreamAttack::new(), 4242, 60 * k), "adaptativo"),
]);
#[cfg(feature = "slh")]
rows.push(from_lab(&run(&mut ForgeTripleAttack::new(), 7, 24 * k), "adaptativo·slh"));
#[cfg(feature = "honey")]
rows.push(from_lab(&run(&mut HoneyAttack::new(), 909_090, 60 * k), "adaptativo·honey"));
#[cfg(feature = "honey")]
rows.push(from_lab(&run(&mut HoneyFuzz::new(), 0xF0F0, 1000 * k), "fuzz·honey"));
rows.extend([
from_bot(&hackerbot::tamper_attack(data, "clave-roja", &dict, b"", &opts), "determinista"),
from_bot(&hackerbot::truncation_attack(data, "clave-roja", &dict, b"", &opts), "determinista"),
from_bot(&hackerbot::uniqueness_attack(data, "clave-roja", &dict, &opts, 64 * k), "determinista"),
from_bot(&hackerbot::forgery_attack(data, &sk, &vk, &dict, 8), "determinista"),
]);
println!(
"{:<20} {:<18} {:>9} {:>9}",
"ATAQUE", "TIPO", "INTENTOS", "BRECHAS"
);
println!("{}", "─".repeat(60));
let mut total_attempts = 0usize;
let mut total_breaches = 0usize;
for r in &rows {
let mark = if r.breaches == 0 { "✔" } else { "✘" };
println!(
"{:<20} {:<18} {:>9} {:>7} {}",
r.name, r.kind, r.attempts, r.breaches, mark
);
for d in &r.details {
println!(" !! BRECHA: {d}");
}
total_attempts += r.attempts;
total_breaches += r.breaches;
}
println!("{}", "─".repeat(60));
println!(
"{:<20} {:<18} {:>9} {:>7}",
"TOTAL",
format!("{} superficies", rows.len()),
total_attempts,
total_breaches
);
println!();
let clean = defenses && total_breaches == 0;
if clean {
println!(
"VEREDICTO: LIMPIO — {} intentos, 0 brechas, defensas intactas. ✅",
total_attempts
);
} else {
eprintln!("VEREDICTO: FALLO — {total_breaches} brecha(s) o defensa debilitada. ✘");
std::process::exit(1);
}
}