A lexicon-driven AppView for ATProto.
0

Configure Feed

Select the types of activity you want to include in your feed.

happyview / src / constant_time.rs
1.6 kB 49 lines
1//! Constant-time comparison helpers for secrets and their hashes. 2//! 3//! Comparing secret material (or its digest) with `==` can leak how many 4//! leading bytes matched via early-exit timing. These helpers compare in time 5//! independent of the *content* of equal-length inputs. Input length is not 6//! treated as secret — the values compared here are fixed-length hashes or 7//! attacker-known challenges — so an early length-mismatch return is fine. 8 9/// Constant-time equality over two byte slices. `subtle`'s slice comparison 10/// short-circuits only on a length mismatch (length is not secret here); for 11/// equal-length inputs it compares every byte regardless of where they differ. 12pub fn ct_eq(a: &[u8], b: &[u8]) -> bool { 13 use subtle::ConstantTimeEq; 14 a.ct_eq(b).into() 15} 16 17/// Constant-time equality over two strings (compares their UTF-8 bytes). 18pub fn ct_eq_str(a: &str, b: &str) -> bool { 19 ct_eq(a.as_bytes(), b.as_bytes()) 20} 21 22#[cfg(test)] 23mod tests { 24 use super::*; 25 26 #[test] 27 fn equal_values_match() { 28 assert!(ct_eq_str("a1b2c3", "a1b2c3")); 29 assert!(ct_eq(b"\x00\x01\x02", b"\x00\x01\x02")); 30 } 31 32 #[test] 33 fn different_same_length_do_not_match() { 34 assert!(!ct_eq_str("a1b2c3", "a1b2c4")); 35 // Differing only in the first byte must also be rejected. 36 assert!(!ct_eq_str("X1b2c3", "a1b2c3")); 37 } 38 39 #[test] 40 fn different_length_does_not_match() { 41 assert!(!ct_eq_str("abc", "abcd")); 42 assert!(!ct_eq_str("abcd", "abc")); 43 } 44 45 #[test] 46 fn empty_values_match() { 47 assert!(ct_eq_str("", "")); 48 } 49}