Skip to main content

rustc_middle/ptrauth/llvm_siphash/
mod.rs

1// LLVM SipHash-2-4 (64 bit version)
2pub fn llvm_pointer_auth_stable_siphash(data: &[u8]) -> u16 {
3    let raw = llvm_siphash_2_4_64(data);
4
5    ((raw % 0xFFFF) + 1) as u16
6}
7
8const SIPHASH_KEY: [u8; 16] = [
9    0xb5, 0xd4, 0xc9, 0xeb, 0x79, 0x10, 0x4a, 0x79, 0x6f, 0xec, 0x8b, 0x1b, 0x42, 0x87, 0x81, 0xd4,
10];
11
12#[inline(always)]
13fn rotl(x: u64, b: u32) -> u64 {
14    (x << b) | (x >> (64 - b))
15}
16
17#[inline(always)]
18fn sipround(v0: &mut u64, v1: &mut u64, v2: &mut u64, v3: &mut u64) {
19    *v0 = v0.wrapping_add(*v1);
20    *v1 = rotl(*v1, 13);
21    *v1 ^= *v0;
22    *v0 = rotl(*v0, 32);
23
24    *v2 = v2.wrapping_add(*v3);
25    *v3 = rotl(*v3, 16);
26    *v3 ^= *v2;
27
28    *v0 = v0.wrapping_add(*v3);
29    *v3 = rotl(*v3, 21);
30    *v3 ^= *v0;
31
32    *v2 = v2.wrapping_add(*v1);
33    *v1 = rotl(*v1, 17);
34    *v1 ^= *v2;
35    *v2 = rotl(*v2, 32);
36}
37
38fn u64_from_le(bytes: &[u8]) -> u64 {
39    u64::from_le_bytes(bytes.try_into().unwrap())
40}
41
42fn load_u64_partial(bytes: &[u8]) -> u64 {
43    let mut b = 0u64;
44
45    match bytes.len() {
46        7 => {
47            b |= (bytes[6] as u64) << 48;
48            b |= (bytes[5] as u64) << 40;
49            b |= (bytes[4] as u64) << 32;
50            b |= (bytes[3] as u64) << 24;
51            b |= (bytes[2] as u64) << 16;
52            b |= (bytes[1] as u64) << 8;
53            b |= bytes[0] as u64;
54        }
55        6 => {
56            b |= (bytes[5] as u64) << 40;
57            b |= (bytes[4] as u64) << 32;
58            b |= (bytes[3] as u64) << 24;
59            b |= (bytes[2] as u64) << 16;
60            b |= (bytes[1] as u64) << 8;
61            b |= bytes[0] as u64;
62        }
63        5 => {
64            b |= (bytes[4] as u64) << 32;
65            b |= (bytes[3] as u64) << 24;
66            b |= (bytes[2] as u64) << 16;
67            b |= (bytes[1] as u64) << 8;
68            b |= bytes[0] as u64;
69        }
70        4 => {
71            b |= (bytes[3] as u64) << 24;
72            b |= (bytes[2] as u64) << 16;
73            b |= (bytes[1] as u64) << 8;
74            b |= bytes[0] as u64;
75        }
76        3 => {
77            b |= (bytes[2] as u64) << 16;
78            b |= (bytes[1] as u64) << 8;
79            b |= bytes[0] as u64;
80        }
81        2 => {
82            b |= (bytes[1] as u64) << 8;
83            b |= bytes[0] as u64;
84        }
85        1 => {
86            b |= bytes[0] as u64;
87        }
88        _ => {}
89    }
90
91    b
92}
93
94fn siphash_2_4_64_with_key(data: &[u8], key: &[u8; 16]) -> u64 {
95    let k0 = u64_from_le(&key[0..8]);
96    let k1 = u64_from_le(&key[8..16]);
97
98    let mut v0: u64 = 0x736f6d6570736575 ^ k0;
99    let mut v1: u64 = 0x646f72616e646f6d ^ k1;
100    let mut v2: u64 = 0x6c7967656e657261 ^ k0;
101    let mut v3: u64 = 0x7465646279746573 ^ k1;
102
103    let mut b: u64 = (data.len() as u64) << 56;
104    let mut i = 0;
105
106    // compression
107    while i + 8 <= data.len() {
108        let m = u64_from_le(&data[i..i + 8]);
109        i += 8;
110
111        v3 ^= m;
112
113        for _ in 0..2 {
114            sipround(&mut v0, &mut v1, &mut v2, &mut v3);
115        }
116
117        v0 ^= m;
118    }
119
120    // tail
121    let tail = &data[i..];
122
123    b |= load_u64_partial(tail);
124
125    v3 ^= b;
126
127    for _ in 0..2 {
128        sipround(&mut v0, &mut v1, &mut v2, &mut v3);
129    }
130
131    v0 ^= b;
132
133    // finalization
134    v2 ^= 0xff;
135
136    for _ in 0..4 {
137        sipround(&mut v0, &mut v1, &mut v2, &mut v3);
138    }
139
140    v0 ^ v1 ^ v2 ^ v3
141}
142// LLVM siphash<2,4> 64-bit output
143fn llvm_siphash_2_4_64(data: &[u8]) -> u64 {
144    siphash_2_4_64_with_key(data, &SIPHASH_KEY)
145}
146
147#[cfg(test)]
148mod llvm_siphash_vectors;
149
150#[cfg(test)]
151mod tests;