The Incredible Hunk

A hunk is a very simple data structure:

#![allow(unused)]
fn main() {
struct Hunk {
    data: [u8; 32]
}
}

It represents 32 bytes of data. This has multiple uses:

  1. It can store a hash.
  2. It can store a private key.
  3. It can store a public key.
  4. It can store a rainbow id.
  5. Probably other things.

However, there are some common operations that are often used.

Hash

The first operation we will look at is hashing an integer. A lookup table would be handy, but does take 32 * 2^32 bytes, or 128 GiB just for this one table.

#![allow(unused)]
fn main() {
impl Hunk {
    pub fn hash(value: u32) -> Hunk {
        Hunk {
            data: blake3::hash(value.to_be_bytes()).into()
        }
    }
}
}

Hunk Hash

One such operation is to hash the Hunk. We call this the hunk_hash, which is simply the blake3 of the Hunk.

#![allow(unused)]
fn main() {
impl Hunk {
    pub fn hunk_hash(&self) -> Hunk {
        Hunk {
          data: blake3::hash(self.data).into()
        )
    }
}
}

Combine

Another operation is to combine two hashes together, to really mix up some bits.

#![allow(unused)]
fn main() {
impl Hunk {
    pub fn combine(&self, other: Hunk) -> Hunk {
        (self ^ other).hunk_hash()
    }
}
}

Make It Rain

And, finally, the star of the show. This is the actual hashing algorithm used by our rainbow tables. We call it raindrop. This will be used for building our chains in the rainbow table, if you happen to already know what that means.

#![allow(unused)]
fn main() {
impl Hunk {
    pub fn raindrop(&self, value: u32) -> Hunk {
        self.combine(Hunk::hash(value))
    }
}
}

Getting back to a (different) challenge

We will want to take a Hunk, and turn it into a 32-bit value. A sort of "reverse-hash". But, not a reverse hash. We want to generate a new, unique 32-bit value from a hash. This will be the key to making rainbow tables work.

#![allow(unused)]
fn main() {
impl Hunk {
    pub fn evaporate(&self) -> u32 {
      u32::from_be_bytes([self.data[0], self.data[1], self.data[2], self.data[3]])
    }
}
}