-
-
Save rust-play/9a9e2bc7b14841ef918b33532bc02264 to your computer and use it in GitHub Desktop.
Code shared from the Rust Playground
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use std::time::{SystemTime, UNIX_EPOCH, Duration}; | |
| // --- CONSTANTS --- | |
| const SHA256_K: [u32; 64] = [ | |
| 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, | |
| 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, | |
| 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, | |
| 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, | |
| 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, | |
| 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, | |
| 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, | |
| 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, | |
| ]; | |
| // --- SHA-1 (Git-compliant) --- | |
| fn git_sha1(data: &[u8]) -> String { | |
| let mut h0: u32 = 0x67452301; let mut h1: u32 = 0xEFCDAB89; | |
| let mut h2: u32 = 0x98BADCFE; let mut h3: u32 = 0x10325476; | |
| let mut h4: u32 = 0xC3D2E1F0; | |
| let mut padded = data.to_vec(); | |
| let bit_len = (padded.len() as u64) * 8; | |
| padded.push(0x80); | |
| while (padded.len() * 8) % 512 != 448 { padded.push(0); } | |
| padded.extend_from_slice(&bit_len.to_be_bytes()); | |
| for chunk in padded.chunks(64) { | |
| let mut w = [0u32; 80]; | |
| for i in 0..16 { w[i] = u32::from_be_bytes([chunk[i*4], chunk[i*4+1], chunk[i*4+2], chunk[i*4+3]]); } | |
| for i in 16..80 { w[i] = (w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]).rotate_left(1); } | |
| let (mut a, mut b, mut c, mut d, mut e) = (h0, h1, h2, h3, h4); | |
| for i in 0..80 { | |
| let (f, k) = match i { | |
| 0..=19 => ((b & c) | ((!b) & d), 0x5A827999), | |
| 20..=39 => (b ^ c ^ d, 0x6ED9EBA1), | |
| 40..=59 => ((b & c) | (b & d) | (c & d), 0x8F1BBCDC), | |
| _ => (b ^ c ^ d, 0xCA62C1D6), | |
| }; | |
| let temp = a.rotate_left(5).wrapping_add(f).wrapping_add(e).wrapping_add(k).wrapping_add(w[i]); | |
| e = d; d = c; c = b.rotate_left(30); b = a; a = temp; | |
| } | |
| h0 = h0.wrapping_add(a); h1 = h1.wrapping_add(b); | |
| h2 = h2.wrapping_add(c); h3 = h3.wrapping_add(d); h4 = h4.wrapping_add(e); | |
| } | |
| format!("{:08x}{:08x}{:08x}{:08x}{:08x}", h0, h1, h2, h3, h4) | |
| } | |
| // --- SHA-256 --- | |
| fn sha256(data: &[u8]) -> String { | |
| let mut h: [u32; 8] = [0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19]; | |
| let mut padded = data.to_vec(); | |
| let bit_len = (padded.len() as u64) * 8; | |
| padded.push(0x80); | |
| while (padded.len() * 8) % 512 != 448 { padded.push(0); } | |
| padded.extend_from_slice(&bit_len.to_be_bytes()); | |
| for chunk in padded.chunks(64) { | |
| let mut w = [0u32; 64]; | |
| for i in 0..16 { w[i] = u32::from_be_bytes([chunk[i*4], chunk[i*4+1], chunk[i*4+2], chunk[i*4+3]]); } | |
| for i in 16..64 { | |
| let s0 = w[i-15].rotate_right(7) ^ w[i-15].rotate_right(18) ^ (w[i-15] >> 3); | |
| let s1 = w[i-2].rotate_right(17) ^ w[i-2].rotate_right(19) ^ (w[i-2] >> 10); | |
| w[i] = w[i-16].wrapping_add(s0).wrapping_add(w[i-7]).wrapping_add(s1); | |
| } | |
| let [mut a, mut b, mut c, mut d, mut e, mut f, mut g, mut h_val] = h; | |
| for i in 0..64 { | |
| let s1 = e.rotate_right(6) ^ e.rotate_right(11) ^ e.rotate_right(25); | |
| let ch = (e & f) ^ ((!e) & g); | |
| let temp1 = h_val.wrapping_add(s1).wrapping_add(ch).wrapping_add(SHA256_K[i]).wrapping_add(w[i]); | |
| let s0 = a.rotate_right(2) ^ a.rotate_right(13) ^ a.rotate_right(22); | |
| let maj = (a & b) ^ (a & c) ^ (b & c); | |
| let temp2 = s0.wrapping_add(maj); | |
| h_val = g; g = f; f = e; e = d.wrapping_add(temp1); d = c; c = b; b = a; a = temp1.wrapping_add(temp2); | |
| } | |
| h = [h[0].wrapping_add(a), h[1].wrapping_add(b), h[2].wrapping_add(c), h[3].wrapping_add(d), | |
| h[4].wrapping_add(e), h[5].wrapping_add(f), h[6].wrapping_add(g), h[7].wrapping_add(h_val)]; | |
| } | |
| h.iter().map(|x| format!("{:08x}", x)).collect() | |
| } | |
| #[derive(Debug, Clone, Copy, PartialEq, PartialOrd)] | |
| pub enum SyncStage { Hour, Minute, Second, SHA1_1Bit, SHA1_2Bit, SHA256_1Bit } | |
| pub struct SyncNode { | |
| pub id: usize, | |
| pub drift: i64, // seconds offset from system clock | |
| pub stage: SyncStage, | |
| pub nonce: u64, | |
| pub success: bool, | |
| pub last_hash: String, | |
| } | |
| impl SyncNode { | |
| pub fn new(id: usize, offset: i64) -> Self { | |
| Self { id, drift: offset, stage: SyncStage::Hour, nonce: 0, success: false, last_hash: String::new() } | |
| } | |
| fn get_time_data(&self) -> (u64, u32, String) { | |
| let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as i64 + self.drift; | |
| let minute = (now / 60) % 60; | |
| let time_str = format!("{:02}:{:02}:{:02}", (now / 3600) % 24, minute, now % 60); | |
| (now as u64, minute as u32, time_str) | |
| } | |
| pub fn update_stage(&mut self, spread: u64, all_same_min: bool, global_sha1_1: bool, global_sha1_2: bool) { | |
| match self.stage { | |
| SyncStage::Hour => if spread < 3600 { self.stage = SyncStage::Minute; }, | |
| SyncStage::Minute => if spread < 60 { self.stage = SyncStage::Second; }, | |
| SyncStage::Second => if spread == 0 && all_same_min { self.stage = SyncStage::SHA1_1Bit; }, | |
| SyncStage::SHA1_1Bit => if global_sha1_1 { self.stage = SyncStage::SHA1_2Bit; self.success = false; }, | |
| SyncStage::SHA1_2Bit => if global_sha1_2 { self.stage = SyncStage::SHA256_1Bit; self.success = false; }, | |
| _ => {} | |
| } | |
| } | |
| pub fn grind(&mut self) { | |
| let (_, min, _) = self.get_time_data(); | |
| loop { | |
| let input = format!("BLOCK-{}-{}", min, self.nonce); | |
| let hash = match self.stage { | |
| SyncStage::SHA1_1Bit | SyncStage::SHA1_2Bit => git_sha1(input.as_bytes()), | |
| SyncStage::SHA256_1Bit => sha256(input.as_bytes()), | |
| _ => return, | |
| }; | |
| let target = match self.stage { | |
| SyncStage::SHA1_1Bit | SyncStage::SHA256_1Bit => "0", | |
| SyncStage::SHA1_2Bit => "00", | |
| _ => "", | |
| }; | |
| if hash.starts_with(target) { | |
| self.last_hash = hash; self.success = true; break; | |
| } | |
| if self.stage == SyncStage::SHA1_2Bit && hash.starts_with("0") { | |
| self.last_hash = hash; self.nonce += 1; break; // Print the 1-bit hit during 2-bit phase | |
| } | |
| self.nonce += 1; | |
| } | |
| } | |
| } | |
| fn main() { | |
| let mut nodes: Vec<SyncNode> = (0..10).map(|i| SyncNode::new(i, (i as i64 * 5) - 20)).collect(); | |
| for round in 1..2000 { | |
| let data: Vec<_> = nodes.iter().map(|n| n.get_time_data()).collect(); | |
| let timestamps: Vec<u64> = data.iter().map(|d| d.0).collect(); | |
| let spread = timestamps.iter().max().unwrap() - timestamps.iter().min().unwrap(); | |
| let all_same_min = data.iter().all(|d| d.1 == data[0].1); | |
| let g_sha1_1 = nodes.iter().all(|n| n.stage == SyncStage::SHA1_1Bit && n.success); | |
| let g_sha1_2 = nodes.iter().all(|n| n.stage == SyncStage::SHA1_2Bit && n.success); | |
| println!("\n--- [ROUND {:03}] Spread:{}s ---", round, spread); | |
| for i in 0..10 { | |
| nodes[i].update_stage(spread, all_same_min, g_sha1_1, g_sha1_2); | |
| match nodes[i].stage { | |
| SyncStage::Hour | SyncStage::Minute | SyncStage::Second => { | |
| let mut sorted = timestamps.clone(); sorted.sort(); | |
| let median = sorted[5] as i64; | |
| let diff = median - timestamps[i] as i64; | |
| nodes[i].drift += diff.signum(); | |
| }, | |
| _ => if !nodes[i].success { nodes[i].grind(); } | |
| } | |
| let mark = if nodes[i].success { "SOLVED " } else { "WAITING" }; | |
| println!("N{:02}|S:{}|UTC:{}|Nonce:{:<6}|{}|HASH:{}", | |
| i, nodes[i].stage as u8, data[i].2, nodes[i].nonce, mark, nodes[i].last_hash); | |
| } | |
| if nodes.iter().all(|n| n.stage == SyncStage::SHA256_1Bit && n.success) { break; } | |
| std::thread::sleep(Duration::from_millis(10)); | |
| } | |
| println!("\n>>> FINAL CASCADING CONSENSUS ACHIEVED <<<"); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment