From 968637e71e1e2931ba590160e7d22ca1b91e70e1 Mon Sep 17 00:00:00 2001 From: Erfan Khadem <45465346+er888kh@users.noreply.github.com> Date: Tue, 6 Sep 2022 21:47:41 +0430 Subject: [PATCH 1/2] Add Poly1305 (#371) --- Cargo.toml | 7 +++ src/big_integer/hello_bigmath.rs | 29 ++++++++++ src/big_integer/mod.rs | 7 +++ src/big_integer/poly1305.rs | 98 ++++++++++++++++++++++++++++++++ src/lib.rs | 3 +- 5 files changed, 143 insertions(+), 1 deletion(-) create mode 100644 src/big_integer/hello_bigmath.rs create mode 100644 src/big_integer/mod.rs create mode 100644 src/big_integer/poly1305.rs diff --git a/Cargo.toml b/Cargo.toml index eabc8f02107..07234918463 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,13 @@ [package] name = "the_algorithms_rust" +edition = "2021" version = "0.1.0" authors = ["Anshul Malik "] [dependencies] +num-bigint = { version = "0.4", optional = true } +num-traits = { version = "0.2", optional = true } + +[features] +default = ["big-math"] +big-math = ["dep:num-bigint", "dep:num-traits"] \ No newline at end of file diff --git a/src/big_integer/hello_bigmath.rs b/src/big_integer/hello_bigmath.rs new file mode 100644 index 00000000000..35d5dcef39d --- /dev/null +++ b/src/big_integer/hello_bigmath.rs @@ -0,0 +1,29 @@ +use num_bigint::BigUint; +use num_traits::One; + +// A trivial example of using Big integer math + +pub fn factorial(num: u32) -> BigUint { + let mut result: BigUint = One::one(); + for i in 1..=num { + result *= i; + } + result +} + +#[cfg(test)] +mod tests { + use std::str::FromStr; + + use super::*; + + #[test] + fn basic_factorial() { + assert_eq!(factorial(10), BigUint::from_str("3628800").unwrap()); + assert_eq!( + factorial(50), + BigUint::from_str("30414093201713378043612608166064768844377641568960512000000000000") + .unwrap() + ); + } +} diff --git a/src/big_integer/mod.rs b/src/big_integer/mod.rs new file mode 100644 index 00000000000..73c1c57015b --- /dev/null +++ b/src/big_integer/mod.rs @@ -0,0 +1,7 @@ +#![cfg(feature = "big-math")] + +mod hello_bigmath; +mod poly1305; + +pub use self::hello_bigmath::factorial; +pub use self::poly1305::Poly1305; diff --git a/src/big_integer/poly1305.rs b/src/big_integer/poly1305.rs new file mode 100644 index 00000000000..8c5a02d35c2 --- /dev/null +++ b/src/big_integer/poly1305.rs @@ -0,0 +1,98 @@ +use num_bigint::BigUint; +use num_traits::Num; +use num_traits::Zero; + +macro_rules! hex_uint { + ($a:literal) => { + BigUint::from_str_radix($a, 16).unwrap() + }; +} + +/** + * Poly1305 Message Authentication Code: + * This implementation is based on RFC8439. + * Note that the Big Integer library we are using may not be suitable for + * cryptographic applications due to non constant time operations. +*/ +pub struct Poly1305 { + p: BigUint, + r: BigUint, + s: BigUint, + /// The accumulator + pub acc: BigUint, +} + +impl Default for Poly1305 { + fn default() -> Self { + Self::new() + } +} + +impl Poly1305 { + pub fn new() -> Self { + Poly1305 { + p: hex_uint!("3fffffffffffffffffffffffffffffffb"), // 2^130 - 5 + r: Zero::zero(), + s: Zero::zero(), + acc: Zero::zero(), + } + } + pub fn clamp_r(&mut self) { + self.r &= hex_uint!("0ffffffc0ffffffc0ffffffc0fffffff"); + } + pub fn set_key(&mut self, key: &[u8; 32]) { + self.r = BigUint::from_bytes_le(&key[..16]); + self.s = BigUint::from_bytes_le(&key[16..]); + self.clamp_r(); + } + /// process a 16-byte-long message block. If message is not long enough, + /// fill the `msg` array with zeros, but set `msg_bytes` to the original + /// chunk length in bytes. See `basic_tv1` for example usage. + pub fn add_msg(&mut self, msg: &[u8; 16], msg_bytes: u64) { + let mut n = BigUint::from_bytes_le(msg); + n.set_bit(msg_bytes * 8, true); + self.acc += n; + self.acc *= &self.r; + self.acc %= &self.p; + } + /// The result is guaranteed to be 16 bytes long + pub fn get_tag(&self) -> Vec { + let result = &self.acc + &self.s; + let mut bytes = result.to_bytes_le(); + bytes.resize(16, 0); + bytes + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::fmt::Write; + fn get_tag_hex(tag: &[u8]) -> String { + let mut result = String::new(); + for &x in tag { + write!(result, "{x:02x}").unwrap(); + } + result + } + #[test] + fn basic_tv1() { + let mut mac = Poly1305::new(); + let key: [u8; 32] = [ + 0x85, 0xd6, 0xbe, 0x78, 0x57, 0x55, 0x6d, 0x33, 0x7f, 0x44, 0x52, 0xfe, 0x42, 0xd5, + 0x06, 0xa8, 0x01, 0x03, 0x80, 0x8a, 0xfb, 0x0d, 0xb2, 0xfd, 0x4a, 0xbf, 0xf6, 0xaf, + 0x41, 0x49, 0xf5, 0x1b, + ]; + let mut tmp_buffer = [0_u8; 16]; + mac.set_key(&key); + mac.add_msg(b"Cryptographic Fo", 16); + mac.add_msg(b"rum Research Gro", 16); + tmp_buffer[..2].copy_from_slice(b"up"); + mac.add_msg(&tmp_buffer, 2); + let result = mac.get_tag(); + assert_eq!( + get_tag_hex(&result.as_slice()), + "a8061dc1305136c6c22b8baf0c0127a9" + ); + } +} diff --git a/src/lib.rs b/src/lib.rs index 71e5bec5faa..28ade98d5b1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +pub mod big_integer; pub mod ciphers; pub mod data_structures; pub mod dynamic_programming; @@ -10,7 +11,7 @@ pub mod string; #[cfg(test)] mod tests { - use sorting; + use super::sorting; #[test] fn quick_sort() { //descending From 4c1f29ea6bbf9c7026fd6b50e5613824290e4916 Mon Sep 17 00:00:00 2001 From: mjh <61671361+mjh316@users.noreply.github.com> Date: Tue, 6 Sep 2022 10:23:52 -0700 Subject: [PATCH 2/2] Add floyd warshall algorithm (#366) --- DIRECTORY.md | 3 + README.md | 2 + src/data_structures/linked_list.rs | 4 +- src/data_structures/rb_tree.rs | 2 +- src/graph/floyd_warshall.rs | 182 +++++++++++++++++++++++++++++ src/graph/mod.rs | 2 + 6 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 src/graph/floyd_warshall.rs diff --git a/DIRECTORY.md b/DIRECTORY.md index a053308fa8a..746db33f9b8 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -1,6 +1,7 @@ # List of all files ## Src + * Ciphers * [Another Rot13](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/another_rot13.rs) * [Caesar](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/caesar.rs) @@ -62,6 +63,8 @@ * [Centroid Decomposition](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/centroid_decomposition.rs) * [Dinic's Max Flow](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/dinic_maxflow.rs) * [2-SAT Problem](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/two_satisfiability.rs) + * [Floyd-Warshall](https://github.com/TheAlgorithms/Rust/blob/master/src/graph/floyd_warshall.rs) + * [Lib](https://github.com/TheAlgorithms/Rust/blob/master/src/lib.rs) * Math * [Baby-Step Giant-Step Algorithm](https://github.com/TheAlgorithms/Rust/blob/master/src/math/baby_step_giant_step.rs) diff --git a/README.md b/README.md index 335c9200ebe..30aabd55195 100644 --- a/README.md +++ b/README.md @@ -46,8 +46,10 @@ These are for demonstration purposes only. - [x] [Centroid Decomposition](./src/graph/centroid_decomposition.rs) - [x] [Dinic's Max Flow](./src/graph/dinic_maxflow.rs) - [x] [2-SAT Problem](./src/graph/two_satisfiability.rs) +- [x] [Floyd-Warshall](./src/graph/floyd_warshall.rs) ## [Math](./src/math) + - [x] [Baby-Step Giant-Step Algorithm](./src/math/baby_step_giant_step.rs) - [x] [Extended euclidean algorithm](./src/math/extended_euclidean_algorithm.rs) - [x] [Gaussian Elimination](./src/math/gaussian_elimination.rs) diff --git a/src/data_structures/linked_list.rs b/src/data_structures/linked_list.rs index adb0f5fdbc7..273ad3b36ce 100644 --- a/src/data_structures/linked_list.rs +++ b/src/data_structures/linked_list.rs @@ -73,7 +73,7 @@ impl LinkedList { panic!("Index out of bounds"); } - if index == 0 || self.head == None { + if index == 0 || self.head.is_none() { self.insert_at_head(obj); return; } @@ -142,7 +142,7 @@ impl LinkedList { panic!("Index out of bounds"); } - if index == 0 || self.head == None { + if index == 0 || self.head.is_none() { return self.delete_head(); } diff --git a/src/data_structures/rb_tree.rs b/src/data_structures/rb_tree.rs index 1d4b721cb9f..f321d56e4d9 100644 --- a/src/data_structures/rb_tree.rs +++ b/src/data_structures/rb_tree.rs @@ -215,7 +215,7 @@ impl RBTree { } /* release resource */ - Box::from_raw(node); + drop(Box::from_raw(node)); if matches!(deleted_color, Color::Black) { delete_fixup(self, parent); } diff --git a/src/graph/floyd_warshall.rs b/src/graph/floyd_warshall.rs new file mode 100644 index 00000000000..7f43fbb4f09 --- /dev/null +++ b/src/graph/floyd_warshall.rs @@ -0,0 +1,182 @@ +use std::collections::BTreeMap; +use std::ops::Add; + +type Graph = BTreeMap>; + +/// Performs the Floyd-Warshall algorithm on the input graph +/// The graph is a weighted, directed graph with no negative cycles +/// +/// Returns a map storing the distance from each node to all the others +/// I.e. For each vertex u, map[u][v] == Some(distance) means +/// distance is the sum of the weights of the edges on the shortest path +/// from u to v +/// +/// For a key v, if map[v].len() == 0, then v cannot reach any other vertex, but is in the graph +/// (island node, or sink in the case of a directed graph) +pub fn floyd_warshall>( + graph: &Graph, +) -> BTreeMap> { + let mut map: BTreeMap> = BTreeMap::new(); + for (u, edges) in graph.iter() { + if !map.contains_key(u) { + map.insert(*u, BTreeMap::new()); + } + for (v, weight) in edges.iter() { + if !map.contains_key(v) { + map.insert(*v, BTreeMap::new()); + } + map.entry(*u).and_modify(|mp| { + mp.insert(*v, *weight); + }); + } + } + let keys = map.iter().map(|(k, _)| *k).collect::>(); + for &k in &keys { + for &i in &keys { + if map[&i].get(&k).is_none() { + continue; + } + for &j in &keys { + if i == j { + continue; + } + if !map[&k].contains_key(&j) { + continue; + } + let entry_i_j = map[&i].get(&j); + let entry_i_k = map[&i][&k]; + let entry_k_j = map[&k][&j]; + match entry_i_j { + Some(&e) => { + if e > entry_i_k + entry_k_j { + map.entry(i) + .or_insert(BTreeMap::new()) + .insert(j, entry_i_k + entry_k_j); + } + } + None => { + map.entry(i).or_default().insert(j, entry_i_k + entry_k_j); + } + }; + } + } + } + map +} + +#[cfg(test)] +mod tests { + use super::{floyd_warshall, Graph}; + use std::collections::BTreeMap; + + fn add_edge(graph: &mut Graph, v1: V, v2: V, c: E) { + graph.entry(v1).or_insert_with(BTreeMap::new).insert(v2, c); + } + + fn bi_add_edge(graph: &mut Graph, v1: V, v2: V, c: E) { + add_edge(graph, v1, v2, c); + add_edge(graph, v2, v1, c); + } + + #[test] + fn single_vertex() { + let mut graph: Graph = BTreeMap::new(); + graph.insert(0, BTreeMap::new()); + + let mut dists = BTreeMap::new(); + dists.insert(0, BTreeMap::new()); + + assert_eq!(floyd_warshall(&graph), dists); + } + + #[test] + fn single_edge() { + let mut graph = BTreeMap::new(); + bi_add_edge(&mut graph, 0, 1, 2); + bi_add_edge(&mut graph, 1, 2, 3); + + let mut dists_0 = BTreeMap::new(); + dists_0.insert(1, BTreeMap::new()); + dists_0.insert(2, BTreeMap::new()); + dists_0.insert(0, BTreeMap::new()); + dists_0.get_mut(&1).unwrap().insert(0, 2); + dists_0.get_mut(&0).unwrap().insert(1, 2); + dists_0.get_mut(&1).unwrap().insert(2, 3); + dists_0.get_mut(&2).unwrap().insert(1, 3); + dists_0.get_mut(&2).unwrap().insert(0, 5); + dists_0.get_mut(&0).unwrap().insert(2, 5); + + assert_eq!(floyd_warshall(&graph), dists_0); + } + + #[test] + fn graph_1() { + let mut graph = BTreeMap::new(); + add_edge(&mut graph, 'a', 'c', 12); + add_edge(&mut graph, 'a', 'd', 60); + add_edge(&mut graph, 'b', 'a', 10); + add_edge(&mut graph, 'c', 'b', 20); + add_edge(&mut graph, 'c', 'd', 32); + add_edge(&mut graph, 'e', 'a', 7); + + let mut dists_a = BTreeMap::new(); + dists_a.insert('d', BTreeMap::new()); + + dists_a + .entry('a') + .or_insert(BTreeMap::new()) + .insert('c', 12); + dists_a + .entry('c') + .or_insert(BTreeMap::new()) + .insert('a', 30); + dists_a + .entry('c') + .or_insert(BTreeMap::new()) + .insert('b', 20); + dists_a + .entry('c') + .or_insert(BTreeMap::new()) + .insert('d', 32); + dists_a.entry('e').or_insert(BTreeMap::new()).insert('a', 7); + dists_a + .entry('b') + .or_insert(BTreeMap::new()) + .insert('a', 10); + dists_a + .entry('a') + .or_insert(BTreeMap::new()) + .insert('d', 44); + dists_a + .entry('a') + .or_insert(BTreeMap::new()) + .insert('b', 32); + dists_a + .entry('a') + .or_insert(BTreeMap::new()) + .insert('b', 32); + dists_a + .entry('b') + .or_insert(BTreeMap::new()) + .insert('c', 22); + + dists_a + .entry('b') + .or_insert(BTreeMap::new()) + .insert('d', 54); + dists_a + .entry('e') + .or_insert(BTreeMap::new()) + .insert('c', 19); + dists_a + .entry('e') + .or_insert(BTreeMap::new()) + .insert('d', 51); + dists_a + .entry('e') + .or_insert(BTreeMap::new()) + .insert('b', 39); + + assert_eq!(floyd_warshall(&graph), dists_a); + } +} diff --git a/src/graph/mod.rs b/src/graph/mod.rs index 62f7ba52dac..28cd4c84ccb 100644 --- a/src/graph/mod.rs +++ b/src/graph/mod.rs @@ -6,6 +6,7 @@ mod depth_first_search_tic_tac_toe; mod dijkstra; mod dinic_maxflow; mod disjoint_set_union; +mod floyd_warshall; mod graph_enumeration; mod heavy_light_decomposition; mod lowest_common_ancestor; @@ -24,6 +25,7 @@ pub use self::depth_first_search_tic_tac_toe::minimax; pub use self::dijkstra::dijkstra; pub use self::dinic_maxflow::DinicMaxFlow; pub use self::disjoint_set_union::DisjointSetUnion; +pub use self::floyd_warshall::floyd_warshall; pub use self::graph_enumeration::enumerate_graph; pub use self::heavy_light_decomposition::HeavyLightDecomposition; pub use self::lowest_common_ancestor::{LowestCommonAncestorOffline, LowestCommonAncestorOnline};