number_theory.rs 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. use crate::arith::*;
  2. use rand::Rng;
  3. const ATTEMPT_MAX: usize = 100;
  4. pub fn is_primitive_root(root: u64, degree: u64, modulus: u64) -> bool {
  5. if root == 0 {
  6. return false;
  7. }
  8. exponentiate_uint_mod(root, degree >> 1, modulus) == modulus - 1
  9. }
  10. pub fn get_primitive_root(degree: u64, modulus: u64) -> Option<u64> {
  11. assert!(modulus > 1);
  12. assert!(degree >= 2);
  13. let size_entire_group = modulus - 1;
  14. let size_quotient_group = size_entire_group / degree;
  15. if size_entire_group - size_quotient_group * degree != 0 {
  16. return None;
  17. }
  18. let mut root = 0u64;
  19. for trial in 0..ATTEMPT_MAX {
  20. let mut rng = rand::thread_rng();
  21. let r1: u64 = rng.gen();
  22. let r2: u64 = rng.gen();
  23. let r3 = ((r1 << 32) | r2) % modulus;
  24. root = exponentiate_uint_mod(r3, size_quotient_group, modulus);
  25. if is_primitive_root(root, degree, modulus) {
  26. break;
  27. }
  28. if trial == ATTEMPT_MAX - 1 {
  29. return None;
  30. }
  31. }
  32. Some(root)
  33. }
  34. pub fn get_minimal_primitive_root(degree: u64, modulus: u64) -> Option<u64> {
  35. let mut root = get_primitive_root(degree, modulus)?;
  36. let generator_sq = multiply_uint_mod(root, root, modulus);
  37. let mut current_generator = root;
  38. for _ in 0..degree {
  39. if current_generator < root {
  40. root = current_generator;
  41. }
  42. current_generator = multiply_uint_mod(current_generator, generator_sq, modulus);
  43. }
  44. Some(root)
  45. }
  46. pub fn extended_gcd(mut x: u64, mut y: u64) -> (u64, i64, i64) {
  47. assert!(x != 0);
  48. assert!(y != 0);
  49. let mut prev_a = 1;
  50. let mut a = 0;
  51. let mut prev_b = 0;
  52. let mut b = 1;
  53. while y != 0 {
  54. let q: i64 = (x / y) as i64;
  55. let mut temp = (x % y) as i64;
  56. x = y;
  57. y = temp as u64;
  58. temp = a;
  59. a = prev_a - (q * a);
  60. prev_a = temp;
  61. temp = b;
  62. b = prev_b - (q * b);
  63. prev_b = temp;
  64. }
  65. (x, prev_a, prev_b)
  66. }
  67. pub fn invert_uint_mod(value: u64, modulus: u64) -> Option<u64> {
  68. if value == 0 {
  69. return None;
  70. }
  71. let gcd_tuple = extended_gcd(value, modulus);
  72. if gcd_tuple.0 != 1 {
  73. return None;
  74. } else if gcd_tuple.1 < 0 {
  75. return Some((gcd_tuple.1 as u64).overflowing_add(modulus).0);
  76. } else {
  77. return Some(gcd_tuple.1 as u64);
  78. }
  79. }