From 954b5835a12395ef0d98dd61c1a7c52e707d431a Mon Sep 17 00:00:00 2001 From: gogo Date: Wed, 19 Jul 2023 19:44:15 +0200 Subject: [PATCH] Implement birthday paradox and document bitcoin collision. --- Cargo.toml | 5 +- cryptatools-core/Cargo.toml | 7 +- cryptatools-core/build.rs | 2 +- .../hash_cryptanalysis/birthday_paradox.rs | 150 ++++- cryptatools-core/src/utils/alphabets.rs | 536 +++++++++++++++++- .../ethereum-colision-evaluation/Cargo.toml | 13 + .../ethereum-colision-evaluation/src/main.rs | 31 + docs/src/SUMMARY.md | 8 +- ...ng-bitcoin-wallet-collision-probability.md | 133 +++++ 9 files changed, 877 insertions(+), 8 deletions(-) create mode 100644 doc-examples/ethereum-colision-evaluation/Cargo.toml create mode 100644 doc-examples/ethereum-colision-evaluation/src/main.rs create mode 100644 docs/src/chapter_2/Blockchain/1-Evaluating-bitcoin-wallet-collision-probability.md diff --git a/Cargo.toml b/Cargo.toml index 6d8d12acbd..5e2dab49b6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,5 +22,6 @@ harness = false members = [ "cryptatools-core", "cryptatools-cli", - "cryptatools-gui" -] + "cryptatools-gui", + "doc-examples/ethereum-colision-evaluation" +] \ No newline at end of file diff --git a/cryptatools-core/Cargo.toml b/cryptatools-core/Cargo.toml index 44faf97c26..95d93aa4c4 100644 --- a/cryptatools-core/Cargo.toml +++ b/cryptatools-core/Cargo.toml @@ -14,8 +14,13 @@ approx = "*" bimap = "*" once_cell = "*" itertools = "*" -rand = "0.8.5" uniffi_bindgen = "*" +time = "*" +rand = "*" +num-bigint = "*" +num-traits = "*" +num = "*" +num-bigfloat = "*" [build-dependencies] uniffi = {version = "*", features = [ "build", "cli" ]} diff --git a/cryptatools-core/build.rs b/cryptatools-core/build.rs index d4b8b76b05..f0d5f3dbc4 100644 --- a/cryptatools-core/build.rs +++ b/cryptatools-core/build.rs @@ -1,3 +1,3 @@ fn main() { uniffi::generate_scaffolding("./src/cryptatools.udl").unwrap(); -} +} \ No newline at end of file diff --git a/cryptatools-core/src/cryptanalysis/general_cryptanalysis_methods/hash_cryptanalysis/birthday_paradox.rs b/cryptatools-core/src/cryptanalysis/general_cryptanalysis_methods/hash_cryptanalysis/birthday_paradox.rs index e646c0f80e..e467cb478b 100644 --- a/cryptatools-core/src/cryptanalysis/general_cryptanalysis_methods/hash_cryptanalysis/birthday_paradox.rs +++ b/cryptatools-core/src/cryptanalysis/general_cryptanalysis_methods/hash_cryptanalysis/birthday_paradox.rs @@ -1,8 +1,17 @@ -use once_cell::sync::Lazy; use std::sync::Arc; +use num_bigfloat::BigFloat; +use num_traits::Pow; +use num::FromPrimitive; +use num_traits::Float; +use num::ToPrimitive; +use num::One; + + + use crate::utils::alphabets::Alphabet; +use crate::utils::alphabets::split_bytes_by_characters_representation; -struct BirtdayParadox { +pub struct BirtdayParadox { alphabet: Arc, } @@ -12,4 +21,141 @@ impl BirtdayParadox { alphabet: alphabet, } } + + /// Calculate Birthday Paradox from hash. Focus of precision. + /// + /// Method to get the percent of chance to get a collision to on a hash. + /// Take the len of the hash, + /// + /// ``` + /// use cryptatools_core::cryptanalysis::general_cryptanalysis_methods::frequency_analysis::coincidence_index::CoincidenceIndexGuesser; + /// use cryptatools_core::cryptanalysis::general_cryptanalysis_methods::hash_cryptanalysis::birthday_paradox::BirtdayParadox; + /// use cryptatools_core::utils::alphabets::Alphabet; + /// use cryptatools_core::utils::convert::Encode; + /// + /// let lowercase_hexadecimal = Alphabet::new_empty().hexadecimal_ascii_lowercase_sixteen_bits_alphabet(); + /// let bp = BirtdayParadox::new(lowercase_hexadecimal.into()); + /// let mut hash = Encode::from_ascii_to_u8(String::from("1")); + /// assert_eq!(hash, vec![49]); + /// assert_eq!(bp.calculate_birtday_paradox_expecting_percent_focusing_on_precision(hash.clone(), 0.5), 5);//20 + /// assert_eq!(bp.calculate_birtday_paradox_expecting_percent_focusing_on_precision(hash.clone(), 0.95), 10);//39 + /// hash = Encode::from_ascii_to_u8(String::from("1f9")); + /// assert_eq!(bp.calculate_birtday_paradox_expecting_percent_focusing_on_precision(hash.clone(), 0.95), 16060); + /// hash = Encode::from_ascii_to_u8(String::from("1f90")); + /// assert_eq!(bp.calculate_birtday_paradox_expecting_percent_focusing_on_precision(hash.clone(), 0.95), 160416); + /// //let hash = Encode::from_ascii_to_u8(String::from("00000000")); + /// //assert_eq!(bp.calculate_birtday_paradox_expecting_percent_focusing_on_precision(hash.clone(), 0.50), 500); + /// //let hash = Encode::from_ascii_to_u8(String::from("1f9090aae28b8a3dceadf281b0f12828e676c326")); + /// //assert_eq!(hash, vec![49, 102, 57, 48, 57, 48, 97, 97, 101, 50, 56, 98, 56, 97, 51, 100, 99, 101, 97, 100, 102, 50, 56, 49, 98, 48, 102, 49, 50, 56, 50, 56, 101, 54, 55, 54, 99, 51, 50, 54]); + /// //assert_eq!(bp.calculate_birtday_paradox_expecting_percent_focusing_on_precision(hash.clone(), 0.5), 20); + /// ``` + pub fn calculate_birtday_paradox_expecting_percent_focusing_on_precision(&self, hash_to_process: Vec, probability_expectation: f64) -> u64 { + let organized_hash = split_bytes_by_characters_representation(&self.alphabet, hash_to_process); + let iter: usize = organized_hash.len() ; + let alphabet_size = self.alphabet.get_encoding().len(); + + let possibilities: BigFloat; + if organized_hash.len() == 1 { + possibilities = BigFloat::from_usize(iter).unwrap() * BigFloat::from_usize(alphabet_size).unwrap(); + } else { + possibilities = BigFloat::from_usize(iter).unwrap().pow(BigFloat::from_usize(alphabet_size).unwrap()); + } + + let mut i = 0; + let probability_expectation: BigFloat = BigFloat::from_f64(probability_expectation); + let mut c = BigFloat::from_f64(1.0); + while c > BigFloat::from_f64(1.0)-probability_expectation { + c *= ((possibilities.clone()) - BigFloat::from(i as u32)) / possibilities.clone(); + i += 1; + } + + i as u64 + } + + /// Calculate Birthday Paradox from hash in order to get number of attempts to try to get `probability_expectation` percent of chance of finding a colision. Focus on speed. + /// + /// Method to get the percent of chance to get a collision to on a hash. + /// Take the len of the hash, + /// Does not convert byte array to representation yet. + /// + /// ``` + /// use cryptatools_core::cryptanalysis::general_cryptanalysis_methods::frequency_analysis::coincidence_index::CoincidenceIndexGuesser; + /// use cryptatools_core::cryptanalysis::general_cryptanalysis_methods::hash_cryptanalysis::birthday_paradox::BirtdayParadox; + /// use cryptatools_core::utils::alphabets::Alphabet; + /// use cryptatools_core::utils::convert::Encode; + /// + /// let lowercase_hexadecimal = Alphabet::new_empty().hexadecimal_ascii_lowercase_sixteen_bits_alphabet(); + /// let mut bp = BirtdayParadox::new(lowercase_hexadecimal.into()); + /// let hash = Encode::from_ascii_to_u8(String::from("bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0w")); + /// assert_eq!(hash, vec![98, 99, 49, 113, 120, 121, 50, 107, 103, 100, 121, 103, 106, 114, 115, 113, 116, 122, 113, 50, 110, 48, 121, 114, 102, 50, 52, 57, 51, 112, 56, 51, 107, 107, 102, 106, 104, 120, 48, 119]); + /// assert_eq!(bp.calculate_birtday_paradox_expecting_percent_focusing_on_speed_with_taylor(hash.clone(), 0.50), 1.4234013764919992e24);// should be exactly + /// ``` + pub fn calculate_birtday_paradox_expecting_percent_focusing_on_speed_with_taylor(&self, hash_to_process: Vec, probability_expectation: f64) -> f64 { + let alphabet_size = self.alphabet.get_encoding().len(); + let hash_output_bytes_len: u32 = hash_to_process.len().clone() as u32; + + let bits = BigFloat::from_usize(alphabet_size).unwrap() + .pow(BigFloat::from_u32(hash_output_bytes_len)); + + let probability = BigFloat::from_f64(probability_expectation); + let days_in_year = bits; + + ((BigFloat::from(-2) * days_in_year * (BigFloat::one() - probability).ln()).sqrt()).to_f64() + } + + + pub fn calculate_birtday_paradox(&self, objects: u64, times: u64) -> u64 { + self.calculate_permuted_choice_number(objects, times) / times + } + + /// Calculate the number of possible choices of `objects` objects chosen `times` times. + /// + /// Amount of combination you could do at maximum if you have `times` attempts to try. Choose `objects` choices. + /// The permuted choice method ignore when two choices are identical in a different order. Example: (1,2) has only one permuted choice because (1,2) and (2,1) are the same amount of choice in a different order. + /// It is not a simple multiplication of two object. + /// "`times` choose `objects`". + /// + /// arguments: + /// - `times`: number of attempts to try + /// - `object`: number of stuff to choose between + /// + /// Returns: the number of possible choices. + /// + /// ``` + /// use cryptatools_core::cryptanalysis::general_cryptanalysis_methods::frequency_analysis::coincidence_index::CoincidenceIndexGuesser; + /// use cryptatools_core::utils::alphabets::Alphabet; + /// use cryptatools_core::utils::convert::Encode; + /// use cryptatools_core::cryptanalysis::general_cryptanalysis_methods::hash_cryptanalysis::birthday_paradox::BirtdayParadox; + /// + /// let ascii_alphabet = Alphabet::new_empty().ascii_printable_only_encoding(); + /// let bp = BirtdayParadox::new(ascii_alphabet.into()); + /// assert_eq!(bp.calculate_permuted_choice_number(5, 2), 10); + /// assert_eq!(bp.calculate_permuted_choice_number(2, 2), 1); + /// ``` + pub fn calculate_permuted_choice_number(&self, objects: u64, times: u64) -> u64 { + self.factorial(objects) / (self.factorial(objects - times) * self.factorial(times)) + } + + /// Get number factorial. + /// + /// ``` + /// use cryptatools_core::cryptanalysis::general_cryptanalysis_methods::frequency_analysis::coincidence_index::CoincidenceIndexGuesser; + /// use cryptatools_core::utils::alphabets::Alphabet; + /// use cryptatools_core::utils::convert::Encode; + /// use cryptatools_core::cryptanalysis::general_cryptanalysis_methods::hash_cryptanalysis::birthday_paradox::BirtdayParadox; + /// + /// let ascii_alphabet = Alphabet::new_empty().ascii_printable_only_encoding(); + /// let bp = BirtdayParadox::new(ascii_alphabet.into()); + /// assert_eq!(bp.factorial(0), 1); + /// assert_eq!(bp.factorial(1), 1); + /// assert_eq!(bp.factorial(2), 2); + /// assert_eq!(bp.factorial(3), 6); + ///``` + pub fn factorial(&self, number: u64) -> u64 { + if number == 0 { + return 1; + } + + (1..=number).product() + } } \ No newline at end of file diff --git a/cryptatools-core/src/utils/alphabets.rs b/cryptatools-core/src/utils/alphabets.rs index d92d406147..f3953db1c8 100644 --- a/cryptatools-core/src/utils/alphabets.rs +++ b/cryptatools-core/src/utils/alphabets.rs @@ -1,5 +1,7 @@ +#![feature(assert_matches)] use itertools::Itertools; use bimap::btree::BiBTreeMap; +//use std::assert_matches::assert_matches; ///``` /// use cryptatools_core::utils::{convert::Encode, alphabets::split_bytes_by_characters_representation, alphabets::Alphabet}; @@ -34,6 +36,8 @@ pub const PRINTABLE: &'static str = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFG //pub const ASCII_ALPHABET: &'static str = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\\u128"; pub const UU_ENCODING_ALPHABET: &'static str = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`"; +#[derive(PartialEq, Eq)] +#[derive(Debug)] #[derive(Clone)] pub struct Encoding { pub str: String, @@ -386,9 +390,539 @@ impl Alphabet { } } + + /// Full Hexadecimal (0x00-0xff) + /// + /// Use this alphabet if you are working on hash because the hash are often hexadecimal. The alphabet is from hex string to the corresponding ascii value in hex byte value. + /// + /// This method has no argument. + /// Returns an alphabet made with hexadecimal and lowercase only values. + pub fn full_hexadecimal_alphabet(&mut self) -> Self { + let mut encoding = BiBTreeMap::new(); + encoding.insert(String::from("00"), vec![0x00]); + encoding.insert(String::from("01"), vec![0x01]); + encoding.insert(String::from("02"), vec![0x02]); + encoding.insert(String::from("03"), vec![0x03]); + encoding.insert(String::from("04"), vec![0x04]); + encoding.insert(String::from("05"), vec![0x05]); + encoding.insert(String::from("06"), vec![0x06]); + encoding.insert(String::from("07"), vec![0x07]); + encoding.insert(String::from("08"), vec![0x08]); + encoding.insert(String::from("09"), vec![0x09]); + encoding.insert(String::from("0a"), vec![0x0a]); + encoding.insert(String::from("0b"), vec![0x0b]); + encoding.insert(String::from("0c"), vec![0x0c]); + encoding.insert(String::from("0d"), vec![0x0d]); + encoding.insert(String::from("0e"), vec![0x0e]); + encoding.insert(String::from("0f"), vec![0x0f]); + + encoding.insert(String::from("10"), vec![0x10]); + encoding.insert(String::from("11"), vec![0x11]); + encoding.insert(String::from("12"), vec![0x12]); + encoding.insert(String::from("13"), vec![0x13]); + encoding.insert(String::from("14"), vec![0x14]); + encoding.insert(String::from("15"), vec![0x15]); + encoding.insert(String::from("16"), vec![0x16]); + encoding.insert(String::from("17"), vec![0x17]); + encoding.insert(String::from("18"), vec![0x18]); + encoding.insert(String::from("19"), vec![0x19]); + encoding.insert(String::from("1a"), vec![0x1a]); + encoding.insert(String::from("1b"), vec![0x1b]); + encoding.insert(String::from("1c"), vec![0x1c]); + encoding.insert(String::from("1d"), vec![0x1d]); + encoding.insert(String::from("1e"), vec![0x1e]); + encoding.insert(String::from("1f"), vec![0x1f]); + + encoding.insert(String::from("20"), vec![0x20]); + encoding.insert(String::from("21"), vec![0x21]); + encoding.insert(String::from("22"), vec![0x22]); + encoding.insert(String::from("23"), vec![0x23]); + encoding.insert(String::from("24"), vec![0x24]); + encoding.insert(String::from("25"), vec![0x25]); + encoding.insert(String::from("26"), vec![0x26]); + encoding.insert(String::from("27"), vec![0x27]); + encoding.insert(String::from("28"), vec![0x28]); + encoding.insert(String::from("29"), vec![0x29]); + encoding.insert(String::from("2a"), vec![0x2a]); + encoding.insert(String::from("2b"), vec![0x2b]); + encoding.insert(String::from("2c"), vec![0x2c]); + encoding.insert(String::from("2d"), vec![0x2d]); + encoding.insert(String::from("2e"), vec![0x2e]); + encoding.insert(String::from("2f"), vec![0x2f]); + + encoding.insert(String::from("30"), vec![0x30]); + encoding.insert(String::from("31"), vec![0x31]); + encoding.insert(String::from("32"), vec![0x32]); + encoding.insert(String::from("33"), vec![0x33]); + encoding.insert(String::from("34"), vec![0x34]); + encoding.insert(String::from("35"), vec![0x35]); + encoding.insert(String::from("36"), vec![0x36]); + encoding.insert(String::from("37"), vec![0x37]); + encoding.insert(String::from("38"), vec![0x38]); + encoding.insert(String::from("39"), vec![0x39]); + encoding.insert(String::from("3a"), vec![0x3a]); + encoding.insert(String::from("3b"), vec![0x3b]); + encoding.insert(String::from("3c"), vec![0x3c]); + encoding.insert(String::from("3d"), vec![0x3d]); + encoding.insert(String::from("3e"), vec![0x3e]); + encoding.insert(String::from("3f"), vec![0x3f]); + + encoding.insert(String::from("40"), vec![0x40]); + encoding.insert(String::from("41"), vec![0x41]); + encoding.insert(String::from("42"), vec![0x42]); + encoding.insert(String::from("43"), vec![0x43]); + encoding.insert(String::from("44"), vec![0x44]); + encoding.insert(String::from("45"), vec![0x45]); + encoding.insert(String::from("46"), vec![0x46]); + encoding.insert(String::from("47"), vec![0x47]); + encoding.insert(String::from("48"), vec![0x48]); + encoding.insert(String::from("49"), vec![0x49]); + encoding.insert(String::from("4a"), vec![0x4a]); + encoding.insert(String::from("4b"), vec![0x4b]); + encoding.insert(String::from("4c"), vec![0x4c]); + encoding.insert(String::from("4d"), vec![0x4d]); + encoding.insert(String::from("4e"), vec![0x4e]); + encoding.insert(String::from("4f"), vec![0x4f]); + + encoding.insert(String::from("50"), vec![0x50]); + encoding.insert(String::from("51"), vec![0x51]); + encoding.insert(String::from("52"), vec![0x52]); + encoding.insert(String::from("53"), vec![0x53]); + encoding.insert(String::from("54"), vec![0x54]); + encoding.insert(String::from("55"), vec![0x55]); + encoding.insert(String::from("56"), vec![0x56]); + encoding.insert(String::from("57"), vec![0x57]); + encoding.insert(String::from("58"), vec![0x58]); + encoding.insert(String::from("59"), vec![0x59]); + encoding.insert(String::from("5a"), vec![0x5a]); + encoding.insert(String::from("5b"), vec![0x5b]); + encoding.insert(String::from("5c"), vec![0x5c]); + encoding.insert(String::from("5d"), vec![0x5d]); + encoding.insert(String::from("5e"), vec![0x5e]); + encoding.insert(String::from("5f"), vec![0x5f]); + + encoding.insert(String::from("60"), vec![0x60]); + encoding.insert(String::from("61"), vec![0x61]); + encoding.insert(String::from("62"), vec![0x62]); + encoding.insert(String::from("63"), vec![0x63]); + encoding.insert(String::from("64"), vec![0x64]); + encoding.insert(String::from("65"), vec![0x65]); + encoding.insert(String::from("66"), vec![0x66]); + encoding.insert(String::from("67"), vec![0x67]); + encoding.insert(String::from("68"), vec![0x68]); + encoding.insert(String::from("69"), vec![0x69]); + encoding.insert(String::from("6a"), vec![0x6a]); + encoding.insert(String::from("6b"), vec![0x6b]); + encoding.insert(String::from("6c"), vec![0x6c]); + encoding.insert(String::from("6d"), vec![0x6d]); + encoding.insert(String::from("6e"), vec![0x6e]); + encoding.insert(String::from("6f"), vec![0x6f]); + + encoding.insert(String::from("70"), vec![0x70]); + encoding.insert(String::from("71"), vec![0x71]); + encoding.insert(String::from("72"), vec![0x72]); + encoding.insert(String::from("73"), vec![0x73]); + encoding.insert(String::from("74"), vec![0x74]); + encoding.insert(String::from("75"), vec![0x75]); + encoding.insert(String::from("76"), vec![0x76]); + encoding.insert(String::from("77"), vec![0x77]); + encoding.insert(String::from("78"), vec![0x78]); + encoding.insert(String::from("79"), vec![0x79]); + encoding.insert(String::from("7a"), vec![0x7a]); + encoding.insert(String::from("7b"), vec![0x7b]); + encoding.insert(String::from("7c"), vec![0x7c]); + encoding.insert(String::from("7d"), vec![0x7d]); + encoding.insert(String::from("7e"), vec![0x7e]); + encoding.insert(String::from("7f"), vec![0x7f]); + + encoding.insert(String::from("80"), vec![0x80]); + encoding.insert(String::from("81"), vec![0x81]); + encoding.insert(String::from("82"), vec![0x82]); + encoding.insert(String::from("83"), vec![0x83]); + encoding.insert(String::from("84"), vec![0x84]); + encoding.insert(String::from("85"), vec![0x85]); + encoding.insert(String::from("86"), vec![0x86]); + encoding.insert(String::from("87"), vec![0x87]); + encoding.insert(String::from("88"), vec![0x88]); + encoding.insert(String::from("89"), vec![0x89]); + encoding.insert(String::from("8a"), vec![0x8a]); + encoding.insert(String::from("8b"), vec![0x8b]); + encoding.insert(String::from("8c"), vec![0x8c]); + encoding.insert(String::from("8d"), vec![0x8d]); + encoding.insert(String::from("8e"), vec![0x8e]); + encoding.insert(String::from("8f"), vec![0x8f]); + + encoding.insert(String::from("90"), vec![0x90]); + encoding.insert(String::from("91"), vec![0x91]); + encoding.insert(String::from("92"), vec![0x92]); + encoding.insert(String::from("93"), vec![0x93]); + encoding.insert(String::from("94"), vec![0x94]); + encoding.insert(String::from("95"), vec![0x95]); + encoding.insert(String::from("96"), vec![0x96]); + encoding.insert(String::from("97"), vec![0x97]); + encoding.insert(String::from("98"), vec![0x98]); + encoding.insert(String::from("99"), vec![0x99]); + encoding.insert(String::from("9a"), vec![0x9a]); + encoding.insert(String::from("9b"), vec![0x9b]); + encoding.insert(String::from("9c"), vec![0x9c]); + encoding.insert(String::from("9d"), vec![0x9d]); + encoding.insert(String::from("9e"), vec![0x9e]); + encoding.insert(String::from("9f"), vec![0x9f]); + + encoding.insert(String::from("a0"), vec![0xa0]); + encoding.insert(String::from("a1"), vec![0xa1]); + encoding.insert(String::from("a2"), vec![0xa2]); + encoding.insert(String::from("a3"), vec![0xa3]); + encoding.insert(String::from("a4"), vec![0xa4]); + encoding.insert(String::from("a5"), vec![0xa5]); + encoding.insert(String::from("a6"), vec![0xa6]); + encoding.insert(String::from("a7"), vec![0xa7]); + encoding.insert(String::from("a8"), vec![0xa8]); + encoding.insert(String::from("a9"), vec![0xa9]); + encoding.insert(String::from("aa"), vec![0xaa]); + encoding.insert(String::from("ab"), vec![0xab]); + encoding.insert(String::from("ac"), vec![0xac]); + encoding.insert(String::from("ad"), vec![0xad]); + encoding.insert(String::from("ae"), vec![0xae]); + encoding.insert(String::from("af"), vec![0xaf]); + + encoding.insert(String::from("b0"), vec![0xb0]); + encoding.insert(String::from("b1"), vec![0xb1]); + encoding.insert(String::from("b2"), vec![0xb2]); + encoding.insert(String::from("b3"), vec![0xb3]); + encoding.insert(String::from("b4"), vec![0xb4]); + encoding.insert(String::from("b5"), vec![0xb5]); + encoding.insert(String::from("b6"), vec![0xb6]); + encoding.insert(String::from("b7"), vec![0xb7]); + encoding.insert(String::from("b8"), vec![0xb8]); + encoding.insert(String::from("b9"), vec![0xb9]); + encoding.insert(String::from("ba"), vec![0xba]); + encoding.insert(String::from("bb"), vec![0xbb]); + encoding.insert(String::from("bc"), vec![0xbc]); + encoding.insert(String::from("bd"), vec![0xbd]); + encoding.insert(String::from("be"), vec![0xbe]); + encoding.insert(String::from("bf"), vec![0xbf]); + + encoding.insert(String::from("c0"), vec![0xc0]); + encoding.insert(String::from("c1"), vec![0xc1]); + encoding.insert(String::from("c2"), vec![0xc2]); + encoding.insert(String::from("c3"), vec![0xc3]); + encoding.insert(String::from("c4"), vec![0xc4]); + encoding.insert(String::from("c5"), vec![0xc5]); + encoding.insert(String::from("c6"), vec![0xc6]); + encoding.insert(String::from("c7"), vec![0xc7]); + encoding.insert(String::from("c8"), vec![0xc8]); + encoding.insert(String::from("c9"), vec![0xc9]); + encoding.insert(String::from("ca"), vec![0xca]); + encoding.insert(String::from("cb"), vec![0xcb]); + encoding.insert(String::from("cc"), vec![0xcc]); + encoding.insert(String::from("cd"), vec![0xcd]); + encoding.insert(String::from("ce"), vec![0xce]); + encoding.insert(String::from("cf"), vec![0xcf]); + + encoding.insert(String::from("d0"), vec![0xd0]); + encoding.insert(String::from("d1"), vec![0xd1]); + encoding.insert(String::from("d2"), vec![0xd2]); + encoding.insert(String::from("d3"), vec![0xd3]); + encoding.insert(String::from("d4"), vec![0xd4]); + encoding.insert(String::from("d5"), vec![0xd5]); + encoding.insert(String::from("d6"), vec![0xd6]); + encoding.insert(String::from("d7"), vec![0xd7]); + encoding.insert(String::from("d8"), vec![0xd8]); + encoding.insert(String::from("d9"), vec![0xd9]); + encoding.insert(String::from("da"), vec![0xda]); + encoding.insert(String::from("db"), vec![0xdb]); + encoding.insert(String::from("dc"), vec![0xdc]); + encoding.insert(String::from("dd"), vec![0xdd]); + encoding.insert(String::from("de"), vec![0xde]); + encoding.insert(String::from("df"), vec![0xdf]); + + encoding.insert(String::from("e0"), vec![0xe0]); + encoding.insert(String::from("e1"), vec![0xe1]); + encoding.insert(String::from("e2"), vec![0xe2]); + encoding.insert(String::from("e3"), vec![0xe3]); + encoding.insert(String::from("e4"), vec![0xe4]); + encoding.insert(String::from("e5"), vec![0xe5]); + encoding.insert(String::from("e6"), vec![0xe6]); + encoding.insert(String::from("e7"), vec![0xe7]); + encoding.insert(String::from("e8"), vec![0xe8]); + encoding.insert(String::from("e9"), vec![0xe9]); + encoding.insert(String::from("ea"), vec![0xea]); + encoding.insert(String::from("eb"), vec![0xeb]); + encoding.insert(String::from("ec"), vec![0xec]); + encoding.insert(String::from("ed"), vec![0xed]); + encoding.insert(String::from("ee"), vec![0xee]); + encoding.insert(String::from("ef"), vec![0xef]); + + encoding.insert(String::from("f0"), vec![0xf0]); + encoding.insert(String::from("f1"), vec![0xf1]); + encoding.insert(String::from("f2"), vec![0xf2]); + encoding.insert(String::from("f3"), vec![0xf3]); + encoding.insert(String::from("f4"), vec![0xf4]); + encoding.insert(String::from("f5"), vec![0xf5]); + encoding.insert(String::from("f6"), vec![0xf6]); + encoding.insert(String::from("f7"), vec![0xf7]); + encoding.insert(String::from("f8"), vec![0xf8]); + encoding.insert(String::from("f9"), vec![0xf9]); + encoding.insert(String::from("fa"), vec![0xfa]); + encoding.insert(String::from("fb"), vec![0xfb]); + encoding.insert(String::from("fc"), vec![0xfc]); + encoding.insert(String::from("fd"), vec![0xfd]); + encoding.insert(String::from("fe"), vec![0xfe]); + encoding.insert(String::from("ff"), vec![0xff]); + + self.encoding = encoding.clone(); + + Alphabet { + encoding: encoding + } + } + + + + /// Ascii lowercase hexadecimal alphabet + /// + /// Use this alphabet if you are working on hash because the hash are often hexadecimal. The alphabet is from hex string to the corresponding ascii value in hex byte value. + /// + /// This method has no argument. + /// Returns an alphabet made with hexadecimal and lowercase only values. + pub fn hexadecimal_ascii_lowercase_sixteen_bits_alphabet(&mut self) -> Self { + let mut encoding = BiBTreeMap::new(); + encoding.insert(String::from("0"), vec![0x30]); + encoding.insert(String::from("1"), vec![0x31]); + encoding.insert(String::from("2"), vec![0x32]); + encoding.insert(String::from("3"), vec![0x33]); + encoding.insert(String::from("4"), vec![0x34]); + encoding.insert(String::from("5"), vec![0x35]); + encoding.insert(String::from("6"), vec![0x36]); + encoding.insert(String::from("7"), vec![0x37]); + encoding.insert(String::from("8"), vec![0x38]); + encoding.insert(String::from("9"), vec![0x39]); + encoding.insert(String::from("a"), vec![0x61]); + encoding.insert(String::from("b"), vec![0x62]); + encoding.insert(String::from("c"), vec![0x63]); + encoding.insert(String::from("d"), vec![0x64]); + encoding.insert(String::from("e"), vec![0x65]); + encoding.insert(String::from("f"), vec![0x66]); + + self.encoding = encoding.clone(); + + Alphabet { + encoding: encoding + } + } + + + /// Extended ascii alphabet. + /// + /// Contains 256 values of ascii character. + /// This is the default alphabet that you should use when working on networking packets, program file or assembly language. + /// + /// This method has no argument. + /// Returns an alphabet made with extended ascii values.. + pub fn extended_ascii_encoding(&mut self) -> Self { + let mut encoding = BiBTreeMap::new(); + encoding.insert(String::from("\x00"), vec![0x00]); + encoding.insert(String::from("\x01"), vec![0x01]); + encoding.insert(String::from("\x02"), vec![0x02]); + encoding.insert(String::from("\x03"), vec![0x03]); + encoding.insert(String::from("\x04"), vec![0x04]); + encoding.insert(String::from("\x05"), vec![0x05]); + encoding.insert(String::from("\x06"), vec![0x06]); + encoding.insert(String::from("\x07"), vec![0x07]); + encoding.insert(String::from("\x08"), vec![0x08]); + encoding.insert(String::from("\x09"), vec![0x09]); + encoding.insert(String::from("\x0a"), vec![0x0a]); + encoding.insert(String::from("\x0b"), vec![0x0b]); + encoding.insert(String::from("\x0c"), vec![0x0c]); + encoding.insert(String::from("\x0d"), vec![0x0d]); + encoding.insert(String::from("\x0e"), vec![0x0e]); + encoding.insert(String::from("\x0f"), vec![0x0f]); + encoding.insert(String::from("\x10"), vec![0x10]); + encoding.insert(String::from("\x11"), vec![0x11]); + encoding.insert(String::from("\x12"), vec![0x12]); + encoding.insert(String::from("\x13"), vec![0x13]); + encoding.insert(String::from("\x14"), vec![0x14]); + encoding.insert(String::from("\x15"), vec![0x15]); + encoding.insert(String::from("\x16"), vec![0x16]); + encoding.insert(String::from("\x17"), vec![0x17]); + encoding.insert(String::from("\x18"), vec![0x18]); + encoding.insert(String::from("\x19"), vec![0x19]); + encoding.insert(String::from("\x1a"), vec![0x1a]); + encoding.insert(String::from("\x1b"), vec![0x1b]); + encoding.insert(String::from("\x1c"), vec![0x1c]); + encoding.insert(String::from("\x1d"), vec![0x1d]); + encoding.insert(String::from("\x1e"), vec![0x1e]); + encoding.insert(String::from("\x1f"), vec![0x1f]); + encoding.insert(String::from(" "), vec![0x20]); + encoding.insert(String::from("!"), vec![0x21]); + encoding.insert(String::from("\""), vec![0x22]); + encoding.insert(String::from("#"), vec![0x23]); + encoding.insert(String::from("$"), vec![0x24]); + encoding.insert(String::from("%"), vec![0x25]); + encoding.insert(String::from("&"), vec![0x26]); + encoding.insert(String::from("'"), vec![0x27]); + encoding.insert(String::from("("), vec![0x28]); + encoding.insert(String::from(")"), vec![0x29]); + encoding.insert(String::from("*"), vec![0x2a]); + encoding.insert(String::from("+"), vec![0x2b]); + encoding.insert(String::from(","), vec![0x2c]); + encoding.insert(String::from("-"), vec![0x2d]); + encoding.insert(String::from("."), vec![0x2e]); + encoding.insert(String::from("/"), vec![0x2f]); + encoding.insert(String::from("0"), vec![0x30]); + encoding.insert(String::from("1"), vec![0x31]); + encoding.insert(String::from("2"), vec![0x32]); + encoding.insert(String::from("3"), vec![0x33]); + encoding.insert(String::from("4"), vec![0x34]); + encoding.insert(String::from("5"), vec![0x35]); + encoding.insert(String::from("6"), vec![0x36]); + encoding.insert(String::from("7"), vec![0x37]); + encoding.insert(String::from("8"), vec![0x38]); + encoding.insert(String::from("9"), vec![0x39]); + encoding.insert(String::from(":"), vec![0x3a]); + encoding.insert(String::from(";"), vec![0x3b]); + encoding.insert(String::from("<"), vec![0x3c]); + encoding.insert(String::from("="), vec![0x3d]); + encoding.insert(String::from(">"), vec![0x3e]); + encoding.insert(String::from("?"), vec![0x3f]); + encoding.insert(String::from("@"), vec![0x40]); + encoding.insert(String::from("A"), vec![0x41]); + encoding.insert(String::from("B"), vec![0x42]); + encoding.insert(String::from("C"), vec![0x43]); + encoding.insert(String::from("D"), vec![0x44]); + encoding.insert(String::from("E"), vec![0x45]); + encoding.insert(String::from("F"), vec![0x46]); + encoding.insert(String::from("G"), vec![0x47]); + encoding.insert(String::from("H"), vec![0x48]); + encoding.insert(String::from("I"), vec![0x49]); + encoding.insert(String::from("J"), vec![0x4a]); + encoding.insert(String::from("K"), vec![0x4b]); + encoding.insert(String::from("L"), vec![0x4c]); + encoding.insert(String::from("M"), vec![0x4d]); + encoding.insert(String::from("N"), vec![0x4e]); + encoding.insert(String::from("O"), vec![0x4f]); + encoding.insert(String::from("P"), vec![0x50]); + encoding.insert(String::from("Q"), vec![0x51]); + encoding.insert(String::from("R"), vec![0x52]); + encoding.insert(String::from("S"), vec![0x53]); + encoding.insert(String::from("T"), vec![0x54]); + encoding.insert(String::from("U"), vec![0x55]); + encoding.insert(String::from("V"), vec![0x56]); + encoding.insert(String::from("W"), vec![0x57]); + encoding.insert(String::from("X"), vec![0x58]); + encoding.insert(String::from("Y"), vec![0x59]); + encoding.insert(String::from("Z"), vec![0x5a]); + encoding.insert(String::from("["), vec![0x5b]); + encoding.insert(String::from("\\"), vec![0x5c]); + encoding.insert(String::from("]"), vec![0x5d]); + encoding.insert(String::from("^"), vec![0x5e]); + encoding.insert(String::from("_"), vec![0x5f]); + encoding.insert(String::from("`"), vec![0x60]); + encoding.insert(String::from("a"), vec![0x61]); + encoding.insert(String::from("b"), vec![0x62]); + encoding.insert(String::from("c"), vec![0x63]); + encoding.insert(String::from("d"), vec![0x64]); + encoding.insert(String::from("e"), vec![0x65]); + encoding.insert(String::from("f"), vec![0x66]); + encoding.insert(String::from("g"), vec![0x67]); + encoding.insert(String::from("h"), vec![0x68]); + encoding.insert(String::from("i"), vec![0x69]); + encoding.insert(String::from("j"), vec![0x6a]); + encoding.insert(String::from("k"), vec![0x6b]); + encoding.insert(String::from("l"), vec![0x6c]); + encoding.insert(String::from("m"), vec![0x6d]); + encoding.insert(String::from("n"), vec![0x6e]); + encoding.insert(String::from("o"), vec![0x6f]); + encoding.insert(String::from("p"), vec![0x70]); + encoding.insert(String::from("q"), vec![0x71]); + encoding.insert(String::from("r"), vec![0x72]); + encoding.insert(String::from("s"), vec![0x73]); + encoding.insert(String::from("t"), vec![0x74]); + encoding.insert(String::from("u"), vec![0x75]); + encoding.insert(String::from("v"), vec![0x76]); + encoding.insert(String::from("w"), vec![0x77]); + encoding.insert(String::from("x"), vec![0x78]); + encoding.insert(String::from("y"), vec![0x79]); + encoding.insert(String::from("z"), vec![0x7a]); + encoding.insert(String::from("{"), vec![0x7b]); + encoding.insert(String::from("|"), vec![0x7c]); + encoding.insert(String::from("}"), vec![0x7d]); + encoding.insert(String::from("~"), vec![0x7e]); + encoding.insert(String::from("\x7f"), vec![0x7f]); + encoding.insert(String::from("€"), vec![0x80]);//\\u128 + + + self.encoding = encoding.clone(); + + Alphabet { + encoding: encoding + } + } + + + + + + + + + + + pub fn get_encoding(&self) -> Vec { self.encoding.iter() .map(|(str, bytes)| Encoding { str: str.clone(), bytes: bytes.clone() }) .collect_vec() } -} \ No newline at end of file + + /// Convert opcodes to an human readable set of characters text in the same order as the original unconverted text. + /// + /// Once deciphered in plain characters, a cryptographic algorithm still need to be seen in a decodable format. This is why this method returns a Vector of `Encoded` struct. + /// + /// paramaters: + /// - encoding: opcode vector to convert to a set of character. + /// + /// Returns: a converted human readable set of character text in the same order as the original unconverted text. + /// + /// ``` + /// #![feature(assert_matches)] + /// + /// use std::assert_matches::assert_matches; + /// use cryptatools_core::utils::{convert::Encode, alphabets::split_bytes_by_characters_representation, alphabets::Alphabet}; + /// use cryptatools_core::utils::alphabets::Encoding; + /// + /// + /// let ascii_alphabet = Alphabet::new_empty().ascii_encoding(); + /// let alph = ascii_alphabet.decode(vec![0x41, 0x41, 0x42, 0x42]); + /// let decoded = vec![Encoding{str: String::from("A"), bytes: vec![0x41]}, Encoding{str: String::from("A"), bytes: vec![0x41]}, Encoding{str: String::from("B"), bytes: vec![0x42]}, Encoding{str: String::from("B"), bytes: vec![0x42]}]; + /// assert_eq!(alph, decoded); + /// ``` + pub fn decode(&self, encoded: Vec) -> Vec { + let mut alway_iterate = 0; + let mut iterate_foreach_character_decoded = 0; + let mut out: Vec = vec![]; + while iterate_foreach_character_decoded < encoded.len() { + let part: Vec = encoded[iterate_foreach_character_decoded..alway_iterate].to_vec(); + match self.encoding.contains_right(&part) { + true => { + let decoded = self.encoding.get_by_right(&part); + out.push(Encoding{str: String::from(decoded.unwrap()), + bytes: part}); + iterate_foreach_character_decoded += 1; + }, + false => { + + } + } + alway_iterate += 1; + } + + out + } +} + +/* +let decoded = encoded[j..i].into_iter().map(|e| (e.str, e.bytes)) + .collect::>(); +*/ \ No newline at end of file diff --git a/doc-examples/ethereum-colision-evaluation/Cargo.toml b/doc-examples/ethereum-colision-evaluation/Cargo.toml new file mode 100644 index 0000000000..19c24a026e --- /dev/null +++ b/doc-examples/ethereum-colision-evaluation/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "ethereum-colision-evaluation" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +ethers = { version = "*", features = ["ws"] } +tokio = { version = "1", features = ["macros", "rt", "rt-multi-thread"] } +eyre = "0.6" +cryptatools-core = { path = "../../cryptatools-core", package = 'cryptatools-core' } +#cryptatools-core = { git = "https://github.com/gogo2464/cryptatools-rs", package = 'cryptatools-core' } \ No newline at end of file diff --git a/doc-examples/ethereum-colision-evaluation/src/main.rs b/doc-examples/ethereum-colision-evaluation/src/main.rs new file mode 100644 index 0000000000..4b643c46f3 --- /dev/null +++ b/doc-examples/ethereum-colision-evaluation/src/main.rs @@ -0,0 +1,31 @@ +use ethers::prelude::*; + +use cryptatools_core::utils::{convert::Encode, alphabets::split_bytes_by_characters_representation, alphabets::Alphabet, alphabets::Encoding}; +use cryptatools_core::cryptanalysis::general_cryptanalysis_methods::frequency_analysis::coincidence_index::CoincidenceIndexGuesser; +use cryptatools_core::cryptanalysis::general_cryptanalysis_methods::hash_cryptanalysis::birthday_paradox::BirtdayParadox; + +const WSS_URL: &str = "wss://mainnet.infura.io/ws/v3/c60b0bb42f8a4c6481ecd229eddaca27"; + +#[tokio::main] +async fn main() -> eyre::Result<()> { + let hexadecimal_alphabet = Alphabet::new_empty().full_hexadecimal_alphabet(); + let bp = BirtdayParadox::new(hexadecimal_alphabet.into()); + + let provider = Provider::::connect(WSS_URL).await?; + let mut stream = provider.subscribe_blocks().await?.take(1); + let mut wallet_block: Option> = None; + while let Some(block) = stream.next().await { + if let Some(author) = block.author { + wallet_block = Some(author.0.to_vec()); + } + } + + if let Some(wallet_block) = wallet_block { + let target_hash = wallet_block; + println!("After {:?} attempts, there is 50% of chances to get a collision on ethereum addresses.", bp.calculate_birtday_paradox_expecting_percent_focusing_on_speed_with_taylor(target_hash.clone(), 0.50)); + } else { + println!("Error: wallet not found. Check your internet connection."); + } + + Ok(()) +} \ No newline at end of file diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 2b206dcf5c..16207f32a4 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -13,7 +13,13 @@ # II - How To -- [Use cryptanalysis attack method against a caesar encryption shellcode shellcode for Malware analysis with cryptatools and radare2 rust bindings (r2pipe)](./chapter_2/1-caesar_shellcode_cryptanalysis_attack.md) +# 1. Cryptanalysis for Reverse engineering and malware analysis + +- [Using Cryptanalysis Attack Method Against A Caesar Encryption Shellcode Shellcode For Malware Analysis With Cryptatools And Radare2 Rust Bindings (r2pipe)](./chapter_2/1-caesar_shellcode_cryptanalysis_attack.md) + +# 2. Blockchain and cryptocurrencies cryptanalysis + +- [Cryptography Of Bitcoin Address Using Birthday Paradox](./chapter_2/Blockchain/1-Evaluating-bitcoin-wallet-collision-probability.md) # III - API Ref diff --git a/docs/src/chapter_2/Blockchain/1-Evaluating-bitcoin-wallet-collision-probability.md b/docs/src/chapter_2/Blockchain/1-Evaluating-bitcoin-wallet-collision-probability.md new file mode 100644 index 0000000000..4f9b91c867 --- /dev/null +++ b/docs/src/chapter_2/Blockchain/1-Evaluating-bitcoin-wallet-collision-probability.md @@ -0,0 +1,133 @@ +## Evaluating Ethereum address collision probabilities with birthday paradox method using ether-rs and cryptatools-rs + +# I - Intro And Challenges + +# 1. Intro + +Ethereum is a decentralized cryptocurrency. Each people has his own wallet authenticated with a public/private keyset. As ethereum is decentralized, if someone create the adress of somebody else, then he will be able to spoof his identity. Hopefully addresses are random, then we need to create a lot of identities. + +But how many identities do we need to create? A paper at this address [here](https://download.wpsoftware.net/bitcoin-birthday.pdf) has already answered to this question. + +Today we are going to implement a cryptanalys attack with `cryptatools` to automatically know the attempts required instead of calculating manually. + +# 2. Challenges And Terms + +In the origin, the Birtday Paradox Attack is an attack where the attackant wants to check if the has output is tall enough hash output in order to find collision using pure brute force. +It is effective in web2 hashing algorithm in order to know if collision are possible on hash algorithm. +This attack supposes that the hash output generation is purely perfectly random. Tough this methd seems very very brute, the birtday paradox uses math probabilities in order to evaluate if a hash outpute is long enough. + +Today we are going to implement a birtday paradox evalution on bitcoin cryptocurrency using cryptatools-rs, we are able to use birtday paradox, not in order to run hash attack but to evalutate how many time we will need to try in order to have 50% of chances to reach a collision between two wallets. + +# II let's do it + +# 1. Fecthing A Random Author Adress + +We need to fetch a random hash in order to check if the hash is strong enough. We will use the library `ether-rs`: + +```rust +use ethers::prelude::*; +``` + +then let's use it in order to really fetch the block: + +```rust +use ethers::prelude::*; + +const WSS_URL: &str = "wss://mainnet.infura.io/ws/v3/c60b0bb42f8a4c6481ecd229eddaca27"; + +#[tokio::main] +async fn main() -> eyre::Result<()> { + let provider = Provider::::connect(WSS_URL).await?; + let mut stream = provider.subscribe_blocks().await?.take(1); + let mut wallet_block: Option> = None; + while let Some(block) = stream.next().await { + if let Some(author) = block.author { + wallet_block = Some(author.0.to_vec()); + + println!("random hash author: {:?}", author); + } + } + + Ok(()) +} +``` + +# 2. Configuring cryptatools-rs + + +In `cryptatools-rs`, the alphabet is a concept that applies not only for letters but also to any format. We need to tells cryptatools-rs to use hexadecimal alphabet because it will calculate the length in bits of the alphabet in order to occur the birthday paradox with the right number of bits. + +We need to select the alphabet. We will use `full_hexadecimal_alphabet` struct because it is a struct that contains 255 values. + +```rust +let hexadecimal_alphabet = Alphabet::new_empty().full_hexadecimal_alphabet(); +let mut bp = BirtdayParadox::new(hexadecimal_alphabet.into()); +``` + +Now we will need to call the method `calculate_birtday_paradox_expecting_percent_focusing_on_speed_with_taylor`. + +This is a method that is speed enough to be calculated on more than let's say 10 characters hash. This is sadly less precise than the method `calculate_birtday_paradox_expecting_percent_focusing_on_precision` that we will not user here. + +Let's write: + +```rust +bp.calculate_birtday_paradox_expecting_percent_focusing_on_speed_with_taylor(target_hash.clone(), 0.50) +``` + +in + +```rust +use ethers::prelude::*; + +use cryptatools_core::utils::{convert::Encode, alphabets::split_bytes_by_characters_representation, alphabets::Alphabet, alphabets::Encoding}; +use cryptatools_core::cryptanalysis::general_cryptanalysis_methods::frequency_analysis::coincidence_index::CoincidenceIndexGuesser; +use cryptatools_core::cryptanalysis::general_cryptanalysis_methods::hash_cryptanalysis::birthday_paradox::BirtdayParadox; + +const WSS_URL: &str = "wss://mainnet.infura.io/ws/v3/c60b0bb42f8a4c6481ecd229eddaca27"; + +#[tokio::main] +async fn main() -> eyre::Result<()> { + let hexadecimal_alphabet = Alphabet::new_empty().full_hexadecimal_alphabet(); + let bp = BirtdayParadox::new(hexadecimal_alphabet.into()); + + let provider = Provider::::connect(WSS_URL).await?; + let mut stream = provider.subscribe_blocks().await?.take(1); + let mut wallet_block: Option> = None; + while let Some(block) = stream.next().await { + if let Some(author) = block.author { + wallet_block = Some(author.0.to_vec()); + } + } + + if let Some(wallet_block) = wallet_block { + let target_hash = wallet_block; + println!("after {:?} attempts, there is 50% of chances to get a collision on ethereum addresses.", bp.calculate_birtday_paradox_expecting_percent_focusing_on_speed_with_taylor(target_hash.clone(), 0.50)); + } else { + println!("Error: wallet not found. Check your internet connection."); + } + + Ok(()) +} +``` + +# 4. Running a Birtday paradox evaluation. + +In the paper they mentionned: +``` +For e = 50%, this gives n = 1.41 × 10^24. +``` + +Let's run... +``` +After 1.4234013764919992e24 attempts, there is 50% of chances to get a collision on ethereum addresses. +``` + +Sounds perfect! It is exactly the same answer than the paper! + +Of course there is a difference of 0.01e24 but the birthday paradox is an approximation. + +# Conclusion + +ethereum wallet hash and alphabet length provide same resistance as the bitcoin. + +We do not have to worry about the probability to find a wallet collision. It is very safe! \ No newline at end of file