I found this far more awkward to write than the Python or C version. I use a python script (at the bottom) to generate the constants, rather than doing that in Rust. ### main.rs ```rust #![allow(dead_code)] #![allow(unused_variables)] mod sha256_consts; use sha256_consts::*; // sha256 hasher state const BLOCK_SIZE : usize = 512 / 8; #[derive(Copy)] struct StateVector { h : [u32 ; 8] } impl Clone for StateVector { fn clone(&self) -> StateVector { return StateVector { h: self.h.clone() } } } #[derive(Copy)] pub struct Sha256 { state : StateVector, end_of_buffer : usize, length_so_far : usize, buffer : [u8; BLOCK_SIZE], } impl Clone for Sha256 { fn clone(&self) -> Sha256 { return Sha256 { state: self.state, buffer: self.buffer, end_of_buffer: self.end_of_buffer, length_so_far: self.length_so_far, } } } #[inline(always)] fn from_be_bytes(a: u8, b:u8, c:u8, d:u8) -> u32 { return (d as u32) + ((c as u32) << 8) + ((b as u32) << 16) + ((a as u32) << 24); } #[inline(always)] fn sizeof(x : T) -> usize { return std::mem::size_of::(); } #[inline(always)] fn rotr(x : u32, n : u32) -> u32 { return x.rotate_right(n) } impl Sha256 { pub fn new() -> Sha256 { return Sha256 { state: StateVector { h: I.clone() }, buffer: [0; BLOCK_SIZE], end_of_buffer: 0, length_so_far: 0 } } pub fn print_state(&self) { println!("{}",self.hex()); } pub fn update(&mut self, bytes : &[u8]) -> &mut Sha256 { let remaining_space = BLOCK_SIZE - self.end_of_buffer; let bytes_length = bytes.len(); if remaining_space > bytes_length { // bytes will fit in existing buffer let ptr = &mut self.buffer[BLOCK_SIZE-remaining_space.. BLOCK_SIZE-remaining_space+bytes.len()]; ptr.clone_from_slice(&bytes[0..bytes_length]); self.length_so_far += bytes_length; self.end_of_buffer += bytes_length; } else { { let ptr = &mut self.buffer[BLOCK_SIZE - remaining_space.. BLOCK_SIZE]; ptr.clone_from_slice(&bytes[0..remaining_space]); } self.end_of_buffer = 0; self.length_so_far += remaining_space; self.compute_block(None); let total_blocks = (bytes_length - remaining_space) / BLOCK_SIZE; for i in 0..total_blocks { let start_index = i*BLOCK_SIZE + remaining_space; self.compute_block(Some(&bytes[start_index..start_index+BLOCK_SIZE])); self.length_so_far += BLOCK_SIZE; } let leftover = (bytes_length - remaining_space) % BLOCK_SIZE; let buffer_ptr = &mut self.buffer[0..leftover]; buffer_ptr.clone_from_slice(&bytes[bytes_length-leftover..bytes_length]); self.end_of_buffer += leftover; self.length_so_far += leftover; } return self } fn finalize(&mut self) -> &mut Sha256 { // add padding let remaining_space = BLOCK_SIZE - self.end_of_buffer; let total_bits : u64 = (self.length_so_far as u64) * 8; let end_of_buffer = self.end_of_buffer; if remaining_space < 9 && remaining_space > 0 { // pad buffer, compute block, // pad with zeros and append size big endian self.buffer[end_of_buffer] = 0x80; for i in (end_of_buffer+1)..(BLOCK_SIZE) { self.buffer[i] = 0x00; } self.compute_block(None); for i in 0..(BLOCK_SIZE-8) { self.buffer[i] = 0x00; } for i in 0..8 { self.buffer[BLOCK_SIZE-1-i] = (total_bits >> 8*i) as u8; } self.compute_block(None); } else { self.buffer[end_of_buffer] = 0x80; for i in (end_of_buffer+1)..(BLOCK_SIZE-8) { self.buffer[i] = 0x00; } for i in 0..8 { self.buffer[BLOCK_SIZE-1-i] = (total_bits >> 8*i) as u8; } self.compute_block(None); } return self; } fn compute_block(&mut self, input : Option<&[u8]>) { let data : &[u8] = match input { Some(a) => a, None => &self.buffer }; let mut w : [u32 ; 64] = [0 ; 64]; for i in 0..(data.len() / 4) { w[i] = from_be_bytes(data[i*4],data[i*4+1],data[i*4+2],data[i*4+3]); } for i in (data.len() / 4)..64 { let s0 : u32 = rotr( w[i-15], 7 ) ^ rotr( w[i-15], 18 ) ^ (w[i-15] >> 3); let s1 : u32 = rotr( w[i-2], 17 ) ^ rotr( w[i-2], 19 ) ^ (w[i-2] >> 10); w[i] = w[i-16].wrapping_add(s0).wrapping_add(w[i-7]).wrapping_add(s1); } let mut a = self.state.h[0]; let mut b = self.state.h[1]; let mut c = self.state.h[2]; let mut d = self.state.h[3]; let mut e = self.state.h[4]; let mut f = self.state.h[5]; let mut g = self.state.h[6]; let mut h = self.state.h[7]; for i in 0..64 { let s1 : u32 = rotr(e,6) ^ rotr(e,11) ^ rotr(e,25); let ch : u32 = (e & f) ^ ((!e) & g); let t1 : u32 = h.wrapping_add(s1).wrapping_add(ch).wrapping_add(K[i]).wrapping_add(w[i]); let s0 : u32 = rotr(a,2) ^ rotr(a,13) ^ rotr(a,22); let maj : u32 = (a & b) ^ (b & c) ^ (c & a); let t2 : u32 = s0.wrapping_add(maj); h = g; g = f; f = e; e = d.wrapping_add(t1); d = c; c = b; b = a; a = t1.wrapping_add(t2); } self.state.h[0] = self.state.h[0].wrapping_add(a); self.state.h[1] = self.state.h[1].wrapping_add(b); self.state.h[2] = self.state.h[2].wrapping_add(c); self.state.h[3] = self.state.h[3].wrapping_add(d); self.state.h[4] = self.state.h[4].wrapping_add(e); self.state.h[5] = self.state.h[5].wrapping_add(f); self.state.h[6] = self.state.h[6].wrapping_add(g); self.state.h[7] = self.state.h[7].wrapping_add(h); } fn hex(&self) -> String { let mut x : String = String::new(); for i in 0..8 { x += &format!("{:08x}",self.state.h[i]).to_string(); } return x; } fn dump(&self) { println!("Length: {}",self.length_so_far); } } use std::env; use std::fs::File; use std::io::{self,BufReader,BufRead}; fn sha_file(file : BufReader,filename : String) -> io::Result<()> { const CAP : usize = 4096; let mut reader = BufReader::with_capacity(CAP,file); let mut sha = Sha256::new(); loop { let length = { let buffer = reader.fill_buf()?; sha.update(buffer as &[u8]); buffer.len() }; if length == 0 { break; } reader.consume(length); } sha.finalize(); println!("{} *{}",sha.hex(),filename); io::Result::Ok(()) } fn error_file(error : io::Error,filename : String) -> io::Result<()> { println!("Error with file '{}': {}",filename,error); io::Result::Err(error) } fn main() { let args: Vec = env::args().collect(); for i in 1..args.len() { let arg = &args[i]; let file = File::open(arg); match file { Ok(file) => sha_file(BufReader::new(file),arg.to_string()), Err(error) => error_file(error,arg.to_string()) }.ok(); } } ``` ### sha256_consts.rs ```rust pub const I : [u32 ; 8] = [ 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19 ]; pub const 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 ]; ``` ### consts.py ```python #!/usr/bin/env python3 import math ofn = "src/consts.rsi" # generate constants for sha256 def isprime(x): for i in range(2,int(1+x**0.5)): if x % i == 0: return False return True def tofrac(x): f = x - math.floor(x) g = f * 2**32 h = int(g) return h def gen_consts(): a = list(filter(isprime,range(2,312)))[:64] b = a[:8] I = list(map(lambda t: tofrac(t**(1/2)),b)) K = list(map(lambda t: tofrac(t**(1/3)),a)) return (I,K) I,K = gen_consts() def print_consts(ty,name,vals): n = len(vals) print(f"const {name} : [{ty} ; {n}] = [") for i,val in enumerate(vals): if i