Rust `find_any`继续搜索

e4yzc0pl  于 2023-08-05  发布在  其他
关注(0)|答案(1)|浏览(115)

我正试图用蛮力从g^x = y (mod p)中找到x,因为我知道x只有“几个”位。

  1. use num_bigint::BigUint;
  2. use num_traits::One;
  3. use rayon::prelude::*;
  4. use std::sync::Mutex;
  5. fn main() {
  6. let p = BigUint::parse_bytes("531137992816767098689588206552468627329593117727031923199444138200403559860852242739162502265229285668889329486246501015346579337652707239409519978766587351943831270835393219031728127"
  7. .as_bytes(), 10).unwrap();
  8. let g = BigUint::parse_bytes("743488989946216334211646350465118756727157777337013657445667148279632819469843031446430723942629760903918287800011367316376"
  9. .as_bytes(), 10).unwrap();
  10. let y = BigUint::parse_bytes("85300193795644893333630947242400469685524126293619036977651049331711403849653080708338436527820826037193273430333874138094661788038445049976895820193634304228963983382234907450594225"
  11. .as_bytes(), 10).unwrap();
  12. println!("g: {}", g);
  13. println!("y: {}", y);
  14. // Brute force y = g^x
  15. let size = BigUint::from(2u32).pow(20);
  16. let num_cores = 8 as usize;
  17. let chunk_size = &size / num_cores;
  18. let num = Mutex::new(None);
  19. (0..num_cores)
  20. .into_par_iter()
  21. .find_any(|&core_idx| {
  22. let start = chunk_size.clone() * core_idx;
  23. let end = if core_idx == num_cores - 1 {
  24. size.clone()
  25. } else {
  26. start.clone() + chunk_size.clone()
  27. };
  28. let mut x = start.clone();
  29. while x < end {
  30. let y_candidate = g.modpow(&x, &p);
  31. // Check if g^x == y
  32. if y_candidate == y {
  33. println!("Found x: {}", x);
  34. *num.lock().unwrap() = Some(x.clone());
  35. return true;
  36. }
  37. x += BigUint::one();
  38. }
  39. false
  40. });
  41. if let Some(x) = num.lock().unwrap().clone() {
  42. println!("Found num: {}", x);
  43. } else {
  44. println!("x not found in the specified range.");
  45. };
  46. }

字符串
我面临的问题是,尽管一个线程找到了x,但其余的线程仍在继续搜索。我猜find_any不能保证其他线程会停止。有什么建议可以优化一下吗?资料来源:
“在并行迭代器中搜索与给定 predicate 匹配的某个项并返回它。这个操作类似于在顺序迭代器上查找,但是返回的项可能不是并行序列中第一个匹配的项,因为我们并行搜索整个序列。
一旦找到匹配项,我们将尝试尽快停止处理迭代器中的其余项(就像find一旦找到匹配项就停止迭代一样)”

qgelzfjb

qgelzfjb1#

这可以通过直接并行迭代搜索范围来简化,只要您的最大x值适合u64甚至u128

(1)简单并行

  1. use num_bigint::BigUint;
  2. use num_traits::One;
  3. use rayon::prelude::*;
  4. use std::sync::Mutex;
  5. fn main() {
  6. let p = BigUint::parse_bytes("531137992816767098689588206552468627329593117727031923199444138200403559860852242739162502265229285668889329486246501015346579337652707239409519978766587351943831270835393219031728127"
  7. .as_bytes(), 10).unwrap();
  8. let g = BigUint::parse_bytes("743488989946216334211646350465118756727157777337013657445667148279632819469843031446430723942629760903918287800011367316376"
  9. .as_bytes(), 10).unwrap();
  10. let y = BigUint::parse_bytes("85300193795644893333630947242400469685524126293619036977651049331711403849653080708338436527820826037193273430333874138094661788038445049976895820193634304228963983382234907450594225"
  11. .as_bytes(), 10).unwrap();
  12. println!("g: {}", g);
  13. println!("y: {}", y);
  14. // Brute force y = g^x
  15. let size = 2_u64.pow(20);
  16. let num = (0..size)
  17. .into_par_iter()
  18. .map(|n| BigUint::from(n))
  19. .find_any(|x| {
  20. let y_candidate = g.modpow(&x, &p);
  21. // Check if g^x == y
  22. if y_candidate == y {
  23. println!("Found x: {}", x);
  24. true
  25. } else {
  26. false
  27. }
  28. });
  29. if let Some(x) = num.clone() {
  30. println!("Found num: {}", x);
  31. } else {
  32. println!("x not found in the specified range.");
  33. };
  34. }

字符串
playground

(2)分块处理

但是将计算分块可能会更有性能。而不是像你所做的那样每个核心一个块,使用一个足够小的块大小,这样就不会太明显:

  1. use num_bigint::BigUint;
  2. use rayon::prelude::*;
  3. fn main() {
  4. let p = BigUint::parse_bytes("531137992816767098689588206552468627329593117727031923199444138200403559860852242739162502265229285668889329486246501015346579337652707239409519978766587351943831270835393219031728127"
  5. .as_bytes(), 10).unwrap();
  6. let g = BigUint::parse_bytes("743488989946216334211646350465118756727157777337013657445667148279632819469843031446430723942629760903918287800011367316376"
  7. .as_bytes(), 10).unwrap();
  8. let y = BigUint::parse_bytes("85300193795644893333630947242400469685524126293619036977651049331711403849653080708338436527820826037193273430333874138094661788038445049976895820193634304228963983382234907450594225"
  9. .as_bytes(), 10).unwrap();
  10. println!("g: {}", g);
  11. println!("y: {}", y);
  12. // Brute force y = g^x
  13. let size = BigUint::from(2_u32).pow(20);
  14. let min_chunk_size: usize = 1000;
  15. // Ensure that we don't have more than `usize::MAX` chunks
  16. let chunk_size = (&size / usize::MAX).max(BigUint::from(min_chunk_size));
  17. let chunk_count: usize = (&size / &chunk_size).try_into().unwrap();
  18. let num = (0..chunk_count)
  19. .into_par_iter()
  20. .find_map_any(|chunk| {
  21. let start = &chunk_size * chunk;
  22. let end = if chunk + 1 == chunk_count {
  23. size.clone()
  24. } else {
  25. &start + &chunk_size
  26. };
  27. let mut x = start;
  28. while x < end {
  29. let y_candidate = g.modpow(&x, &p);
  30. // Check if g^x == y
  31. if y_candidate == y {
  32. println!("Found x: {}", x);
  33. return Some(x);
  34. }
  35. x += 1_u8;
  36. }
  37. None
  38. });
  39. if let Some(x) = num.clone() {
  40. println!("Found num: {}", x);
  41. } else {
  42. println!("x not found in the specified range.");
  43. };
  44. }


playground
这也允许您将size设置为BigUint,这意味着您的x范围是无限的。但是如果size > usize::MAX * 1000,块大小(以及找到答案后的延迟)将开始增加。

(3)原子标志

您可以在找到答案时设置原子,并在循环中检查该原子。这允许您几乎立即停止,即使是非常大的块大小。

  1. use std::sync::atomic::{AtomicBool, Ordering};
  2. use num_bigint::BigUint;
  3. use rayon::prelude::*;
  4. fn main() {
  5. let p = BigUint::parse_bytes("531137992816767098689588206552468627329593117727031923199444138200403559860852242739162502265229285668889329486246501015346579337652707239409519978766587351943831270835393219031728127"
  6. .as_bytes(), 10).unwrap();
  7. let g = BigUint::parse_bytes("743488989946216334211646350465118756727157777337013657445667148279632819469843031446430723942629760903918287800011367316376"
  8. .as_bytes(), 10).unwrap();
  9. let y = BigUint::parse_bytes("85300193795644893333630947242400469685524126293619036977651049331711403849653080708338436527820826037193273430333874138094661788038445049976895820193634304228963983382234907450594225"
  10. .as_bytes(), 10).unwrap();
  11. println!("g: {}", g);
  12. println!("y: {}", y);
  13. // Brute force y = g^x
  14. let zero = BigUint::from(0_u32);
  15. let size = BigUint::from(2_u32).pow(20);
  16. let chunk_count: usize = 8;
  17. let chunk_size = &size / &chunk_count;
  18. let found = AtomicBool::new(false);
  19. let num = (0..chunk_count)
  20. .into_par_iter()
  21. .find_map_any(|chunk| {
  22. let start = &chunk_size * chunk;
  23. let end = if chunk + 1 == chunk_count {
  24. size.clone()
  25. } else {
  26. &start + &chunk_size
  27. };
  28. let mut x = start;
  29. while x < end {
  30. // Stop if the answer was found
  31. // Check infrequently to as to amortize the atomic read
  32. if &x % 100_u32 == zero {
  33. if found.load(Ordering::Relaxed) {
  34. break;
  35. }
  36. }
  37. let y_candidate = g.modpow(&x, &p);
  38. // Check if g^x == y
  39. if y_candidate == y {
  40. println!("Found x: {}", x);
  41. found.store(true, Ordering::Relaxed);
  42. return Some(x);
  43. }
  44. x += 1_u8;
  45. }
  46. None
  47. });
  48. if let Some(x) = num.clone() {
  49. println!("Found num: {}", x);
  50. } else {
  51. println!("x not found in the specified range.");
  52. };
  53. }


playground
如果您期望答案接近范围的开始,我建议使用比处理核心多得多的块。这可以防止在与答案相距甚远的块上浪费太多的处理能力。

展开查看全部

相关问题