Skip to content

Commit

Permalink
balloon outline
Browse files Browse the repository at this point in the history
  • Loading branch information
SymmetricChaos committed Jan 5, 2025
1 parent 2405728 commit dd6e751
Show file tree
Hide file tree
Showing 5 changed files with 191 additions and 2 deletions.
136 changes: 136 additions & 0 deletions hashers/src/balloon.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// https://eprint.iacr.org/2016/027.pdf

use std::ops::Range;

use crate::{
sha::{Sha2_256, Sha2_512},
traits::StatefulHasher,
};

// pub enum BalloonVariant {
// Sha256,
// Sha512,
// }

// impl BalloonVariant {
// pub fn blocksize(&self) -> usize {
// match self {
// BalloonVariant::Sha256 => 32,
// BalloonVariant::Sha512 => 64,
// }
// }

// pub fn init(&self) -> Box<dyn StatefulHasher> {
// match self {
// BalloonVariant::Sha256 => Box::new(Sha2_256::init()),
// BalloonVariant::Sha512 => Box::new(Sha2_512::init()),
// }
// }
// }

pub struct Balloon {
// variant: BalloonVariant,
m_cost: u64,
t_cost: u64,
salt: Vec<u8>,
buffer: Vec<u8>,
}

impl Balloon {
const BLOCKSIZE: usize = 32; // for SHA256
const DELTA: u64 = 3;

fn extract_block(n: usize, blocks: &[u8]) -> &[u8] {
&blocks[n * Self::BLOCKSIZE..][..Self::BLOCKSIZE]
}

fn extract_block_mut(n: usize, blocks: &mut [u8]) -> &mut [u8] {
&mut blocks[n * Self::BLOCKSIZE..][..Self::BLOCKSIZE]
}

fn extract_range(n: usize) -> Range<usize> {
(n * Self::BLOCKSIZE)..(n * Self::BLOCKSIZE + Self::BLOCKSIZE)
}

pub fn init(t_cost: u64, m_cost: u64, salt: &[u8]) -> Self {
Self {
// variant,
m_cost,
t_cost,
salt: salt.to_vec(),
buffer: Vec::new(),
}
}

fn total_memory(&self) -> usize {
self.m_cost as usize * Self::BLOCKSIZE
}
}

impl StatefulHasher for Balloon {
fn update(&mut self, bytes: &[u8]) {
self.buffer.extend_from_slice(bytes);
}

fn finalize(self) -> Vec<u8> {
let mut ctr: u64 = 0;
let mut blocks: Vec<u8> = Vec::with_capacity(self.total_memory());
// Step 1. Expand input into buffer
let mut h = Sha2_256::init();
h.update(&ctr.to_le_bytes());
ctr += 1;
h.update(&self.buffer);
h.update(&self.salt);
blocks.extend(h.finalize_and_reset());

for i in 1..self.m_cost as usize {
h.update(&ctr.to_le_bytes());
ctr += 1;
h.update(&Self::extract_block(i, &blocks));
blocks.extend(h.finalize_and_reset());
}

// Step 2. Mix buffer contents
for _t in 0..self.t_cost as usize {
for m in 0..self.m_cost as usize {
// Step 2a. Hash last and current blocks
let p = if m == 0 {
(self.m_cost - 1) as usize
} else {
m - 1 as usize
};
h.update(&ctr.to_le_bytes());
ctr += 1;
h.update(&blocks[Self::extract_range(p)]);
h.update(&blocks[Self::extract_range(m)]);
blocks[Self::extract_range(m)].copy_from_slice(&h.finalize_and_reset());

// Step 2b. Hash in pseudorandom blocks
for i in 0..Self::DELTA {
h.update(&self.t_cost.to_le_bytes());
h.update(&(m as u64).to_le_bytes());
h.update(&i.to_le_bytes());
let idx_block = h.finalize_and_reset();

h.update(&ctr.to_le_bytes());
ctr += 1;
h.update(&self.salt);
h.update(&idx_block);
let other = h.finalize_and_reset(); // convert to an integer
let other: usize = todo!();

h.update(&ctr.to_le_bytes());
ctr += 1;
h.update(&blocks[Self::extract_range(m)]);
h.update(&blocks[Self::extract_range(other)]);
blocks[Self::extract_range(m)].copy_from_slice(&h.finalize_and_reset());
}
}
}

// Step 3. Extract output
blocks[Self::extract_range((self.m_cost - 1) as usize)].to_vec()
}

crate::stateful_hash_helpers!();
}
2 changes: 1 addition & 1 deletion hashers/src/ids/hasher_descriptions.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"Adler-32": {
"Description": "Adler-32 is a very fast an simple hash, usually classified as a checksum. It produces a 32-bit hash by concatenating two 16-bit counters.",
"Description": "Adler-32 is a very fast a simple hash, usually classified as a checksum. It produces a 32-bit hash by concatenating two 16-bit counters.",
"Authors": "Mark Adler",
"Publication": "1995",
"Hash Length": 32,
Expand Down
3 changes: 2 additions & 1 deletion hashers/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub mod adler;
pub mod argon2;
pub mod ascon;
pub mod auxiliary;
pub mod balloon;
pub mod bcrypt;
pub mod belt;
pub mod blake;
Expand Down Expand Up @@ -29,6 +30,7 @@ pub mod pbkdf1;
pub mod pbkdf2;
pub mod pearson;
pub mod poly1305;
pub mod poseidon;
pub mod radio_gatun;
pub mod ripemd;
pub mod scrypt;
Expand All @@ -40,7 +42,6 @@ pub mod sm3;
pub mod tiger;
pub mod traits;
pub mod vsh;
pub mod poseidon;

// Template
// use utils::byte_formatting::ByteFormat;
Expand Down
26 changes: 26 additions & 0 deletions hashers/src/sha/sha256.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,32 @@ macro_rules! sha2_256 {
pub fn init() -> Self {
Self::default()
}

pub fn finalize_and_reset(&mut self) -> Vec<u8> {
self.bits_taken += self.buffer.len() as u64 * 8;
self.buffer.push(0x80);
while (self.buffer.len() % 64) != 56 {
self.buffer.push(0x00)
}
self.buffer.extend(self.bits_taken.to_be_bytes());

// There can be multiple final blocks after padding
for chunk in self.buffer.chunks_exact(64) {
compress(&mut self.state, &chunk);
}

let mut out = self
.state
.iter()
.map(|x| x.to_be_bytes())
.flatten()
.collect_vec();
out.truncate($output_len);

*self = Self::init();

out
}
}

impl StatefulHasher for $name {
Expand Down
26 changes: 26 additions & 0 deletions hashers/src/sha/sha512.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,32 @@ macro_rules! sha2_512 {
pub fn init() -> Self {
Self::default()
}

pub fn finalize_and_reset(&mut self) -> Vec<u8> {
self.bits_taken += self.buffer.len() as u128 * 8;
self.buffer.push(0x80);
while (self.buffer.len() % 128) != 112 {
self.buffer.push(0x00)
}
self.buffer.extend(self.bits_taken.to_be_bytes());

// There can be multiple final blocks after padding
for chunk in self.buffer.chunks_exact(128) {
compress(&mut self.state, &chunk);
}

let mut out = self
.state
.iter()
.map(|x| x.to_be_bytes())
.flatten()
.collect_vec();
out.truncate($output_len);

*self = Self::init();

out
}
}

impl StatefulHasher for $name {
Expand Down

0 comments on commit dd6e751

Please sign in to comment.