discrete_logarithm/
lib.rs1#![doc = include_str!("../README.md")]
2#![deny(rust_2018_idioms)]
3#![warn(missing_docs)]
4
5use std::collections::HashMap;
6
7use n_order::n_order_with_factors;
8use rug::{integer::IsPrime, Integer};
9mod n_order;
10mod pohlig_hellman;
11mod pollard_rho;
12mod shanks_steps;
13mod trial_mul;
14mod utils;
15
16pub use n_order::n_order;
17pub use pohlig_hellman::discrete_log_pohlig_hellman;
18pub use pollard_rho::discrete_log_pollard_rho;
19pub use shanks_steps::discrete_log_shanks_steps;
20pub use trial_mul::discrete_log_trial_mul;
21
22#[derive(thiserror::Error, Debug, Clone, PartialEq, Eq)]
24pub enum Error {
25 #[error("Log does not exist")]
27 LogDoesNotExist,
28 #[error("A and n are not relatively prime")]
30 NotRelativelyPrime,
31}
32
33pub fn discrete_log(n: &Integer, a: &Integer, b: &Integer) -> Result<Integer, Error> {
35 discrete_log_with_order(n, a, b, &n_order(b, n)?)
36}
37
38pub fn discrete_log_with_factors(
42 n: &Integer,
43 a: &Integer,
44 b: &Integer,
45 n_factors: &HashMap<Integer, usize>,
46) -> Result<Integer, Error> {
47 discrete_log_with_order(n, a, b, &n_order_with_factors(b, n, n_factors)?)
48}
49
50pub fn discrete_log_with_order(
54 n: &Integer,
55 a: &Integer,
56 b: &Integer,
57 order: &Integer,
58) -> Result<Integer, Error> {
59 if *order < 1000 {
60 discrete_log_trial_mul(n, a, b, Some(order))
61 } else if order.is_probably_prime(100) != IsPrime::No {
62 if *order < shanks_steps::MAX_ORDER {
63 discrete_log_shanks_steps(n, a, b, Some(order))
64 } else {
65 discrete_log_pollard_rho(n, a, b, Some(order))
66 }
67 } else {
68 discrete_log_pohlig_hellman(n, a, b, Some(order))
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use std::str::FromStr;
75
76 use super::*;
77
78 #[test]
79 fn big_discrete_log() {
80 let n = Integer::from_str("83408372012221120677052349409462320990177094246143674474872152829440524098582262384066400107950985845255268335597502228206679771838750219696329523257176739436871327238322817403970284015587320158034304282786944710043150568360761457471641695390427267786485448748458445872307883254297662715749746270343116946519").unwrap();
81 let a = Integer::from_str("109770827223661560471527567179288748906402603483328748683689436879660543465776899146036833470531024202351087008847594392666852763100570391337823820240726499421306887565697452868723849092658743267256316770223643723095601213088336064635680075206929620159782416078143076506249031972043819429093074684182845530529249907297736582589125917235222921623698038868900282049587768700860009877737045693722732170123306528145661683416808514556360429554775212088169626620488741903267154641722293484797745665402402381445609873333905772582972140944493849645600529147490903067975300304532955461710562911203871840101407995813072692212").unwrap();
82 let b = Integer::from_str("65537").unwrap();
83
84 assert_eq!(
85 discrete_log(&n, &a, &b).unwrap(),
86 Integer::from_str("495604594360692646132957963901411709").unwrap(),
87 );
88 }
89}