| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- extern crate sha2;
- extern crate time;
-
- #[cfg(feature = "SHA2")]
- use self::sha2::Sha256;
- use std::thread;
- use std::sync::Arc;
- use std::sync::atomic::AtomicBool;
- use std::sync::atomic::Ordering::Relaxed;
- use std::sync::mpsc::{Sender, channel};
- use time::{Duration, get_time};
-
-
- pub struct Sha256;
-
- pub trait Hasher {
- type Output: HashResult;
- fn hash(input: &[u8]) -> Self::Output;
- }
-
- pub trait HashResult {
- /// Get the output in hex notation.
- fn hex(&self) -> String;
- /// Size of the output in bytes.
- fn size() -> usize;
- }
-
- impl Hasher for Sha256 {
- type Output = [u8; 32];
-
- fn hash(input: &[u8]) -> Self::Output {
- use self::sha2::*;
- let mut tmp = Sha256::new();
- tmp.input(input);
- let r = tmp.result().as_slice().to_vec();
- [
- r[0],
- r[1],
- r[2],
- r[3],
- r[4],
- r[5],
- r[6],
- r[7],
- r[8],
- r[9],
- r[10],
- r[11],
- r[12],
- r[13],
- r[14],
- r[15],
- r[16],
- r[17],
- r[18],
- r[19],
- r[20],
- r[21],
- r[22],
- r[23],
- r[24],
- r[25],
- r[26],
- r[27],
- r[28],
- r[29],
- r[30],
- r[31],
- ]
- }
- }
-
- impl HashResult for [u8; 32] {
- fn hex(&self) -> String {
- const HEX: [char; 16] = [
- '0',
- '1',
- '2',
- '3',
- '4',
- '5',
- '6',
- '7',
- '8',
- '9',
- 'a',
- 'b',
- 'c',
- 'd',
- 'e',
- 'f',
- ];
- let mut tmp = String::with_capacity(32 * 2);
- for byte in self.iter() {
- tmp.push(HEX[*byte as usize / 16]);
- tmp.push(HEX[*byte as usize % 16]);
- }
- tmp
- }
-
- fn size() -> usize {
- 32
- }
- }
-
- #[derive(Debug, PartialEq)]
- pub struct Solution {
- pub number: usize,
- pub hash: String,
- }
-
- /// Überprüft ob *base* und *number* auf einen Hash abbilden,
- /// der mit der übergebenen *difficulty* übereinstimmt.
- /// Falls ja, kommt eine `Solution` in der Option mit den Ergebnissen zurück.
- /// Falls nein, steht None im Optional
- pub fn verify_product(base: usize, number: usize, difficulty: &String) -> Option<Solution> {
- let sol = base * number;
- let input = sol.to_string();
- let bytes = input.as_bytes();
-
- let hash = Sha256::hash(bytes).hex();
-
- if hash.ends_with(difficulty) {
- return Some(Solution {
- number: number,
- hash: hash,
- });
- }
-
- None
- }
-
- /// Sucht nach einem Hash für die angegebene Basis und die Schwierigkeit.
- /// Wenn `total` > 1 ist, dann hat jeder Aufruf mit einem anderen `start`-Wert (von 0 - total)
- /// eine disjunkte Zahlenmenge für die Suche zur Auswahl.
- fn search_hash(
- hash: &String,
- base: usize,
- start: usize,
- total: usize,
- sync: bool,
- found: Arc<AtomicBool>,
- special: usize,
- solution_tx: Sender<Solution>,
- timing_tx: Sender<(Duration, usize)>,
- measure: bool,
- ) {
- let max = <usize>::max_value();
- let mut n = start;
-
- let thread_start = get_time();
- while n < max {
-
- // Der special Parameter begrenzt die Anzahl der load()-Aufrufe auf jeden n.ten Loop.
- if n % special == 0 && found.load(Relaxed) {
- // Anderer Thread hat eine Lösung gefunden (sync ist aktiviert). Beende Suche.
- break;
- }
-
- if let Some(solution) = verify_product(base, n, hash) {
- if sync {
- found.store(true, Relaxed);
- }
- // Sende gefundene Solution an den Consumer.
- let _ = solution_tx.send(solution);
- // Beende Suche.
- break;
- }
- n += total;
- }
-
- // Falls measure aktiviert ist Sende Zeitdauer und Anzahl Loops an den Consumer.
- if measure {
- let thread_end = get_time();
- let _ = timing_tx.send((thread_end - thread_start, (n / total)));
- }
- }
-
- /// Teilt, wenn nötig, die Suche nach dem Hash auf mehrere Threads auf.
- /// Gibt ggf. die Solution (für die Tests) zurück.
- pub fn search_with_threads(
- threads: usize,
- diff_string: String,
- with_base: usize,
- time_measurement: bool,
- verbosity: u64,
- sync: Option<usize>,
- wait: bool,
- ) -> Option<Solution> {
-
- let diff = Arc::new(diff_string);
- let mut children = vec![];
- let mut solution = None;
-
- let (solution_tx, solution_rx) = channel();
- let (timing_tx, timing_rx) = channel();
-
- let found = Arc::new(AtomicBool::new(false));
- let m = time_measurement && verbosity > 0;
-
- let total_start = get_time();
- if threads > 1 {
-
- if verbosity > 0 {
- println!("Searching with {} threads", threads);
- }
-
- // Erstellt Anzahl angeforderter Threads.
- // Klont für jeden Thread die Referenz auf die gemeinsamen Variablen.
- for i in 0..threads {
- let diff = diff.clone();
- let solution_tx = solution_tx.clone();
- let timing_tx = timing_tx.clone();
- let found = found.clone();
-
- children.push(thread::spawn(move || {
-
- // Suche in jedem der Threads.
- search_hash(
- &diff,
- with_base,
- i,
- threads,
- sync.is_some(),
- found,
- sync.unwrap_or(1),
- solution_tx,
- timing_tx,
- m,
- );
-
- if verbosity > 1 {
- println!("[DEBUG] Thread {} exited", i);
- }
- }));
- }
- } else {
- // Suche auf dem Main-Thread.
- search_hash(
- &diff,
- with_base,
- 0,
- 1,
- sync.is_some(),
- found,
- sync.unwrap_or(1),
- solution_tx,
- timing_tx,
- m,
- );
-
- if verbosity > 1 {
- println!("[DEBUG] Finished search on main thread.");
- }
- }
-
- // Empfängt die Lösung von einem der Producer.
- match solution_rx.recv() {
- Ok(sol) => {
- solution = Some(Solution {
- number: sol.number,
- hash: sol.hash.clone(),
- });
- let total_end = get_time();
- println!("Number: {} --> hash: {}", sol.number, sol.hash);
- if time_measurement && verbosity == 0 {
- let diff = total_end - total_start;
- let s = diff.num_seconds();
- let ms = diff.num_milliseconds();
- let us = diff.num_microseconds().unwrap_or(ms * 1000);
- println!("(Duration {}s / {}ms / {}us)", s, ms, us);
- }
- }
- Err(_) => {}
- }
-
- let mut sum_loops = 0usize;
- let mut sum_time: Duration = Duration::zero();
-
- for child in children {
-
- if time_measurement && verbosity > 0 {
- // Warte auf Zeitstatistik-Nachricht von jedem Thread auf dem zweiten MPSC Channel.
- if let Ok(stats) = timing_rx.recv() {
- // Addiere Werte dieses threads zu der Summe.
- sum_time = sum_time + stats.0;
- sum_loops += stats.1;
- }
- }
-
- // Falls *wait* wahr ist, warte auf aktuellen thread (child)
- if wait {
- let _ = child.join();
- }
- }
-
- // Gebe die Gesamtergebnisse der Threads aus.
- if time_measurement && verbosity > 0 {
- println!("Sum Loops in Producers: {}", sum_loops);
- let s = sum_time.num_seconds();
- let ms = sum_time.num_milliseconds();
- let us = sum_time.num_microseconds().unwrap_or(ms * 1000);
- println!("Sum Duration in Producers: {}s / {}ms / {}us", s, ms, us);
- }
-
- // Gebe die Option einer Solution zurück.
- solution
- }
|