penis 0.1.1

A Rust implementation of the Penis Protocol
Documentation
use crate::consts::SCHEDULE_SEED;
use crate::primitivefns::*;
use crate::structs::{NRound, PartialSchedArray, PrivateBlock, RawBlockRef, SchedArray, State};

pub(crate) const fn execute_until_rounds(
    block: RawBlockRef,
    previous_state: &State,
    n: NRound,
) -> PrivateBlock {
    let mut schedule_array: SchedArray = [0; 64];

    let mut i = 0;
    while i < 16 {
        schedule_array[i] = u32::from_be_bytes([
            block[i * 4],
            block[i * 4 + 1],
            block[i * 4 + 2],
            block[i * 4 + 3],
        ]);
        i += 1;
    }

    while i < n + 16 {
        schedule_array[i] = lsigma1(schedule_array[i - 2])
            .wrapping_add(schedule_array[i - 7])
            .wrapping_add(lsigma0(schedule_array[i - 15]))
            .wrapping_add(schedule_array[i - 16]);
        i += 1;
    }

    let mut a = previous_state.a;
    let mut b = previous_state.b;
    let mut c = previous_state.c;
    let mut d = previous_state.d;
    let mut e = previous_state.e;
    let mut f = previous_state.f;
    let mut g = previous_state.g;
    let mut h = previous_state.h;

    let mut i = 0;
    while i < n {
        let t1 = h
            .wrapping_add(sigma1(e))
            .wrapping_add(ch(e, f, g))
            .wrapping_add(SCHEDULE_SEED[i])
            .wrapping_add(schedule_array[i]);
        let t2 = sigma0(a).wrapping_add(maj(a, b, c));
        h = g;
        g = f;
        f = e;
        e = d.wrapping_add(t1);
        d = c;
        c = b;
        b = a;
        a = t1.wrapping_add(t2);
        i += 1;
    }

    // copy the array, equivalent to
    // psa.copy_from_slice(&schedule_array[n..(n + 16)]);
    // but it can't be const, so we do it manually
    // Additionally, we can avoid the mut variable
    let psa: PartialSchedArray = [
        schedule_array[n],
        schedule_array[n + 1],
        schedule_array[n + 2],
        schedule_array[n + 3],
        schedule_array[n + 4],
        schedule_array[n + 5],
        schedule_array[n + 6],
        schedule_array[n + 7],
        schedule_array[n + 8],
        schedule_array[n + 9],
        schedule_array[n + 10],
        schedule_array[n + 11],
        schedule_array[n + 12],
        schedule_array[n + 13],
        schedule_array[n + 14],
        schedule_array[n + 15],
    ];

    let state = State {
        a,
        b,
        c,
        d,
        e,
        f,
        g,
        h,
    };
    PrivateBlock { state, psa }
}

pub(crate) const fn execute_from_rounds(
    pb: &PrivateBlock,
    previous_state: State,
    n: NRound,
) -> State {
    let partial_state = &pb.state;
    let psa = &pb.psa;
    let mut rsa: SchedArray = [0u32; 64];

    let mut i = 0;
    while i < 16 {
        rsa[i] = psa[i];
        i += 1;
    }
    while i < 64 - n {
        rsa[i] = lsigma1(rsa[i - 2])
            .wrapping_add(rsa[i - 7])
            .wrapping_add(lsigma0(rsa[i - 15]))
            .wrapping_add(rsa[i - 16]);
        i += 1;
    }

    let mut a = partial_state.a;
    let mut b = partial_state.b;
    let mut c = partial_state.c;
    let mut d = partial_state.d;
    let mut e = partial_state.e;
    let mut f = partial_state.f;
    let mut g = partial_state.g;
    let mut h = partial_state.h;

    let mut i = 0;
    while i < 64 - n {
        let t1 = h
            .wrapping_add(sigma1(e))
            .wrapping_add(ch(e, f, g))
            .wrapping_add(SCHEDULE_SEED[i + n])
            .wrapping_add(rsa[i]);
        let t2 = sigma0(a).wrapping_add(maj(a, b, c));
        h = g;
        g = f;
        f = e;
        e = d.wrapping_add(t1);
        d = c;
        c = b;
        b = a;
        a = t1.wrapping_add(t2);
        i += 1;
    }

    State {
        a: a.wrapping_add(previous_state.a),
        b: b.wrapping_add(previous_state.b),
        c: c.wrapping_add(previous_state.c),
        d: d.wrapping_add(previous_state.d),
        e: e.wrapping_add(previous_state.e),
        f: f.wrapping_add(previous_state.f),
        g: g.wrapping_add(previous_state.g),
        h: h.wrapping_add(previous_state.h),
    }
}