Each task's tests were run against a reference at its end state; the end states were replayed from master in order with the gate at each step (650 to 762 tests); each skeleton compiles against its tests and fails them. The reference is kept off this machine. Lessons T27 (every wait in a test has a limit) and T28 (mutate the reference before hand-over) come from this work. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
66 lines
2.1 KiB
Rust
66 lines
2.1 KiB
Rust
//! SHA-1 (FIPS 180-4), used only to check the `Sec-WebSocket-Accept` header of a WebSocket
|
|
//! handshake (RFC 6455, section 4.2.2). Never use it for anything that needs to resist attack.
|
|
|
|
/// The digest of `data`.
|
|
pub fn sha1(data: &[u8]) -> [u8; 20] {
|
|
let mut h = Sha1::new();
|
|
h.update(data);
|
|
h.finish()
|
|
}
|
|
|
|
/// SHA-1 fed in pieces.
|
|
#[derive(Debug, Clone)]
|
|
pub struct Sha1 {
|
|
state: [u32; 5],
|
|
block: [u8; 64],
|
|
filled: usize,
|
|
length: u64,
|
|
}
|
|
|
|
impl Default for Sha1 {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
impl Sha1 {
|
|
pub fn new() -> Sha1 {
|
|
Sha1 {
|
|
state: [
|
|
0x6745_2301,
|
|
0xEFCD_AB89,
|
|
0x98BA_DCFE,
|
|
0x1032_5476,
|
|
0xC3D2_E1F0,
|
|
],
|
|
block: [0; 64],
|
|
filled: 0,
|
|
length: 0,
|
|
}
|
|
}
|
|
|
|
pub fn update(&mut self, mut data: &[u8]) {
|
|
// Add 8 * data.len() to `length` (wrapping; `u64::try_from`, never `as`). Copy bytes into
|
|
// `block` from `filled` on; each time it is full (64), `compress` it and set `filled` to 0.
|
|
// Use `split_at` and `get_mut(..)`, no indexing that can go out of bounds.
|
|
todo!()
|
|
}
|
|
|
|
pub fn finish(mut self) -> [u8; 20] {
|
|
// Save `length`. Feed 0x80 then zeros so that 56 bytes of the block are filled (56 -
|
|
// filled, or 120 - filled when filled >= 56), then the saved length as 8 big-endian bytes,
|
|
// through `update`. `update` adds to `length`: put the saved value back after. Then the
|
|
// five state words, big-endian.
|
|
todo!()
|
|
}
|
|
|
|
fn compress(&mut self, block: &[u8; 64]) {
|
|
// FIPS 180-4, section 6.1.2: w[0..16] are the block as big-endian u32s; w[i] = (w[i-3] ^
|
|
// w[i-8] ^ w[i-14] ^ w[i-16]).rotate_left(1) for 16..80. Eighty rounds with f and k by
|
|
// range: 0..=19 (b & c) | (!b & d), 0x5A827999; 20..=39 b ^ c ^ d, 0x6ED9EBA1; 40..=59 (b &
|
|
// c) | (b & d) | (c & d), 0x8F1BBCDC; 60..=79 b ^ c ^ d, 0xCA62C1D6. All additions
|
|
// wrapping. Add a..e into state.
|
|
todo!()
|
|
}
|
|
}
|