lang/rust/ HomePage


Rustup

To get rust up and running on Linux:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

SHA256

I like to use SHA256 as an exercise in learning a language. Rust made it far more fiddly than C or Python. Here is my source, first main.rs:

#![allow(dead_code)]
#![allow(unused_variables)]

// Code for doing the hashing -- see below for the sha256 constants file.
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<T>(x : T) -> usize {
  return std::mem::size_of::<T>();
}
#[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
      //println!("Nearly full block");
      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 {
      //println!("Not nearly full block");
      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;
      }
      /*
      for i in 0..BLOCK_SIZE {
        print!("{:02x}",self.buffer[i]);
      }
      println!("");
      */
      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);
  }
}

// Driver program that emulates sha256sum in behaviour
use std::env;
use std::fs;
use std::fs::File;
use std::io::BufReader;
fn sha_file(file : BufReader<File>,filename : String) {
  const CAP : usize = 4096;
  //let data = file.read();
  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.update(&data as &[u8]);
  sha.finalize();
  println!("{} *{}",sha.hex(),filename);
}
fn error_file(error : std::io::Error,filename : String) {
  println!("Error with file '{}': {}",filename,error);
}
fn main() {
  let args: Vec<String> = 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())
    };
    let data = fs::read(arg).expect("Unable to read file");
    let mut sha = Sha256::new();
    sha.update(&data as &[u8]);
    sha.finalize();
    println!("{} *{}",sha.hex(),arg);
    //sha.dump();
  }
}

and sha256_consts.rs

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
];