Skip to content

[pull] master from TheAlgorithms:master #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 30, 2022
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
2 changes: 2 additions & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
* [Transposition](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/transposition.rs)
* [Vigenere](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/vigenere.rs)
* [Xor](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/xor.rs)
* [Salsa20](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/salsa.rs)
* [HMAC](https://github.com/TheAlgorithms/Rust/blob/master/src/ciphers/hashing_traits.rs)
* Data Structures
* [Avl Tree](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/avl_tree.rs)
* [B Tree](https://github.com/TheAlgorithms/Rust/blob/master/src/data_structures/b_tree.rs)
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ These are for demonstration purposes only.
- [x] [Transposition](./src/ciphers/transposition.rs)
- [x] [Vigenère](./src/ciphers/vigenere.rs)
- [x] [XOR](./src/ciphers/xor.rs)
- [x] [Salsa20](./src/ciphers/salsa.rs)
- [x] [HMAC](./src/ciphers/hashing_traits.rs)
- Rot13
- [x] [Another Rot13](./src/ciphers/another_rot13.rs)
- [x] [Rot13](./src/ciphers/rot13.rs)
Expand Down
149 changes: 149 additions & 0 deletions src/ciphers/chacha.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/*
* ChaCha20 implementation based on RFC8439
* ChaCha20 is a stream cipher developed independently by Daniel J. Bernstein.
* To use it, the `chacha20` function should be called with appropriate
* parameters and the output of the function should be XORed with plain text.
*/

macro_rules! quarter_round {
($a:expr,$b:expr,$c:expr,$d:expr) => {
$a = $a.wrapping_add($b);
$d = ($d ^ $a).rotate_left(16);
$c = $c.wrapping_add($d);
$b = ($b ^ $c).rotate_left(12);
$a = $a.wrapping_add($b);
$d = ($d ^ $a).rotate_left(8);
$c = $c.wrapping_add($d);
$b = ($b ^ $c).rotate_left(7);
};
}

#[allow(dead_code)]
// "expand 32-byte k", written in little-endian order
pub const C: [u32; 4] = [0x61707865, 0x3320646e, 0x79622d32, 0x6b206574];

/**
* `chacha20` function takes as input an array of 16 32-bit integers (512 bits)
* of which 128 bits is the constant 'expand 32-byte k', 256 bits is the key,
* and 128 bits are nonce and counter. According to RFC8439, the nonce should
* be 96 bits long, which leaves 32 bits for the counter. Given that the block
* length is 512 bits, this leaves enough counter values to encrypt 256GB of
* data.
*
* The 16 input numbers can be thought of as the elements of a 4x4 matrix like
* the one bellow, on which we do the main operations of the cipher.
*
* +----+----+----+----+
* | 00 | 01 | 02 | 03 |
* +----+----+----+----+
* | 04 | 05 | 06 | 07 |
* +----+----+----+----+
* | 08 | 09 | 10 | 11 |
* +----+----+----+----+
* | 12 | 13 | 14 | 15 |
* +----+----+----+----+
*
* As per the diagram bellow, input[0, 1, 2, 3] are the constants mentioned
* above, input[4..=11] is filled with the key, and input[6..=9] should be
* filled with nonce and counter values. The output of the function is stored
* in `output` variable and can be XORed with the plain text to produce the
* cipher text.
*
* +------+------+------+------+
* | | | | |
* | C[0] | C[1] | C[2] | C[3] |
* | | | | |
* +------+------+------+------+
* | | | | |
* | key0 | key1 | key2 | key3 |
* | | | | |
* +------+------+------+------+
* | | | | |
* | key4 | key5 | key6 | key7 |
* | | | | |
* +------+------+------+------+
* | | | | |
* | ctr0 | no.0 | no.1 | no.2 |
* | | | | |
* +------+------+------+------+
*
* Note that the constants, the key, and the nonce should be written in
* little-endian order, meaning that for example if the key is 01:02:03:04
* (in hex), it corresponds to the integer 0x04030201. It is important to
* know that the hex value of the counter is meaningless, and only its integer
* value matters, and it should start with (for example) 0x00000000, and then
* 0x00000001 and so on until 0xffffffff. Keep in mind that as soon as we get
* from bytes to words, we stop caring about their representation in memory,
* and we only need the math to be correct.
*
* The output of the function can be used without any change, as long as the
* plain text has the same endianness. For example if the plain text is
* "hello world", and the first word of the output is 0x01020304, then the
* first byte of plain text ('h') should be XORed with the least-significant
* byte of 0x01020304, which is 0x04.
*/
pub fn chacha20(input: &[u32; 16], output: &mut [u32; 16]) {
output.copy_from_slice(&input[..]);
for _ in 0..10 {
// Odd round (column round)
quarter_round!(output[0], output[4], output[8], output[12]); // column 1
quarter_round!(output[1], output[5], output[9], output[13]); // column 2
quarter_round!(output[2], output[6], output[10], output[14]); // column 3
quarter_round!(output[3], output[7], output[11], output[15]); // column 4

// Even round (diagonal round)
quarter_round!(output[0], output[5], output[10], output[15]); // diag 1
quarter_round!(output[1], output[6], output[11], output[12]); // diag 2
quarter_round!(output[2], output[7], output[8], output[13]); // diag 3
quarter_round!(output[3], output[4], output[9], output[14]); // diag 4
}
for (a, &b) in output.iter_mut().zip(input.iter()) {
*a = a.wrapping_add(b);
}
}

#[cfg(test)]
mod tests {
use super::*;
use std::fmt::Write;

fn output_hex(inp: &[u32; 16]) -> String {
let mut res = String::new();
res.reserve(512 / 4);
for &x in inp {
write!(&mut res, "{x:08x}").unwrap();
}
res
}

#[test]
// test vector 1
fn basic_tv1() {
let mut inp = [0u32; 16];
let mut out = [0u32; 16];
inp[0] = C[0];
inp[1] = C[1];
inp[2] = C[2];
inp[3] = C[3];
inp[4] = 0x03020100; // The key is 00:01:02:..:1f (hex)
inp[5] = 0x07060504;
inp[6] = 0x0b0a0908;
inp[7] = 0x0f0e0d0c;
inp[8] = 0x13121110;
inp[9] = 0x17161514;
inp[10] = 0x1b1a1918;
inp[11] = 0x1f1e1d1c;
inp[12] = 0x00000001; // The value of counter is 1 (an integer). Nonce:
inp[13] = 0x09000000; // 00:00:00:09
inp[14] = 0x4a000000; // 00:00:00:4a
inp[15] = 0x00000000; // 00:00:00:00
chacha20(&inp, &mut out);
assert_eq!(
output_hex(&out),
concat!(
"e4e7f11015593bd11fdd0f50c47120a3c7f4d1c70368c0339aaa22044e6cd4c3",
"466482d209aa9f0705d7c214a2028bd9d19c12b5b94e16dee883d0cb4e3c50a2"
)
);
}
}
4 changes: 4 additions & 0 deletions src/ciphers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
mod aes;
mod another_rot13;
mod caesar;
mod chacha;
mod hashing_traits;
mod morse_code;
mod polybius;
mod rot13;
mod salsa;
mod sha256;
mod tea;
mod theoretical_rot13;
Expand All @@ -15,11 +17,13 @@ mod xor;
pub use self::aes::{aes_decrypt, aes_encrypt, AesKey};
pub use self::another_rot13::another_rot13;
pub use self::caesar::caesar;
pub use self::chacha::chacha20;
pub use self::hashing_traits::Hasher;
pub use self::hashing_traits::HMAC;
pub use self::morse_code::{decode, encode};
pub use self::polybius::{decode_ascii, encode_ascii};
pub use self::rot13::rot13;
pub use self::salsa::salsa20;
pub use self::sha256::SHA256;
pub use self::tea::{tea_decrypt, tea_encrypt};
pub use self::theoretical_rot13::theoretical_rot13;
Expand Down
129 changes: 129 additions & 0 deletions src/ciphers/salsa.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
/*
* Salsa20 implementation based on https://en.wikipedia.org/wiki/Salsa20
* Salsa20 is a stream cipher developed by Daniel J. Bernstein. To use it, the
* `salsa20` function should be called with appropriate parameters and the
* output of the function should be XORed with plain text.
*/

macro_rules! quarter_round {
($v1:expr,$v2:expr,$v3:expr,$v4:expr) => {
$v2 ^= ($v1.wrapping_add($v4).rotate_left(7));
$v3 ^= ($v2.wrapping_add($v1).rotate_left(9));
$v4 ^= ($v3.wrapping_add($v2).rotate_left(13));
$v1 ^= ($v4.wrapping_add($v3).rotate_left(18));
};
}

#[allow(dead_code)]
pub const C: [u32; 4] = [0x65787061, 0x6e642033, 0x322d6279, 0x7465206b];

/**
* `salsa20` function takes as input an array of 16 32-bit integers (512 bits)
* of which 128 bits is the constant 'expand 32-byte k', 256 bits is the key,
* and 128 bits are nonce and counter. It is up to the user to determine how
* many bits each of nonce and counter take, but a default of 64 bits each
* seems to be a sane choice.
*
* The 16 input numbers can be thought of as the elements of a 4x4 matrix like
* the one bellow, on which we do the main operations of the cipher.
*
* +----+----+----+----+
* | 00 | 01 | 02 | 03 |
* +----+----+----+----+
* | 04 | 05 | 06 | 07 |
* +----+----+----+----+
* | 08 | 09 | 10 | 11 |
* +----+----+----+----+
* | 12 | 13 | 14 | 15 |
* +----+----+----+----+
*
* As per the diagram bellow, input[0, 5, 10, 15] are the constants mentioned
* above, input[1, 2, 3, 4, 11, 12, 13, 14] is filled with the key, and
* input[6, 7, 8, 9] should be filled with nonce and counter values. The output
* of the function is stored in `output` variable and can be XORed with the
* plain text to produce the cipher text.
*
* +------+------+------+------+
* | | | | |
* | C[0] | key1 | key2 | key3 |
* | | | | |
* +------+------+------+------+
* | | | | |
* | key4 | C[1] | no1 | no2 |
* | | | | |
* +------+------+------+------+
* | | | | |
* | ctr1 | ctr2 | C[2] | key5 |
* | | | | |
* +------+------+------+------+
* | | | | |
* | key6 | key7 | key8 | C[3] |
* | | | | |
* +------+------+------+------+
*/
pub fn salsa20(input: &[u32; 16], output: &mut [u32; 16]) {
output.copy_from_slice(&input[..]);
for _ in 0..10 {
// Odd round
quarter_round!(output[0], output[4], output[8], output[12]); // column 1
quarter_round!(output[5], output[9], output[13], output[1]); // column 2
quarter_round!(output[10], output[14], output[2], output[6]); // column 3
quarter_round!(output[15], output[3], output[7], output[11]); // column 4

// Even round
quarter_round!(output[0], output[1], output[2], output[3]); // row 1
quarter_round!(output[5], output[6], output[7], output[4]); // row 2
quarter_round!(output[10], output[11], output[8], output[9]); // row 3
quarter_round!(output[15], output[12], output[13], output[14]); // row 4
}
for (a, &b) in output.iter_mut().zip(input.iter()) {
*a = a.wrapping_add(b);
}
}

#[cfg(test)]
mod tests {
use super::*;
use std::fmt::Write;

fn output_hex(inp: &[u32; 16]) -> String {
let mut res = String::new();
res.reserve(512 / 4);
for &x in inp {
write!(&mut res, "{x:08x}").unwrap();
}
res
}
#[test]
// test vector 1
fn basic_tv1() {
let mut inp = [0u32; 16];
let mut out = [0u32; 16];
inp[0] = C[0];
inp[1] = 0x01020304; // 1, 2, 3, 4
inp[2] = 0x05060708; // 5, 6, 7, 8, ...
inp[3] = 0x090a0b0c;
inp[4] = 0x0d0e0f10;
inp[5] = C[1];
inp[6] = 0x65666768; // 101, 102, 103, 104
inp[7] = 0x696a6b6c; // 105, 106, 107, 108, ...
inp[8] = 0x6d6e6f70;
inp[9] = 0x71727374;
inp[10] = C[2];
inp[11] = 0xc9cacbcc; // 201, 202, 203, 204
inp[12] = 0xcdcecfd0; // 205, 206, 207, 208, ...
inp[13] = 0xd1d2d3d4;
inp[14] = 0xd5d6d7d8;
inp[15] = C[3];
salsa20(&inp, &mut out);
// Checked with wikipedia implementation, does not agree with
// "https://cr.yp.to/snuffle/spec.pdf"
assert_eq!(
output_hex(&out),
concat!(
"de1d6f8d91dbf69d0db4b70c8b4320d236694432896d98b05aa7b76d5738ca13",
"04e5a170c8e479af1542ed2f30f26ba57da20203cfe955c66f4cc7a06dd34359"
)
);
}
}
6 changes: 3 additions & 3 deletions src/graph/depth_first_search_tic_tac_toe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use std::io;
//#[cfg(not(test))]
//use rand::Rng;

#[derive(Copy, Clone, PartialEq, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct Position {
x: u8,
y: u8,
Expand All @@ -43,13 +43,13 @@ pub enum Players {
PlayerO,
}

#[derive(Copy, Clone, PartialEq, Debug)]
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
struct SinglePlayAction {
position: Position,
side: Players,
}

#[derive(Clone, PartialEq, Debug)]
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct PlayActions {
positions: Vec<Position>,
side: Players,
Expand Down