我正试图用蛮力从g^x = y (mod p)
中找到x
,因为我知道x
只有“几个”位。
use num_bigint::BigUint;
use num_traits::One;
use rayon::prelude::*;
use std::sync::Mutex;
fn main() {
let p = BigUint::parse_bytes("531137992816767098689588206552468627329593117727031923199444138200403559860852242739162502265229285668889329486246501015346579337652707239409519978766587351943831270835393219031728127"
.as_bytes(), 10).unwrap();
let g = BigUint::parse_bytes("743488989946216334211646350465118756727157777337013657445667148279632819469843031446430723942629760903918287800011367316376"
.as_bytes(), 10).unwrap();
let y = BigUint::parse_bytes("85300193795644893333630947242400469685524126293619036977651049331711403849653080708338436527820826037193273430333874138094661788038445049976895820193634304228963983382234907450594225"
.as_bytes(), 10).unwrap();
println!("g: {}", g);
println!("y: {}", y);
// Brute force y = g^x
let size = BigUint::from(2u32).pow(20);
let num_cores = 8 as usize;
let chunk_size = &size / num_cores;
let num = Mutex::new(None);
(0..num_cores)
.into_par_iter()
.find_any(|&core_idx| {
let start = chunk_size.clone() * core_idx;
let end = if core_idx == num_cores - 1 {
size.clone()
} else {
start.clone() + chunk_size.clone()
};
let mut x = start.clone();
while x < end {
let y_candidate = g.modpow(&x, &p);
// Check if g^x == y
if y_candidate == y {
println!("Found x: {}", x);
*num.lock().unwrap() = Some(x.clone());
return true;
}
x += BigUint::one();
}
false
});
if let Some(x) = num.lock().unwrap().clone() {
println!("Found num: {}", x);
} else {
println!("x not found in the specified range.");
};
}
字符串
我面临的问题是,尽管一个线程找到了x
,但其余的线程仍在继续搜索。我猜find_any
不能保证其他线程会停止。有什么建议可以优化一下吗?资料来源:
“在并行迭代器中搜索与给定 predicate 匹配的某个项并返回它。这个操作类似于在顺序迭代器上查找,但是返回的项可能不是并行序列中第一个匹配的项,因为我们并行搜索整个序列。
一旦找到匹配项,我们将尝试尽快停止处理迭代器中的其余项(就像find一旦找到匹配项就停止迭代一样)”
1条答案
按热度按时间qgelzfjb1#
这可以通过直接并行迭代搜索范围来简化,只要您的最大
x
值适合u64
甚至u128
。(1)简单并行
字符串
playground
(2)分块处理
但是将计算分块可能会更有性能。而不是像你所做的那样每个核心一个块,使用一个足够小的块大小,这样就不会太明显:
型
playground
这也允许您将
size
设置为BigUint
,这意味着您的x
范围是无限的。但是如果size > usize::MAX * 1000
,块大小(以及找到答案后的延迟)将开始增加。(3)原子标志
您可以在找到答案时设置原子,并在循环中检查该原子。这允许您几乎立即停止,即使是非常大的块大小。
型
playground的
如果您期望答案接近范围的开始,我建议使用比处理核心多得多的块。这可以防止在与答案相距甚远的块上浪费太多的处理能力。