SPB Git

spb/wp34_uqo

Public
6.1 KB · 181 lines rust
1//! (b) Fixture instances generated by the Python reference (`scripts/gen_fixtures.py` → `src/wp34/ec.py`2//! + PARI/GP): 60 prime-order curves of 20–32 bits (10 of them j = 0 per size) with known d.3//! Every algorithm / option combination must recover d, and 1-thread runs must be deterministic.45use rho_engine::{run, SolveSpec};6use serde::Deserialize;7use std::path::PathBuf;89#[derive(Deserialize, Clone)]10struct Fx {11    label: String,12    j0: bool,13    p: String,14    a: String,15    b: String,16    n: String,17    gx: String,18    gy: String,19    qx: String,20    qy: String,21    d: String,22    #[serde(default)]23    beta: Option<String>,24    #[serde(default)]25    lambda: Option<String>,26}2728#[derive(Deserialize)]29struct Doc {30    instances: Vec<Fx>,31}3233fn fixture_path() -> PathBuf {34    let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR"));35    p.push("../../../tests/fixtures/ecdlp_instances.json");36    p37}3839fn load() -> Vec<Fx> {40    let text = std::fs::read_to_string(fixture_path()).expect("fixture tests/fixtures/ecdlp_instances.json (run scripts/gen_fixtures.py)");41    let doc: Doc = serde_json::from_str(&text).unwrap();42    assert!(doc.instances.len() >= 50);43    doc.instances44}4546fn spec(fx: &Fx, alg: &str, seed: u64) -> SolveSpec {47    SolveSpec {48        p: fx.p.clone(),49        a: fx.a.clone(),50        b: fx.b.clone(),51        n: fx.n.clone(),52        gx: fx.gx.clone(),53        gy: fx.gy.clone(),54        qx: fx.qx.clone(),55        qy: fx.qy.clone(),56        alg: alg.into(),57        seed,58        label: Some(fx.label.clone()),59        expected_d: Some(fx.d.clone()),60        r: 20,61        cycle: None,62        dp: None,63        threads: 1,64        walks: None,65        mixed: 0,66        neg: false,67        aut3: false,68        beta: fx.beta.clone(),69        lambda: fx.lambda.clone(),70        cycle_check: 32,71        max_walk_len: None,72        lo: None,73        hi: None,74        memory: None,75        chains: 64,76    }77}7879fn check(s: &SolveSpec, what: &str) -> serde_json::Value {80    let out = run(s);81    assert_eq!(out.get("ok").and_then(|v| v.as_bool()), Some(true), "{what}: {out}");82    assert_eq!(out.get("match").and_then(|v| v.as_bool()), Some(true), "{what}: {out}");83    assert_eq!(out["d"].as_str(), s.expected_d.as_deref(), "{what}");84    out85}8687#[test]88fn fixtures_every_algorithm_recovers_d() {89    let fxs = load();90    for fx in &fxs {91        let seed = 7;92        check(&spec(fx, "bsgs", seed), &format!("{} bsgs", fx.label));93        let mut s = spec(fx, "bsgs", seed);94        s.memory = Some("1000".into());95        s.threads = 2;96        check(&s, &format!("{} bsgs --memory 1000 --threads 2", fx.label));9798        let mut s = spec(fx, "rho", seed);99        s.cycle = Some("floyd".into());100        check(&s, &format!("{} rho floyd", fx.label));101        s.cycle = Some("brent".into());102        check(&s, &format!("{} rho brent", fx.label));103        s.cycle = Some("dp".into());104        check(&s, &format!("{} rho dp 1 thread", fx.label));105        s.threads = 4;106        check(&s, &format!("{} rho dp 4 threads", fx.label));107        let mut s = spec(fx, "rho", seed);108        s.neg = true;109        check(&s, &format!("{} rho neg", fx.label));110        s.cycle = Some("brent".into());111        check(&s, &format!("{} rho neg brent", fx.label));112        let mut s = spec(fx, "rho", seed);113        s.mixed = 4;114        check(&s, &format!("{} rho mixed 4", fx.label));115        if fx.j0 {116            let mut s = spec(fx, "rho", seed);117            s.aut3 = true;118            check(&s, &format!("{} rho aut3", fx.label));119            s.neg = true;120            check(&s, &format!("{} rho neg aut3", fx.label));121            s.cycle = Some("floyd".into());122            check(&s, &format!("{} rho neg aut3 floyd", fx.label));123            s.cycle = None;124            s.threads = 4;125            check(&s, &format!("{} rho neg aut3 4 threads", fx.label));126        }127        let s = spec(fx, "kangaroo", seed);128        check(&s, &format!("{} kangaroo [0, n)", fx.label));129        let mut s = spec(fx, "kangaroo", seed);130        s.threads = 4;131        check(&s, &format!("{} kangaroo 4 threads", fx.label));132        // tight interval around d133        let d: u64 = fx.d.parse().unwrap();134        let n: u64 = fx.n.parse().unwrap();135        let mut s = spec(fx, "kangaroo", seed);136        s.lo = Some(d.saturating_sub(50_000).to_string());137        s.hi = Some((d + 50_000).min(n - 1).to_string());138        check(&s, &format!("{} kangaroo tight", fx.label));139    }140}141142#[test]143fn one_thread_runs_are_deterministic() {144    let fxs = load();145    for fx in fxs.iter().filter(|f| f.label.starts_with("28b") || f.label.starts_with("32b-j0")).take(6) {146        for (alg, neg, aut3, cycle) in [("rho", false, false, None), ("rho", true, false, None), ("rho", true, fx.j0, None), ("rho", false, false, Some("brent")), ("kangaroo", false, false, None)] {147            let mut s = spec(fx, alg, 99);148            s.neg = neg;149            s.aut3 = aut3;150            s.cycle = cycle.map(String::from);151            let a = check(&s, "det a");152            let b = check(&s, "det b");153            for key in ["iterations", "ops", "dp_count", "fruitless_cycles", "restarts"] {154                assert_eq!(a.get(key), b.get(key), "{} {alg} neg={neg} aut3={aut3} key={key}", fx.label);155            }156        }157    }158}159160#[test]161fn wrong_beta_or_lambda_aborts() {162    let fxs = load();163    let fx = fxs.iter().find(|f| f.j0).unwrap();164    let mut s = spec(fx, "rho", 1);165    s.aut3 = true;166    let beta: u64 = fx.beta.as_ref().unwrap().parse().unwrap();167    s.beta = Some((beta + 1).to_string());168    let out = run(&s);169    assert_eq!(out.get("ok").and_then(|v| v.as_bool()), Some(false));170    assert!(out.get("error").is_some());171    // right beta but the other cube root of unity as lambda (λ² instead of λ) must also abort172    let mut s = spec(fx, "rho", 1);173    s.aut3 = true;174    let n: u64 = fx.n.parse().unwrap();175    let lam: u128 = fx.lambda.as_ref().unwrap().parse().unwrap();176    s.lambda = Some(((lam * lam) % n as u128).to_string());177    let out = run(&s);178    assert_eq!(out.get("ok").and_then(|v| v.as_bool()), Some(false), "{out}");179    assert!(out["error"].as_str().unwrap().contains("lambda*G"));180}181
Files · main
Menu

Theme