SPB Git

spb/wp34_uqo

Public
6.4 KB · 207 lines rust
1//! CLI: `rho_engine solve …` (one JSON object on stdout) and `rho_engine batch …` (JSON array).23use clap::{Args, Parser, Subcommand};4use rho_engine::SolveSpec;5use std::io::Write;67#[derive(Parser)]8#[command(name = "rho_engine", version, about = "Native ECDLP engine (BSGS / Pollard rho / kangaroo) for synthetic prime-order curves, p < 2^62")]9struct Cli {10    #[command(subcommand)]11    cmd: Cmd,12}1314#[derive(Subcommand)]15enum Cmd {16    /// Solve one instance Q = d·G and print a JSON result object17    Solve(SolveArgs),18    /// Run every job of a JSON array file sequentially and write a JSON array of results19    Batch {20        /// input file: JSON array of job objects (same keys as the `solve` flags, decimal strings)21        #[arg(long)]22        file: String,23        /// output file (JSON array); "-" for stdout24        #[arg(long, default_value = "-")]25        out: String,26        /// print progress lines on stderr27        #[arg(long)]28        verbose: bool,29    },30}3132#[derive(Args)]33struct SolveArgs {34    #[arg(long)]35    p: String,36    #[arg(long)]37    a: String,38    #[arg(long)]39    b: String,40    /// prime order of G41    #[arg(long)]42    n: String,43    #[arg(long)]44    gx: String,45    #[arg(long)]46    gy: String,47    #[arg(long)]48    qx: String,49    #[arg(long)]50    qy: String,51    /// bsgs | rho | kangaroo52    #[arg(long)]53    alg: String,54    #[arg(long, default_value_t = 1)]55    seed: u64,56    /// print JSON (always on; kept for compatibility)57    #[arg(long)]58    json: bool,59    /// optional label copied to the output60    #[arg(long)]61    label: Option<String>,62    /// optional known answer (adds "match")63    #[arg(long)]64    expected_d: Option<String>,65    /// rho: number of partitions of the r-adding walk66    #[arg(long, default_value_t = 20)]67    r: usize,68    /// rho: floyd | brent (single walk) | dp (van Oorschot–Wiener, default)69    #[arg(long)]70    cycle: Option<String>,71    /// rho/kangaroo: distinguished-point bits (default ⌊bits/4⌋ − 2, ≥ 1)72    #[arg(long)]73    dp: Option<u32>,74    #[arg(long, default_value_t = 1)]75    threads: usize,76    /// rho: walks per thread (default 128); kangaroo: kangaroos per thread (default automatic)77    #[arg(long)]78    walks: Option<usize>,79    /// rho: Teske mixed walk — every k-th partition is a doubling partition (0 = pure adding walk)80    #[arg(long, default_value_t = 0)]81    mixed: usize,82    /// rho: negation map (classes {P, −P})83    #[arg(long)]84    neg: bool,85    /// rho: order-3 automorphism classes (a = 0 curves; requires --beta and --lambda)86    #[arg(long)]87    aut3: bool,88    #[arg(long)]89    beta: Option<String>,90    #[arg(long)]91    lambda: Option<String>,92    /// rho: remember one point every K steps for fruitless-cycle detection93    #[arg(long, default_value_t = 32)]94    cycle_check: u64,95    /// rho (dp): abandon a walk after this many steps without a distinguished point96    #[arg(long)]97    max_walk_len: Option<u64>,98    /// kangaroo: interval lower bound (default 0)99    #[arg(long)]100    lo: Option<String>,101    /// kangaroo: interval upper bound (default n − 1)102    #[arg(long)]103    hi: Option<String>,104    /// bsgs: number of baby steps m (default ⌈√n⌉)105    #[arg(long)]106    memory: Option<String>,107    /// bsgs: chains per thread for batch inversion108    #[arg(long, default_value_t = 64)]109    chains: usize,110}111112impl From<SolveArgs> for SolveSpec {113    fn from(a: SolveArgs) -> SolveSpec {114        SolveSpec {115            p: a.p,116            a: a.a,117            b: a.b,118            n: a.n,119            gx: a.gx,120            gy: a.gy,121            qx: a.qx,122            qy: a.qy,123            alg: a.alg,124            seed: a.seed,125            label: a.label,126            expected_d: a.expected_d,127            r: a.r,128            cycle: a.cycle,129            dp: a.dp,130            threads: a.threads,131            walks: a.walks,132            mixed: a.mixed,133            neg: a.neg,134            aut3: a.aut3,135            beta: a.beta,136            lambda: a.lambda,137            cycle_check: a.cycle_check,138            max_walk_len: a.max_walk_len,139            lo: a.lo,140            hi: a.hi,141            memory: a.memory,142            chains: a.chains,143        }144    }145}146147fn main() {148    let cli = Cli::parse();149    match cli.cmd {150        Cmd::Solve(args) => {151            let spec: SolveSpec = args.into();152            let out = rho_engine::run(&spec);153            println!("{}", serde_json::to_string(&out).unwrap());154            if out.get("ok").and_then(|v| v.as_bool()) != Some(true) {155                std::process::exit(2);156            }157        }158        Cmd::Batch { file, out, verbose } => {159            let text = std::fs::read_to_string(&file).unwrap_or_else(|e| {160                eprintln!("cannot read {file}: {e}");161                std::process::exit(1)162            });163            let specs: Vec<SolveSpec> = serde_json::from_str(&text).unwrap_or_else(|e| {164                eprintln!("cannot parse {file}: {e}");165                std::process::exit(1)166            });167            let mut results = Vec::with_capacity(specs.len());168            let mut failures = 0usize;169            for (i, spec) in specs.iter().enumerate() {170                let res = rho_engine::run(spec);171                let ok = res.get("ok").and_then(|v| v.as_bool()) == Some(true);172                if !ok {173                    failures += 1;174                }175                if verbose {176                    eprintln!(177                        "[{}/{}] {} alg={} ok={} wall={:.3}s group_ops={}",178                        i + 1,179                        specs.len(),180                        spec.label.as_deref().unwrap_or("-"),181                        spec.alg,182                        ok,183                        res.get("wall_s").and_then(|v| v.as_f64()).unwrap_or(0.0),184                        res.get("group_ops").and_then(|v| v.as_u64()).unwrap_or(0)185                    );186                }187                results.push(res);188            }189            let text = serde_json::to_string_pretty(&results).unwrap();190            if out == "-" {191                println!("{text}");192            } else {193                let mut f = std::fs::File::create(&out).unwrap_or_else(|e| {194                    eprintln!("cannot write {out}: {e}");195                    std::process::exit(1)196                });197                f.write_all(text.as_bytes()).unwrap();198                f.write_all(b"\n").unwrap();199            }200            if failures > 0 {201                eprintln!("{failures} job(s) failed");202                std::process::exit(2);203            }204        }205    }206}207
Files · c732f7e320257301eb619a8227b914374a41aac4
Menu

Theme