Programming Language

Nocter

A self-contained systems language built around simplicity, encapsulation, and foolproof design.

/development/std/hash/state.nct

state.nct

//! Private streaming hash-state representation and algorithm.

see ./index.nct

use /internal/hash.acquire_seed
use /num

struct HashState {
    seed: u64
    lane0: u64
    lane1: u64
    lane2: u64
    lane3: u64
    buffered: u64
    buffer: u64
    written: u64
}

construct HashState {
    func fresh(): Self {
        return HashState.from_seed(acquire_seed())
    }

    func from_seed(seed: u64): Self {
        let rotated = seed.rotate_right(32)
        return HashState {
            seed: seed,
            lane0: seed.bit_xor(8317987319222330741),
            lane1: rotated.bit_xor(7237128888997146477),
            lane2: seed.bit_xor(7816392313619706465),
            lane3: rotated.bit_xor(8387220255154660723),
            buffered: 0,
            buffer: 0,
            written: 0,
        }
    }
}

instance HashState {
    method &self.restart(): Self {
        return HashState.from_seed(self.seed)
    }

    method &+self.write(bytes: &[u8]): void {
        var index: usize = 0
        while index < bytes.len() {
            let current_buffer: u64 = self.buffer
            let shifted = current_buffer.wrapping_mul(256)
            self.buffer = shifted.wrapping_add(bytes[index] as u64)
            let current_buffered: u64 = self.buffered
            self.buffered = current_buffered.wrapping_add(1)
            let current_written: u64 = self.written
            self.written = current_written.wrapping_add(1)
            if self.buffered == 8 {
                let message: u64 = self.buffer
                compress(self, message)
                self.buffered = 0
                self.buffer = 0
            }
            index += 1
        }
        return
    }

    method &self.finish(): u64 {
        var final = HashState {
            seed: self.seed,
            lane0: self.lane0,
            lane1: self.lane1,
            lane2: self.lane2,
            lane3: self.lane3,
            buffered: self.buffered,
            buffer: self.buffer,
            written: self.written,
        }
        let buffered: u64 = final.buffered
        let boundary = buffered.rotate_right(8)
        let buffer: u64 = final.buffer
        compress(&+final, buffer.bit_xor(boundary))
        let written: u64 = final.written
        compress(&+final, written)
        let lane2: u64 = final.lane2
        final.lane2 = lane2.bit_xor(255)
        mix_round(&+final)
        mix_round(&+final)
        mix_round(&+final)
        mix_round(&+final)
        let left = final.lane0.bit_xor(final.lane1)
        let right = final.lane2.bit_xor(final.lane3)
        return left.bit_xor(right)
    }
}

func compress(state: &+HashState, message: u64): void {
    let lane3: u64 = state.lane3
    state.lane3 = lane3.bit_xor(message)
    mix_round(state)
    mix_round(state)
    let lane0: u64 = state.lane0
    state.lane0 = lane0.bit_xor(message)
    return
}

func mix_round(state: &+HashState): void {
    let lane0: u64 = state.lane0
    let lane1: u64 = state.lane1
    state.lane0 = lane0.wrapping_add(lane1)
    state.lane1 = lane1.rotate_right(51)
    let rotated1: u64 = state.lane1
    let sum0: u64 = state.lane0
    state.lane1 = rotated1.bit_xor(sum0)
    state.lane0 = sum0.rotate_right(32)

    let lane2: u64 = state.lane2
    let lane3: u64 = state.lane3
    state.lane2 = lane2.wrapping_add(lane3)
    state.lane3 = lane3.rotate_right(48)
    let rotated3: u64 = state.lane3
    let sum2: u64 = state.lane2
    state.lane3 = rotated3.bit_xor(sum2)

    let next0: u64 = state.lane0
    let next3: u64 = state.lane3
    state.lane0 = next0.wrapping_add(next3)
    state.lane3 = next3.rotate_right(43)
    let final3: u64 = state.lane3
    let final0: u64 = state.lane0
    state.lane3 = final3.bit_xor(final0)

    let next2: u64 = state.lane2
    let next1: u64 = state.lane1
    state.lane2 = next2.wrapping_add(next1)
    state.lane1 = next1.rotate_right(47)
    let final1: u64 = state.lane1
    let final2: u64 = state.lane2
    state.lane1 = final1.bit_xor(final2)
    state.lane2 = final2.rotate_right(32)
    return
}