Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
[package]
name = "the_algorithms_rust"
edition = "2021"
version = "0.1.0"
authors = ["Anshul Malik <malikanshul29@gmail.com>"]

[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"]
3 changes: 3 additions & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
@@ -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)
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
29 changes: 29 additions & 0 deletions src/big_integer/hello_bigmath.rs
Original file line number Diff line number Diff line change
@@ -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()
);
}
}
7 changes: 7 additions & 0 deletions src/big_integer/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#![cfg(feature = "big-math")]

mod hello_bigmath;
mod poly1305;

pub use self::hello_bigmath::factorial;
pub use self::poly1305::Poly1305;
98 changes: 98 additions & 0 deletions src/big_integer/poly1305.rs
Original file line number Diff line number Diff line change
@@ -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<u8> {
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"
);
}
}
4 changes: 2 additions & 2 deletions src/data_structures/linked_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ impl<T> LinkedList<T> {
panic!("Index out of bounds");
}

if index == 0 || self.head == None {
if index == 0 || self.head.is_none() {
self.insert_at_head(obj);
return;
}
Expand Down Expand Up @@ -142,7 +142,7 @@ impl<T> LinkedList<T> {
panic!("Index out of bounds");
}

if index == 0 || self.head == None {
if index == 0 || self.head.is_none() {
return self.delete_head();
}

Expand Down
2 changes: 1 addition & 1 deletion src/data_structures/rb_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ impl<K: Ord, V> RBTree<K, V> {
}

/* release resource */
Box::from_raw(node);
drop(Box::from_raw(node));
if matches!(deleted_color, Color::Black) {
delete_fixup(self, parent);
}
Expand Down
182 changes: 182 additions & 0 deletions src/graph/floyd_warshall.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
use std::collections::BTreeMap;
use std::ops::Add;

type Graph<V, E> = BTreeMap<V, BTreeMap<V, E>>;

/// 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<V: Ord + Copy, E: Ord + Copy + Add<Output = E>>(
graph: &Graph<V, E>,
) -> BTreeMap<V, BTreeMap<V, E>> {
let mut map: BTreeMap<V, BTreeMap<V, E>> = 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::<Vec<_>>();
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<V: Ord + Copy, E: Ord + Copy>(graph: &mut Graph<V, E>, v1: V, v2: V, c: E) {
graph.entry(v1).or_insert_with(BTreeMap::new).insert(v2, c);
}

fn bi_add_edge<V: Ord + Copy, E: Ord + Copy>(graph: &mut Graph<V, E>, 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<usize, usize> = 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);
}
}
Loading