makepad/libs/relax/compiler/tests/git_sha1_path.rs
Admin b22a714840 makepad run: the Rust JIT (libs/relax) and makepad-remote
The JIT that runs makepad apps from source: lexer, front end, type checker,
lazy borrow checker (Gandalf; `--check-first` opts in), codegen, session and
warm/cold caches keyed by compiler stamp, provided crates bound late,
startup images, live patching. User-facing name is `makepad run` (binary
`makepad`, MAKEPAD_RUN_* env, ~/.makepad-run); libs/relax stays the internal
library name. `makepad check` reports rustc-style diagnostics with rustc
error codes and checks a whole workspace (`--workspace`). Runs on macOS,
Linux, Windows and Android. makepad-remote: one tool schema for apps and the
WM (app/1): grabs, captures, traces, frame profiles and tweaks.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-13 12:26:21 +02:00

82 lines
3.3 KiB
Rust

// makepad_git's own SHA-1 (libs/git/src/sha1.rs, the hashing Scope's indexing runs) under Relax: its dispatch picks the
// hardware path (SHA-NI on x86_64 when the CPU has it, Arm SHA1 always on aarch64); every input length 0..=300 and a
// few large inputs must hash as a scalar reference SHA-1 does. Also runs that file's own unit tests (cfg(test)).
// `makepad test libs/relax/compiler/tests/git_sha1_path.rs`; also runnable with rustc -O --test.
#![allow(dead_code)]
#[path = "../../../../libs/git/src/sha1.rs"]
mod git_sha1;
fn reference(data: &[u8]) -> [u8; 20] {
let mut h: [u32; 5] = [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0];
let mut msg = data.to_vec();
let bits = (data.len() as u64) * 8;
msg.push(0x80);
while msg.len() % 64 != 56 {
msg.push(0);
}
msg.extend_from_slice(&bits.to_be_bytes());
for block in msg.chunks(64) {
let mut w = [0u32; 80];
for i in 0..16 {
w[i] = u32::from_be_bytes([block[4 * i], block[4 * i + 1], block[4 * i + 2], block[4 * i + 3]]);
}
for i in 16..80 {
w[i] = (w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]).rotate_left(1);
}
let (mut a, mut b, mut c, mut d, mut e) = (h[0], h[1], h[2], h[3], h[4]);
for i in 0..80 {
let (f, k) = match i {
0..=19 => ((b & c) | (!b & d), 0x5A827999),
20..=39 => (b ^ c ^ d, 0x6ED9EBA1),
40..=59 => ((b & c) | (b & d) | (c & d), 0x8F1BBCDC),
_ => (b ^ c ^ d, 0xCA62C1D6),
};
let t = a.rotate_left(5).wrapping_add(f).wrapping_add(e).wrapping_add(k).wrapping_add(w[i]);
e = d;
d = c;
c = b.rotate_left(30);
b = a;
a = t;
}
h[0] = h[0].wrapping_add(a);
h[1] = h[1].wrapping_add(b);
h[2] = h[2].wrapping_add(c);
h[3] = h[3].wrapping_add(d);
h[4] = h[4].wrapping_add(e);
}
let mut out = [0u8; 20];
for i in 0..5 {
out[4 * i..4 * i + 4].copy_from_slice(&h[i].to_be_bytes());
}
out
}
fn data(len: usize, seed: u32) -> Vec<u8> {
let mut x = seed.wrapping_mul(2654435761).wrapping_add(len as u32) | 1;
(0..len).map(|_| { x ^= x << 13; x ^= x >> 17; x ^= x << 5; (x >> 7) as u8 }).collect()
}
#[test]
fn git_sha1_matches_reference() {
#[cfg(target_arch = "x86_64")]
println!("hardware path: sha={}", std::is_x86_feature_detected!("sha"));
let mut lens: Vec<usize> = (0..=300).collect();
lens.extend_from_slice(&[1000, 4095, 4096, 4097, 65536, 1 << 20]);
for (k, &len) in lens.iter().enumerate() {
let d = data(len, k as u32);
let mut one = git_sha1::Sha1::new();
one.update(&d);
assert_eq!(one.finalize(), reference(&d), "one-shot, len {len}");
// split updates cross the 64-byte buffer at every offset class
let mut split = git_sha1::Sha1::new();
let cut = (len * 7 / 13).min(len);
split.update(&d[..cut]);
split.update(&d[cut..]);
assert_eq!(split.finalize(), reference(&d), "split at {cut}, len {len}");
}
let mut abc = git_sha1::Sha1::new();
abc.update(b"abc");
let hex: String = abc.finalize().iter().map(|b| format!("{:02x}", b)).collect();
assert_eq!(hex, "a9993e364706816aba3e25717850c26c9cd0d89d");
}