#![no_std]
#![no_main]

//! Validate purestd's SipHash-1-3 against the canonical reference.
//!
//! The 64 expected values below are SipHash-1-3 of the standard test inputs
//! (key = bytes `00..0f`; input #i is the `i` bytes `00,01,…,i-1`), generated by
//! the canonical veorq/SipHash reference C compiled with `cROUNDS=1, dROUNDS=3`.
//! That same harness reproduces all 64 official SipHash-2-4 `vectors.h` exactly,
//! so it is trustworthy ground truth.
//!
//! We also feed each input as two separate `write` calls to confirm the
//! streaming `Hasher` path (used whenever a `Hash` impl writes in pieces)
//! matches the single-shot result. A clean exit 0 means every check passed.

use purestd::hash::{Hasher, SipHasher13};
use purestd::prelude::*;

// key = bytes 00..0f, little-endian: k0 = 0x0706050403020100, k1 = 0x0f0e0d0c0b0a0908
const K0: u64 = 0x0706050403020100;
const K1: u64 = 0x0f0e0d0c0b0a0908;

const SIP13_VECTORS: [u64; 64] = [
    0xabac0158050fc4dc, 0xc9f49bf37d57ca93, 0x82cb9b024dc7d44d, 0x8bf80ab8e7ddf7fb,
    0xcf75576088d38328, 0xdef9d52f49533b67, 0xc50d2b50c59f22a7, 0xd3927d989bb11140,
    0x369095118d299a8e, 0x25a48eb36c063de4, 0x79de85ee92ff097f, 0x70c118c1f94dc352,
    0x78a384b157b4d9a2, 0x306f760c1229ffa7, 0x605aa111c0f95d34, 0xd320d86d2a519956,
    0xcc4fdd1a7d908b66, 0x9cf2689063dbd80c, 0x8ffc389cb473e63e, 0xf21f9de58d297d1c,
    0xc0dc2f46a6cce040, 0xb992abfe2b45f844, 0x7ffe7b9ba320872e, 0x525a0e7fdae6c123,
    0xf464aeb267349c8c, 0x45cd5928705b0979, 0x3a3e35e3ca9913a5, 0xa91dc74e4ade3b35,
    0xfb0bed02ef6cd00d, 0x88d93cb44ab1e1f4, 0x540f11d643c5e663, 0x2370dd1f8c21d1bc,
    0x81157b6c16a7b60d, 0x4d54b9e57a8ff9bf, 0x759f12781f2a753e, 0xcea1a3bebf186b91,
    0x2cf508d3ada26206, 0xb6101c2da3c33057, 0xb3f47496ae3a36a1, 0x626b57547b108392,
    0xc1d2363299e41531, 0x667cc1923f1ad944, 0x65704ffec8138825, 0x24f280d1c28949a6,
    0xc2ca1cedfaf8876b, 0xc2164bfc9f042196, 0xa16e9c9368b1d623, 0x49fb169c8b5114fd,
    0x9f3143f8df074c46, 0xc6fdaf2412cc86b3, 0x7eaf49d10a52098f, 0x1cf313559d292f9a,
    0xc44a30dda2f41f12, 0x36fae98943a71ed0, 0x318fb34c73f0bce6, 0xa27abf3670a7e980,
    0xb4bcc0db243c6d75, 0x23f8d852fdb71513, 0x8f035f4da67d8a08, 0xd89cd0e5b7e8f148,
    0xf6f4e6bcf7a644ee, 0xaec59ad80f1837f2, 0xc3b2f6154b6694e0, 0x9d199062b7bbb3a8,
];

fn main() {
    let mut input = [0u8; 64];
    for (i, b) in input.iter_mut().enumerate() {
        *b = i as u8;
    }

    let mut failures = 0;
    for len in 0..64 {
        let msg = &input[..len];
        let expected = SIP13_VECTORS[len];

        // Single-shot.
        let mut h = SipHasher13::new_with_keys(K0, K1);
        h.write(msg);
        let got = h.finish();
        if got != expected {
            eprintln!("len {len}: single-shot {got:#018x} != ref {expected:#018x}");
            failures += 1;
        }

        // Streaming: split into two writes at an awkward (non-8-aligned) point.
        if len > 0 {
            let split = (len * 3 / 7).min(len);
            let mut hs = SipHasher13::new_with_keys(K0, K1);
            hs.write(&msg[..split]);
            hs.write(&msg[split..]);
            let gots = hs.finish();
            if gots != expected {
                eprintln!("len {len}: streaming {gots:#018x} != ref {expected:#018x}");
                failures += 1;
            }
        }
    }

    if failures == 0 {
        println!("sipcheck: all 64 SipHash-1-3 reference vectors match (single + streaming)");
    } else {
        println!("sipcheck: {failures} FAILURES");
        purestd::process::exit(1);
    }
}

purestd::entry!(main);
