diff --git a/bitcoin_address/.gitignore b/bitcoin_address/.gitignore new file mode 100644 index 0000000..6985cf1 --- /dev/null +++ b/bitcoin_address/.gitignore @@ -0,0 +1,14 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb diff --git a/bitcoin_address/Cargo.toml b/bitcoin_address/Cargo.toml new file mode 100644 index 0000000..495e6c3 --- /dev/null +++ b/bitcoin_address/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "bitcoin_address" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +bs58 = "0.5.0" +hex = "0.4.3" +sha256 = "1.5.0" diff --git a/bitcoin_address/src/main.rs b/bitcoin_address/src/main.rs new file mode 100644 index 0000000..9bb4dcf --- /dev/null +++ b/bitcoin_address/src/main.rs @@ -0,0 +1,62 @@ +use bs58; +use hex; +use sha256; + +// Mainnet +enum Prefixes { + P2PKH, + P2SH, + WIFPrivateKey, + ExtendedPrivateKey, + ExtendedPublicKey, +} + +impl Prefixes { + fn value(&self) -> Vec { + match *self { + Prefixes::P2PKH => vec![0], // 00 + Prefixes::P2SH => vec![5], // 05 + Prefixes::WIFPrivateKey => vec![128], // 80 + Prefixes::ExtendedPrivateKey => vec![4, 136, 173, 228], // 04 88 AD E4 + Prefixes::ExtendedPublicKey => vec![4, 136, 178, 30], // 04 88 B2 1E + } + } +} + +fn my_checksum(data: &Vec) -> String { + // There was a bug here because the first sha256 returns a String - didn't even think of + // Kind of fucking dumb it returns that as the "default" data type IUAM + sha256::digest(hex::decode(sha256::digest(data)).unwrap())[0..8].to_string() +} + +fn pubkeyhash_to_address(prefix: &str, p2pkh: &str, checksum: Option<&str>) -> String { + let mut address_unencoded: Vec = vec![]; + address_unencoded.extend(hex::decode(prefix).unwrap()); + address_unencoded.extend(hex::decode(p2pkh).unwrap()); + let determined_checksum = my_checksum(&address_unencoded); + if let Some(chk) = checksum { + assert_eq!(chk, determined_checksum); + }; + address_unencoded.extend(hex::decode(determined_checksum).unwrap()); + bs58::encode(address_unencoded).into_string() +} + +fn main() { + println!("Hello, world!"); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn satoshi2() { + let prefix = hex::encode(Prefixes::P2PKH.value()); + let pubkeyhash = "11b366edfc0a8b66feebae5c2e25a7b6a5d1cf31".to_string(); + let satoshi2_address = pubkeyhash_to_address(&prefix, &pubkeyhash, None); + assert_eq!( + satoshi2_address, + "12cbQLTFMXRnSzktFkuoG3eHoMeFtpTu3S".to_string() + ); + } +} diff --git a/crypto/caeser_cipher/.gitignore b/crypto/caeser_cipher/.gitignore new file mode 100644 index 0000000..6985cf1 --- /dev/null +++ b/crypto/caeser_cipher/.gitignore @@ -0,0 +1,14 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb diff --git a/crypto/caeser_cipher/Cargo.toml b/crypto/caeser_cipher/Cargo.toml new file mode 100644 index 0000000..0967fe2 --- /dev/null +++ b/crypto/caeser_cipher/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "caeser_cipher" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/crypto/caeser_cipher/src/main.rs b/crypto/caeser_cipher/src/main.rs new file mode 100644 index 0000000..e31ce95 --- /dev/null +++ b/crypto/caeser_cipher/src/main.rs @@ -0,0 +1,49 @@ +fn main() { + println!("Hello, world!"); +} + +fn caesar(plain: &str, rshift: u8) -> String { + let alphabet = "abcdefghijklmnopqrstuvwxyz"; + let mut out = String::new(); + for c in plain.chars() { + if !c.is_alphabetic() { + out.push(c); + continue; + } + let num = (alphabet + .bytes() + .position(|a| a == c.to_lowercase().next().unwrap() as u8) + .unwrap() as u8 + + rshift) + % 26; + let a = alphabet.chars().nth(num as usize).unwrap(); + let a = if c.is_uppercase() { + a.to_uppercase().next().unwrap() + } else { + a + }; + out.push(a); + } + out +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn rot13() { + let message = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; + let shift = 13; + let out = "NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm"; + assert_eq!(caesar(message, shift), out); + } + + #[test] + fn wiki_caesar() { + let message = "THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG"; + let shift = 23; + let out = "QEB NRFZH YOLTK CLU GRJMP LSBO QEB IXWV ALD"; + assert_eq!(caesar(message, shift), out); + } +} diff --git a/crypto/vigenere/.gitignore b/crypto/vigenere/.gitignore new file mode 100644 index 0000000..6985cf1 --- /dev/null +++ b/crypto/vigenere/.gitignore @@ -0,0 +1,14 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb diff --git a/crypto/vigenere/Cargo.toml b/crypto/vigenere/Cargo.toml new file mode 100644 index 0000000..8c75b70 --- /dev/null +++ b/crypto/vigenere/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "vigenere" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/crypto/vigenere/src/main.rs b/crypto/vigenere/src/main.rs new file mode 100644 index 0000000..0fda6e3 --- /dev/null +++ b/crypto/vigenere/src/main.rs @@ -0,0 +1,22 @@ +fn vigenere(input: &str, key: &str) -> String { + let mut out = String::new(); + + out +} + +fn main() { + println!("Hello, world!"); +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn vigenere_wiki1() { + let message = "attacking tonight"; + let key = "OCULORHINOLARINGOLOGY"; + let out = "ovnlqbpvt hznzouz"; + assert_eq!(vigenere(&message, &key), out); + } +} diff --git a/element_words_rs/.gitignore b/element_words_rs/.gitignore new file mode 100644 index 0000000..6985cf1 --- /dev/null +++ b/element_words_rs/.gitignore @@ -0,0 +1,14 @@ +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information +*.pdb diff --git a/element_words_rs/Cargo.toml b/element_words_rs/Cargo.toml new file mode 100644 index 0000000..41f7778 --- /dev/null +++ b/element_words_rs/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "elname_rs" +version = "0.1.0" +edition = "2021" + +[lib] +name = "elname" +path = "src/lib.rs" + +[[bin]] +name = "elname" +path = "src/main.rs" +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +itertools = "0.11.0" diff --git a/element_words_rs/src/lib.rs b/element_words_rs/src/lib.rs new file mode 100644 index 0000000..4e43b7d --- /dev/null +++ b/element_words_rs/src/lib.rs @@ -0,0 +1,244 @@ +use itertools::Itertools; + +#[derive(PartialEq, Debug)] +pub enum ElementSubstring { + Element(String), + NonElement(String), +} + +fn elementsubstringvec_length(elword: &Vec) -> usize { + let mut size = 0; + for substring in elword { + match substring { + ElementSubstring::Element(s) => { + for _char in s.chars() { + size += 1; + } + } + ElementSubstring::NonElement(s) => { + for _char in s.chars() { + size += 1; + } + } + } + } + size +} + +const SINGLE_CHAR_ELEMENTS: &'static [&'static str] = &[ + "B", "C", "F", "H", "I", "N", "O", "P", "K", "S", "W", "U", "V", "Y", +]; +const DOUBLE_CHAR_ELEMENTS: &'static [&'static str] = &[ + "Ac", "Al", "Am", "Sb", "Ar", "As", "At", "Ba", "Bk", "Be", "Bi", "Bh", "Br", "Cd", "Cs", "Ca", + "Cf", "Ce", "Cl", "Cr", "Co", "Cn", "Cu", "Cm", "Ds", "Db", "Dy", "Es", "Er", "Eu", "Fm", "Fl", + "Fr", "Gd", "Ga", "Ge", "Au", "Hf", "Hs", "He", "Ho", "In", "Ir", "Fe", "Kr", "La", "Lr", "Pb", + "Li", "Lv", "Lu", "Mg", "Mn", "Mt", "Md", "Hg", "Mo", "Mc", "Nd", "Ne", "Np", "Ni", "Nh", "Nb", + "No", "Og", "Os", "Pd", "Pt", "Pu", "Po", "Pr", "Pm", "Pa", "Ra", "Rn", "Re", "Rh", "Rg", "Rb", + "Ru", "Rf", "Sm", "Sc", "Sg", "Se", "Si", "Ag", "Na", "Sr", "Ta", "Tc", "Te", "Ts", "Tb", "Tl", + "Th", "Tm", "Sn", "Ti", "Xe", "Yb", "Zn", "Zr", +]; + +pub fn partial_elname(word: &str) -> Vec { + let mut elword = vec![]; + let word = word.to_lowercase(); + let mut substring: String = String::new(); + let mut skip_next_loop = false; + for (prev, next) in word.chars().tuple_windows() { + if skip_next_loop { + skip_next_loop = false; + continue; + } + let potential_el: String = prev.to_string().to_uppercase() + &next.to_string(); + let mut found_match = false; + for element in DOUBLE_CHAR_ELEMENTS { + if element == &potential_el { + if substring.len() > 0 { + elword.push(ElementSubstring::NonElement(substring.clone())); + substring = String::new(); + } + elword.push(ElementSubstring::Element(element.to_string())); + skip_next_loop = true; + found_match = true; + break; + } + } + if found_match { + continue; + } + + for element in SINGLE_CHAR_ELEMENTS { + if element.to_lowercase().chars().next().unwrap() == prev { + if substring.len() > 0 { + elword.push(ElementSubstring::NonElement(substring.clone())); + substring = String::new(); + } + elword.push(ElementSubstring::Element(element.to_string())); + found_match = true; + break; + } + } + if found_match { + continue; + } + substring.push(prev); + } + // This gets triggered when either: + // - the last window is 2 valid Elements as in "CrISP", or + // - the second to last window is a 2 letter Element (and would be skipped) as in "BaN" + if elementsubstringvec_length(&elword) <= word.chars().count() - 1 { + let last_char = word.chars().last().unwrap(); + let mut found_match = false; + for element in SINGLE_CHAR_ELEMENTS { + if element.to_lowercase().chars().next().unwrap() == last_char { + if substring.len() > 0 { + elword.push(ElementSubstring::NonElement(substring.clone())); + substring = String::new(); + } + elword.push(ElementSubstring::Element(element.to_string())); + found_match = true; + break; + } + } + if !found_match { + substring.push(last_char); + } + } + if substring.len() > 0 { + elword.push(ElementSubstring::NonElement(substring.clone())); + } + elword +} + +pub fn complete_elname(word: &str) -> Option> { + let mut elword: Vec = vec![]; + let word = word.to_lowercase(); + // The thing feels a bit un-rust-y, but does seem to work! + let mut skip_next_loop = false; + for (prev, next) in word.chars().tuple_windows() { + if skip_next_loop { + skip_next_loop = false; + continue; + } + + let potential_el: String = prev.to_string().to_uppercase() + &next.to_string(); + + let mut found_match = false; + // Can probably short circuit slightly here based on ASCII value or something (if in alphabetical order) + for element in DOUBLE_CHAR_ELEMENTS { + if element == &potential_el { + elword.push(element.to_string()); + skip_next_loop = true; + found_match = true; + break; + } + } + if found_match { + continue; + } + + for element in SINGLE_CHAR_ELEMENTS { + if element.to_lowercase().chars().next().unwrap() == prev { + elword.push(element.to_string()); + found_match = true; + break; + } + } + + if !found_match { + return None; + } + } + + // This gets triggered when either: + // - the last window is 2 valid Elements as in "CrISP", or + // - the second to last window is a 2 letter Element (and would be skipped) as in "BaN" + let mut num_chars = 0; + for els in &elword { + num_chars += els.chars().count(); + } + if num_chars == word.chars().count() - 1 { + let mut found_match = false; + let last_char = word.chars().last().unwrap(); + for element in SINGLE_CHAR_ELEMENTS { + if element.to_lowercase().chars().nth(0).unwrap() == last_char { + elword.push(element.to_string()); + found_match = true; + break; + } + } + if !found_match { + return None; + } + } + + Some(elword) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_complete_elname() { + assert_eq!(complete_elname("a"), None); + assert_eq!(complete_elname("bar"), None); + assert_eq!(complete_elname("zee"), None); + assert_eq!(complete_elname("ge"), Some(vec!["Ge".to_string()])); + assert_eq!( + complete_elname("cras"), + Some(vec!["Cr".to_string(), "As".to_string()]) + ); + assert_eq!( + complete_elname("ban"), + Some(vec!["Ba".to_string(), "N".to_string()]) + ); + assert_eq!(complete_elname("arthur"), None); + assert_eq!( + complete_elname("crisp"), + Some(vec![ + "Cr".to_string(), + "I".to_string(), + "S".to_string(), + "P".to_string() + ]) + ); + assert_eq!(complete_elname("accepting"), None); + } + + #[test] + fn test_partial_elname() { + type ES = ElementSubstring; + assert_eq!(partial_elname("a"), vec![ES::NonElement("a".to_string())]); + assert_eq!( + partial_elname("bar"), + vec![ + ES::Element("Ba".to_string()), + ES::NonElement("r".to_string()) + ] + ); + assert_eq!( + partial_elname("zee"), + vec![ES::NonElement("zee".to_string())] + ); + assert_eq!(partial_elname("ge"), vec![ES::Element("Ge".to_string())]); + assert_eq!( + partial_elname("crisp"), + vec![ + ES::Element("Cr".to_string()), + ES::Element("I".to_string()), + ES::Element("S".to_string()), + ES::Element("P".to_string()) + ] + ); + assert_eq!( + partial_elname("accepting"), + vec![ + ES::Element("Ac".to_string()), + ES::Element("Ce".to_string()), + ES::Element("Pt".to_string()), + ES::Element("In".to_string()), + ES::NonElement("g".to_string()) + ] + ); + } +} diff --git a/element_words_rs/src/main.rs b/element_words_rs/src/main.rs new file mode 100644 index 0000000..c1f172a --- /dev/null +++ b/element_words_rs/src/main.rs @@ -0,0 +1,17 @@ +use elname::{complete_elname, partial_elname}; +use std::fs::read_to_string; + +pub fn main() { + // Presume running in the elname_rs folder + for line in read_to_string("../wordlist.10000").unwrap().lines() { + let tmp_elname = complete_elname(line); + if let Some(el) = tmp_elname { + //println!("{} -> {:?}", line, el); + } + } + for line in read_to_string("../wordlist.10000").unwrap().lines() { + let tmp_elname = partial_elname(line); + println!("{} -> {:?}", line, tmp_elname); + } + +}