Без опису
Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. extern crate sha2;
  2. extern crate time;
  3. #[cfg(feature = "SHA2")]
  4. use self::sha2::Sha256;
  5. use std::thread;
  6. use std::sync::Arc;
  7. use std::sync::atomic::AtomicBool;
  8. use std::sync::atomic::Ordering::Relaxed;
  9. use std::sync::mpsc::{Sender, channel};
  10. use time::{Duration, get_time};
  11. pub struct Sha256;
  12. pub trait Hasher {
  13. type Output: HashResult;
  14. fn hash(input: &[u8]) -> Self::Output;
  15. }
  16. pub trait HashResult {
  17. /// Get the output in hex notation.
  18. fn hex(&self) -> String;
  19. /// Size of the output in bytes.
  20. fn size() -> usize;
  21. }
  22. impl Hasher for Sha256 {
  23. type Output = [u8; 32];
  24. fn hash(input: &[u8]) -> Self::Output {
  25. use self::sha2::*;
  26. let mut tmp = Sha256::new();
  27. tmp.input(input);
  28. let r = tmp.result().as_slice().to_vec();
  29. [
  30. r[0],
  31. r[1],
  32. r[2],
  33. r[3],
  34. r[4],
  35. r[5],
  36. r[6],
  37. r[7],
  38. r[8],
  39. r[9],
  40. r[10],
  41. r[11],
  42. r[12],
  43. r[13],
  44. r[14],
  45. r[15],
  46. r[16],
  47. r[17],
  48. r[18],
  49. r[19],
  50. r[20],
  51. r[21],
  52. r[22],
  53. r[23],
  54. r[24],
  55. r[25],
  56. r[26],
  57. r[27],
  58. r[28],
  59. r[29],
  60. r[30],
  61. r[31],
  62. ]
  63. }
  64. }
  65. impl HashResult for [u8; 32] {
  66. fn hex(&self) -> String {
  67. const HEX: [char; 16] = [
  68. '0',
  69. '1',
  70. '2',
  71. '3',
  72. '4',
  73. '5',
  74. '6',
  75. '7',
  76. '8',
  77. '9',
  78. 'a',
  79. 'b',
  80. 'c',
  81. 'd',
  82. 'e',
  83. 'f',
  84. ];
  85. let mut tmp = String::with_capacity(32 * 2);
  86. for byte in self.iter() {
  87. tmp.push(HEX[*byte as usize / 16]);
  88. tmp.push(HEX[*byte as usize % 16]);
  89. }
  90. tmp
  91. }
  92. fn size() -> usize {
  93. 32
  94. }
  95. }
  96. #[derive(Debug, PartialEq)]
  97. pub struct Solution {
  98. pub number: usize,
  99. pub hash: String,
  100. }
  101. /// Überprüft ob *base* und *number* auf einen Hash abbilden,
  102. /// der mit der übergebenen *difficulty* übereinstimmt.
  103. /// Falls ja, kommt eine `Solution` in der Option mit den Ergebnissen zurück.
  104. /// Falls nein, steht None im Optional
  105. pub fn verify_product(base: usize, number: usize, difficulty: &String) -> Option<Solution> {
  106. let sol = base * number;
  107. let input = sol.to_string();
  108. let bytes = input.as_bytes();
  109. let hash = Sha256::hash(bytes).hex();
  110. if hash.ends_with(difficulty) {
  111. return Some(Solution {
  112. number: number,
  113. hash: hash,
  114. });
  115. }
  116. None
  117. }
  118. /// Sucht nach einem Hash für die angegebene Basis und die Schwierigkeit.
  119. /// Wenn `total` > 1 ist, dann hat jeder Aufruf mit einem anderen `start`-Wert (von 0 - total)
  120. /// eine disjunkte Zahlenmenge für die Suche zur Auswahl.
  121. fn search_hash(
  122. hash: &String,
  123. base: usize,
  124. start: usize,
  125. total: usize,
  126. sync: bool,
  127. found: Arc<AtomicBool>,
  128. special: usize,
  129. solution_tx: Sender<Solution>,
  130. timing_tx: Sender<(Duration, usize)>,
  131. measure: bool,
  132. ) {
  133. let max = <usize>::max_value();
  134. let mut n = start;
  135. let thread_start = get_time();
  136. while n < max {
  137. // Der special Parameter begrenzt die Anzahl der load()-Aufrufe auf jeden n.ten Loop.
  138. if n % special == 0 && found.load(Relaxed) {
  139. // Anderer Thread hat eine Lösung gefunden (sync ist aktiviert). Beende Suche.
  140. break;
  141. }
  142. if let Some(solution) = verify_product(base, n, hash) {
  143. if sync {
  144. found.store(true, Relaxed);
  145. }
  146. // Sende gefundene Solution an den Consumer.
  147. let _ = solution_tx.send(solution);
  148. // Beende Suche.
  149. break;
  150. }
  151. n += total;
  152. }
  153. // Falls measure aktiviert ist Sende Zeitdauer und Anzahl Loops an den Consumer.
  154. if measure {
  155. let thread_end = get_time();
  156. let _ = timing_tx.send((thread_end - thread_start, (n / total)));
  157. }
  158. }
  159. /// Teilt, wenn nötig, die Suche nach dem Hash auf mehrere Threads auf.
  160. /// Gibt ggf. die Solution (für die Tests) zurück.
  161. pub fn search_with_threads(
  162. threads: usize,
  163. diff_string: String,
  164. with_base: usize,
  165. time_measurement: bool,
  166. verbosity: u64,
  167. sync: Option<usize>,
  168. wait: bool,
  169. ) -> Option<Solution> {
  170. let diff = Arc::new(diff_string);
  171. let mut children = vec![];
  172. let mut solution = None;
  173. let (solution_tx, solution_rx) = channel();
  174. let (timing_tx, timing_rx) = channel();
  175. let found = Arc::new(AtomicBool::new(false));
  176. let m = time_measurement && verbosity > 0;
  177. let total_start = get_time();
  178. if threads > 1 {
  179. if verbosity > 0 {
  180. println!("Searching with {} threads", threads);
  181. }
  182. // Erstellt Anzahl angeforderter Threads.
  183. // Klont für jeden Thread die Referenz auf die gemeinsamen Variablen.
  184. for i in 0..threads {
  185. let diff = diff.clone();
  186. let solution_tx = solution_tx.clone();
  187. let timing_tx = timing_tx.clone();
  188. let found = found.clone();
  189. children.push(thread::spawn(move || {
  190. // Suche in jedem der Threads.
  191. search_hash(
  192. &diff,
  193. with_base,
  194. i,
  195. threads,
  196. sync.is_some(),
  197. found,
  198. sync.unwrap_or(1),
  199. solution_tx,
  200. timing_tx,
  201. m,
  202. );
  203. if verbosity > 1 {
  204. println!("[DEBUG] Thread {} exited", i);
  205. }
  206. }));
  207. }
  208. } else {
  209. // Suche auf dem Main-Thread.
  210. search_hash(
  211. &diff,
  212. with_base,
  213. 0,
  214. 1,
  215. sync.is_some(),
  216. found,
  217. sync.unwrap_or(1),
  218. solution_tx,
  219. timing_tx,
  220. m,
  221. );
  222. if verbosity > 1 {
  223. println!("[DEBUG] Finished search on main thread.");
  224. }
  225. }
  226. // Empfängt die Lösung von einem der Producer.
  227. match solution_rx.recv() {
  228. Ok(sol) => {
  229. solution = Some(Solution {
  230. number: sol.number,
  231. hash: sol.hash.clone(),
  232. });
  233. let total_end = get_time();
  234. println!("Number: {} --> hash: {}", sol.number, sol.hash);
  235. if time_measurement && verbosity == 0 {
  236. let diff = total_end - total_start;
  237. let s = diff.num_seconds();
  238. let ms = diff.num_milliseconds();
  239. let us = diff.num_microseconds().unwrap_or(ms * 1000);
  240. println!("(Duration {}s / {}ms / {}us)", s, ms, us);
  241. }
  242. }
  243. Err(_) => {}
  244. }
  245. let mut sum_loops = 0usize;
  246. let mut sum_time: Duration = Duration::zero();
  247. for child in children {
  248. if time_measurement && verbosity > 0 {
  249. // Warte auf Zeitstatistik-Nachricht von jedem Thread auf dem zweiten MPSC Channel.
  250. if let Ok(stats) = timing_rx.recv() {
  251. // Addiere Werte dieses threads zu der Summe.
  252. sum_time = sum_time + stats.0;
  253. sum_loops += stats.1;
  254. }
  255. }
  256. // Falls *wait* wahr ist, warte auf aktuellen thread (child)
  257. if wait {
  258. let _ = child.join();
  259. }
  260. }
  261. // Gebe die Gesamtergebnisse der Threads aus.
  262. if time_measurement && verbosity > 0 {
  263. println!("Sum Loops in Producers: {}", sum_loops);
  264. let s = sum_time.num_seconds();
  265. let ms = sum_time.num_milliseconds();
  266. let us = sum_time.num_microseconds().unwrap_or(ms * 1000);
  267. println!("Sum Duration in Producers: {}s / {}ms / {}us", s, ms, us);
  268. }
  269. // Gebe die Option einer Solution zurück.
  270. solution
  271. }