tracelogging/
guid.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT license.
3
4use core::borrow;
5use core::convert::TryInto;
6use core::fmt;
7use core::mem;
8use core::str::from_utf8;
9
10/// [GUID](https://docs.microsoft.com/windows/win32/api/guiddef/ns-guiddef-guid)
11/// ([UUID](https://en.wikipedia.org/wiki/Universally_unique_identifier)).
12/// with host-endian in-memory representation (as expected by the ETW APIs).
13#[repr(C)]
14#[derive(Clone, Copy, Default, PartialEq, Eq, Hash, Ord, PartialOrd)]
15pub struct Guid {
16    data1: u32,
17    data2: u16,
18    data3: u16,
19    data4: [u8; 8],
20}
21
22impl Guid {
23    /// Returns a zeroed GUID, i.e. GUID_NULL.
24    pub const fn zero() -> Self {
25        return Self {
26            data1: 0,
27            data2: 0,
28            data3: 0,
29            data4: [0; 8],
30        };
31    }
32
33    /// Generates a unique GUID using UuidCreate.
34    /// Note: For a zeroed GUID, use Guid::zero().
35    /// ```
36    /// # use tracelogging::Guid;
37    /// let g = Guid::new();
38    /// ```
39    #[cfg(all(windows, not(proc_macro)))]
40    pub fn new() -> Self {
41        #[link(name = "rpcrt4")]
42        extern "system" {
43            fn UuidCreate(uuid: &mut Guid) -> u32;
44        }
45
46        let mut g = Guid::zero();
47
48        // Safety: We assume that UuidCreate is well-behaved.
49        unsafe {
50            UuidCreate(&mut g);
51        }
52        return g;
53    }
54
55    /// Returns a GUID generated from a case-insensitive hash of the specified trace
56    /// provider name. The hash uses the same algorithm as many other ETW tools and APIs.
57    /// Given the same name, it will always generate the same GUID.
58    /// ```
59    /// # use tracelogging::Guid;
60    /// assert_eq!(
61    ///    Guid::from_name("MyProvider"),
62    ///    Guid::from_u128(&0xb3864c38_4273_58c5_545b_8b3608343471));
63    /// ```
64    pub fn from_name(event_provider_name: &str) -> Self {
65        let mut hasher = Sha1NonSecret::new();
66        hasher.write(&[
67            0x48, 0x2C, 0x2D, 0xB2, 0xC3, 0x90, 0x47, 0xC8, 0x87, 0xF8, 0x1A, 0x15, 0xBF, 0xC1,
68            0x30, 0xFB,
69        ]);
70
71        // Hash name as uppercase UTF-16BE
72        let mut u16buf = [0u16; 2];
73        for upper_ch in event_provider_name.chars().flat_map(char::to_uppercase) {
74            for upper_u16 in upper_ch.encode_utf16(&mut u16buf) {
75                hasher.write(&upper_u16.to_be_bytes());
76            }
77        }
78
79        let mut v = hasher.finish();
80        v[7] = (v[7] & 0x0F) | 0x50;
81        return Guid::from_bytes_le(v[0..16].try_into().unwrap());
82    }
83
84    /// Creates a GUID from field values.
85    /// ```
86    /// # use tracelogging::Guid;
87    /// assert_eq!(
88    ///     Guid::from_fields(0xa3a2a1a0, 0xb1b0, 0xc1c0, [0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0]),
89    ///     Guid::from_bytes_be(&[0xa3, 0xa2, 0xa1, 0xa0, 0xb1, 0xb0, 0xc1, 0xc0, 0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0]));
90    /// ```
91    pub const fn from_fields(data1: u32, data2: u16, data3: u16, data4: [u8; 8]) -> Self {
92        return Self {
93            data1,
94            data2,
95            data3,
96            data4,
97        };
98    }
99
100    /// Creates a GUID from bytes in big-endian (RFC) byte order.
101    /// ```
102    /// # use tracelogging::Guid;
103    /// assert_eq!(
104    ///     Guid::from_fields(0xa3a2a1a0, 0xb1b0, 0xc1c0, [0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0]),
105    ///     Guid::from_bytes_be(&[0xa3, 0xa2, 0xa1, 0xa0, 0xb1, 0xb0, 0xc1, 0xc0, 0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0]));
106    /// ```
107    pub const fn from_bytes_be(bytes_be: &[u8; 16]) -> Self {
108        let b = bytes_be;
109        return Self {
110            data1: u32::from_be_bytes([b[0], b[1], b[2], b[3]]),
111            data2: u16::from_be_bytes([b[4], b[5]]),
112            data3: u16::from_be_bytes([b[6], b[7]]),
113            data4: [b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]],
114        };
115    }
116
117    /// Creates a GUID from bytes in little-endian byte order.
118    /// ```
119    /// # use tracelogging::Guid;
120    /// assert_eq!(
121    ///     Guid::from_fields(0xa3a2a1a0, 0xb1b0, 0xc1c0, [0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0]),
122    ///     Guid::from_bytes_le(&[0xa0, 0xa1, 0xa2, 0xa3, 0xb0, 0xb1, 0xc0, 0xc1, 0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0]));
123    /// ```
124    pub const fn from_bytes_le(bytes_le: &[u8; 16]) -> Self {
125        let b = bytes_le;
126        return Self {
127            data1: u32::from_le_bytes([b[0], b[1], b[2], b[3]]),
128            data2: u16::from_le_bytes([b[4], b[5]]),
129            data3: u16::from_le_bytes([b[6], b[7]]),
130            data4: [b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]],
131        };
132    }
133
134    /// Creates a GUID from a u128 value.
135    /// ```
136    /// # use tracelogging::Guid;
137    /// assert_eq!(
138    ///     Guid::from_fields(0xa3a2a1a0, 0xb1b0, 0xc1c0, [0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0]),
139    ///     Guid::from_u128(&0xa3a2a1a0_b1b0_c1c0_d7d6d5d4d3d2d1d0));
140    /// ```
141    pub const fn from_u128(value: &u128) -> Self {
142        return Self {
143            data1: u32::from_le(value.wrapping_shr(96) as u32),
144            data2: u16::from_le(value.wrapping_shr(80) as u16),
145            data3: u16::from_le(value.wrapping_shr(64) as u16),
146            data4: (*value as u64).to_be_bytes(),
147        };
148    }
149
150    /// Creates a GUID from a string with optional {} and optional '-'.
151    /// Returns None if GUID could not be parsed from the input.
152    /// ```
153    /// # use tracelogging::Guid;
154    /// assert_eq!(
155    ///     Guid::from_fields(0xa3a2a1a0, 0xb1b0, 0xc1c0, [0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0]),
156    ///     Guid::try_parse("{a3a2a1a0-b1b0-c1c0-d7d6-d5d4d3d2d1d0}").unwrap());
157    /// assert_eq!(
158    ///     Guid::from_fields(0xa3a2a1a0, 0xb1b0, 0xc1c0, [0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0]),
159    ///     Guid::try_parse("a3a2a1a0-b1b0-c1c0-d7d6-d5d4d3d2d1d0").unwrap());
160    /// assert_eq!(
161    ///     Guid::from_fields(0xa3a2a1a0, 0xb1b0, 0xc1c0, [0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0]),
162    ///     Guid::try_parse("a3a2a1a0b1b0c1c0d7d6d5d4d3d2d1d0").unwrap());
163    /// ```
164    pub fn try_parse(value: &str) -> Option<Self> {
165        return Self::try_parse_ascii(value.as_bytes());
166    }
167
168    /// Creates a GUID from a string with optional {} and optional '-'.
169    /// Returns None if GUID could not be parsed from the input.
170    /// ```
171    /// # use tracelogging::Guid;
172    /// assert_eq!(
173    ///     Guid::from_fields(0xa3a2a1a0, 0xb1b0, 0xc1c0, [0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0]),
174    ///     Guid::try_parse_ascii(b"{a3a2a1a0-b1b0-c1c0-d7d6-d5d4d3d2d1d0}").unwrap());
175    /// assert_eq!(
176    ///     Guid::from_fields(0xa3a2a1a0, 0xb1b0, 0xc1c0, [0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0]),
177    ///     Guid::try_parse_ascii(b"a3a2a1a0-b1b0-c1c0-d7d6-d5d4d3d2d1d0").unwrap());
178    /// assert_eq!(
179    ///     Guid::from_fields(0xa3a2a1a0, 0xb1b0, 0xc1c0, [0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0]),
180    ///     Guid::try_parse_ascii(b"a3a2a1a0b1b0c1c0d7d6d5d4d3d2d1d0").unwrap());
181    /// ```
182    pub fn try_parse_ascii(value: &[u8]) -> Option<Self> {
183        if value.len() < 32 {
184            return None;
185        }
186
187        let mut state = GuidParseState {
188            input: if value[0] != b'{' || value[value.len() - 1] != b'}' {
189                value
190            } else {
191                &value[1..value.len() - 1]
192            },
193            pos: 0,
194            dash: 0,
195            highbits: 0,
196        };
197
198        if (state.input.len() == 36)
199            & (state.input[8] == b'-')
200            & (state.input[13] == b'-')
201            & (state.input[18] == b'-')
202            & (state.input[23] == b'-')
203        {
204            state.dash = 1;
205        } else if state.input.len() != 32 {
206            return None;
207        }
208
209        let b = [
210            state.next(),
211            state.next(),
212            state.next(),
213            state.next(),
214            state.next_dash(),
215            state.next(),
216            state.next_dash(),
217            state.next(),
218            state.next_dash(),
219            state.next(),
220            state.next_dash(),
221            state.next(),
222            state.next(),
223            state.next(),
224            state.next(),
225            state.next(),
226        ];
227
228        if (state.highbits & 0xFFFFFF00) != 0 {
229            return None;
230        }
231
232        return Some(Self::from_bytes_be(&b));
233    }
234
235    /// Returns the field values of the GUID as a tuple.
236    /// ```
237    /// # use tracelogging::Guid;
238    /// assert_eq!(
239    ///     Guid::from_fields(0xa3a2a1a0, 0xb1b0, 0xc1c0, [0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0]).to_fields(),
240    ///     (0xa3a2a1a0, 0xb1b0, 0xc1c0, [0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0]));
241    /// ```
242    #[allow(clippy::wrong_self_convention)]
243    pub const fn to_fields(&self) -> (u32, u16, u16, [u8; 8]) {
244        return (self.data1, self.data2, self.data3, self.data4);
245    }
246
247    /// Returns this implementation's in-memory byte representation.
248    pub const fn as_bytes_raw(&self) -> &[u8; 16] {
249        return unsafe { mem::transmute(self) };
250    }
251
252    /// Returns the bytes of the GUID in big-endian (RFC) byte order.
253    /// ```
254    /// # use tracelogging::Guid;
255    /// assert_eq!(
256    ///     Guid::from_fields(0xa3a2a1a0, 0xb1b0, 0xc1c0, [0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0]).to_bytes_be(),
257    ///     [0xa3, 0xa2, 0xa1, 0xa0, 0xb1, 0xb0, 0xc1, 0xc0, 0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0]);
258    /// ```
259    #[allow(clippy::wrong_self_convention)]
260    pub const fn to_bytes_be(&self) -> [u8; 16] {
261        return [
262            (self.data1 >> 24) as u8,
263            (self.data1 >> 16) as u8,
264            (self.data1 >> 8) as u8,
265            self.data1 as u8,
266            (self.data2 >> 8) as u8,
267            self.data2 as u8,
268            (self.data3 >> 8) as u8,
269            self.data3 as u8,
270            self.data4[0],
271            self.data4[1],
272            self.data4[2],
273            self.data4[3],
274            self.data4[4],
275            self.data4[5],
276            self.data4[6],
277            self.data4[7],
278        ];
279    }
280
281    /// Returns the bytes of the GUID in little-endian byte order.
282    /// ```
283    /// # use tracelogging::Guid;
284    /// assert_eq!(
285    ///     Guid::from_fields(0xa3a2a1a0, 0xb1b0, 0xc1c0, [0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0]).to_bytes_le(),
286    ///     [0xa0, 0xa1, 0xa2, 0xa3, 0xb0, 0xb1, 0xc0, 0xc1, 0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0]);
287    /// ```
288    #[allow(clippy::wrong_self_convention)]
289    pub const fn to_bytes_le(&self) -> [u8; 16] {
290        return [
291            self.data1 as u8,
292            (self.data1 >> 8) as u8,
293            (self.data1 >> 16) as u8,
294            (self.data1 >> 24) as u8,
295            self.data2 as u8,
296            (self.data2 >> 8) as u8,
297            self.data3 as u8,
298            (self.data3 >> 8) as u8,
299            self.data4[0],
300            self.data4[1],
301            self.data4[2],
302            self.data4[3],
303            self.data4[4],
304            self.data4[5],
305            self.data4[6],
306            self.data4[7],
307        ];
308    }
309
310    /// Returns the GUID as a u128 value.
311    /// ```
312    /// use tracelogging::Guid;
313    /// assert_eq!(
314    ///     Guid::from_fields(0xa3a2a1a0, 0xb1b0, 0xc1c0, [0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0]).to_u128(),
315    ///     0xa3a2a1a0_b1b0_c1c0_d7d6d5d4d3d2d1d0);
316    /// ```
317    #[allow(clippy::wrong_self_convention)]
318    pub const fn to_u128(&self) -> u128 {
319        return (self.data1.to_le() as u128) << 96
320            | (self.data2.to_le() as u128) << 80
321            | (self.data3.to_le() as u128) << 64
322            | u64::from_be_bytes(self.data4) as u128;
323    }
324
325    /// Convert GUID to utf8 string bytes.
326    /// To get a &str, use: `str::from_utf8(&guid.to_utf8_bytes()).unwrap()`.
327    /// ```
328    /// use tracelogging::Guid;
329    /// assert_eq!(
330    ///     Guid::from_fields(0xa3a2a1a0, 0xb1b0, 0xc1c0, [0xd7, 0xd6, 0xd5, 0xd4, 0xd3, 0xd2, 0xd1, 0xd0]).to_utf8_bytes(),
331    ///     *b"a3a2a1a0-b1b0-c1c0-d7d6-d5d4d3d2d1d0");
332    /// ```
333    #[allow(clippy::wrong_self_convention)]
334    pub const fn to_utf8_bytes(&self) -> [u8; 36] {
335        const HEX_DIGITS: &[u8] = b"0123456789abcdef";
336        return [
337            HEX_DIGITS[((self.data1 >> 28) & 0xf) as usize],
338            HEX_DIGITS[((self.data1 >> 24) & 0xf) as usize],
339            HEX_DIGITS[((self.data1 >> 20) & 0xf) as usize],
340            HEX_DIGITS[((self.data1 >> 16) & 0xf) as usize],
341            HEX_DIGITS[((self.data1 >> 12) & 0xf) as usize],
342            HEX_DIGITS[((self.data1 >> 8) & 0xf) as usize],
343            HEX_DIGITS[((self.data1 >> 4) & 0xf) as usize],
344            HEX_DIGITS[(self.data1 & 0xf) as usize],
345            b'-',
346            HEX_DIGITS[((self.data2 >> 12) & 0xf) as usize],
347            HEX_DIGITS[((self.data2 >> 8) & 0xf) as usize],
348            HEX_DIGITS[((self.data2 >> 4) & 0xf) as usize],
349            HEX_DIGITS[(self.data2 & 0xf) as usize],
350            b'-',
351            HEX_DIGITS[((self.data3 >> 12) & 0xf) as usize],
352            HEX_DIGITS[((self.data3 >> 8) & 0xf) as usize],
353            HEX_DIGITS[((self.data3 >> 4) & 0xf) as usize],
354            HEX_DIGITS[(self.data3 & 0xf) as usize],
355            b'-',
356            HEX_DIGITS[((self.data4[0] >> 4) & 0xf) as usize],
357            HEX_DIGITS[(self.data4[0] & 0xf) as usize],
358            HEX_DIGITS[((self.data4[1] >> 4) & 0xf) as usize],
359            HEX_DIGITS[(self.data4[1] & 0xf) as usize],
360            b'-',
361            HEX_DIGITS[((self.data4[2] >> 4) & 0xf) as usize],
362            HEX_DIGITS[(self.data4[2] & 0xf) as usize],
363            HEX_DIGITS[((self.data4[3] >> 4) & 0xf) as usize],
364            HEX_DIGITS[(self.data4[3] & 0xf) as usize],
365            HEX_DIGITS[((self.data4[4] >> 4) & 0xf) as usize],
366            HEX_DIGITS[(self.data4[4] & 0xf) as usize],
367            HEX_DIGITS[((self.data4[5] >> 4) & 0xf) as usize],
368            HEX_DIGITS[(self.data4[5] & 0xf) as usize],
369            HEX_DIGITS[((self.data4[6] >> 4) & 0xf) as usize],
370            HEX_DIGITS[(self.data4[6] & 0xf) as usize],
371            HEX_DIGITS[((self.data4[7] >> 4) & 0xf) as usize],
372            HEX_DIGITS[(self.data4[7] & 0xf) as usize],
373        ];
374    }
375}
376
377impl fmt::Debug for Guid {
378    /// Format the GUID, e.g. "a3a2a1a0-b1b0-c1c0-d7d6-d5d4d3d2d1d0".
379    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
380        return f.write_str(from_utf8(&self.to_utf8_bytes()).unwrap());
381    }
382}
383
384impl borrow::Borrow<[u8; 16]> for Guid {
385    /// Returns this implementation's in-memory byte representation.
386    fn borrow(&self) -> &[u8; 16] {
387        return unsafe { mem::transmute(self) };
388    }
389}
390
391struct GuidParseState<'a> {
392    input: &'a [u8],
393    pos: usize,
394    dash: usize,
395    highbits: u32,
396}
397
398impl GuidParseState<'_> {
399    fn next(&mut self) -> u8 {
400        let val1 = Self::hex_to_u4(self.input[self.pos]);
401        let val2 = Self::hex_to_u4(self.input[self.pos + 1]);
402        self.pos += 2;
403        let val = (val1 << 4) | val2;
404        self.highbits |= val;
405        return val as u8;
406    }
407
408    fn next_dash(&mut self) -> u8 {
409        self.pos += self.dash;
410        return self.next();
411    }
412
413    fn hex_to_u4(ch: u8) -> u32 {
414        let hexval;
415        let mut index = ch.wrapping_sub(48);
416        if index < 10 {
417            hexval = index as u32;
418        } else {
419            index = (ch | 32).wrapping_sub(97);
420            hexval = if index < 6 { (index + 10) as u32 } else { 256 };
421        }
422        return hexval;
423    }
424}
425
426/// Single-use SHA1 hasher (finish() is destructive). Note that this implementation
427/// is for hashing public information. Do not use this code to hash private data
428/// as this implementation does not take any steps to avoid information disclosure
429/// (i.e. does not scrub its buffers).
430struct Sha1NonSecret {
431    chunk: [u8; 64],  // Each chunk is 64 bytes.
432    chunk_count: u32, // Implementation limited to 2^32-1 chunks = 255GB.
433    chunk_pos: u8,
434    results: [u32; 5],
435}
436
437impl Sha1NonSecret {
438    pub fn new() -> Sha1NonSecret {
439        return Self {
440            chunk: [0; 64],
441            chunk_count: 0,
442            chunk_pos: 0,
443            results: [0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0],
444        };
445    }
446
447    pub fn write_u8(&mut self, val: u8) {
448        self.chunk[self.chunk_pos as usize] = val;
449        self.chunk_pos = (self.chunk_pos + 1) & 63;
450        if self.chunk_pos == 0 {
451            self.drain();
452        }
453    }
454
455    pub fn write(&mut self, bytes: &[u8]) {
456        for i in bytes {
457            self.write_u8(*i);
458        }
459    }
460
461    pub fn finish(&mut self) -> [u8; 20] {
462        // Need to capture chunk_count before we add end-bit and zerofill.
463        let total_bit_count = (self.chunk_count as u64 * 512) + (self.chunk_pos as u64 * 8);
464
465        // Add end-bit
466        self.write_u8(0x80);
467
468        // Zero-fill until almost to end of chunk.
469        while self.chunk_pos != 56 {
470            self.write_u8(0);
471        }
472
473        // End chunk with total bit count.
474        self.write(&total_bit_count.to_be_bytes());
475        debug_assert_eq!(self.chunk_pos, 0, "Bug: write should have drained");
476
477        let mut sha1 = [0u8; 20];
478        for i in 0..5 {
479            sha1[(i * 4)..(i * 4 + 4)].copy_from_slice(&self.results[i].to_be_bytes());
480        }
481
482        return sha1;
483    }
484
485    fn drain(&mut self) {
486        let mut w = [0u32; 80];
487
488        let mut wpos = 0;
489        while wpos != 16 {
490            w[wpos] = u32::from_be_bytes([
491                self.chunk[wpos * 4],
492                self.chunk[wpos * 4 + 1],
493                self.chunk[wpos * 4 + 2],
494                self.chunk[wpos * 4 + 3],
495            ]);
496            wpos += 1;
497        }
498
499        while wpos != 80 {
500            w[wpos] = (w[wpos - 3] ^ w[wpos - 8] ^ w[wpos - 14] ^ w[wpos - 16]).rotate_left(1);
501            wpos += 1;
502        }
503
504        let mut a = self.results[0];
505        let mut b = self.results[1];
506        let mut c = self.results[2];
507        let mut d = self.results[3];
508        let mut e = self.results[4];
509
510        wpos = 0;
511        while wpos != 20 {
512            const K: u32 = 0x5A827999;
513            let f = (b & c) | (!b & d);
514            let temp = a
515                .rotate_left(5)
516                .wrapping_add(f)
517                .wrapping_add(e)
518                .wrapping_add(K)
519                .wrapping_add(w[wpos]);
520            e = d;
521            d = c;
522            c = b.rotate_left(30);
523            b = a;
524            a = temp;
525            wpos += 1;
526        }
527
528        while wpos != 40 {
529            const K: u32 = 0x6ED9EBA1;
530            let f = b ^ c ^ d;
531            let temp = a
532                .rotate_left(5)
533                .wrapping_add(f)
534                .wrapping_add(e)
535                .wrapping_add(K)
536                .wrapping_add(w[wpos]);
537            e = d;
538            d = c;
539            c = b.rotate_left(30);
540            b = a;
541            a = temp;
542            wpos += 1;
543        }
544
545        while wpos != 60 {
546            const K: u32 = 0x8F1BBCDC;
547            let f = (b & c) | (b & d) | (c & d);
548            let temp = a
549                .rotate_left(5)
550                .wrapping_add(f)
551                .wrapping_add(e)
552                .wrapping_add(K)
553                .wrapping_add(w[wpos]);
554            e = d;
555            d = c;
556            c = b.rotate_left(30);
557            b = a;
558            a = temp;
559            wpos += 1;
560        }
561
562        while wpos != 80 {
563            const K: u32 = 0xCA62C1D6;
564            let f = b ^ c ^ d;
565            let temp = a
566                .rotate_left(5)
567                .wrapping_add(f)
568                .wrapping_add(e)
569                .wrapping_add(K)
570                .wrapping_add(w[wpos]);
571            e = d;
572            d = c;
573            c = b.rotate_left(30);
574            b = a;
575            a = temp;
576            wpos += 1;
577        }
578
579        self.results[0] = self.results[0].wrapping_add(a);
580        self.results[1] = self.results[1].wrapping_add(b);
581        self.results[2] = self.results[2].wrapping_add(c);
582        self.results[3] = self.results[3].wrapping_add(d);
583        self.results[4] = self.results[4].wrapping_add(e);
584        self.chunk_count += 1;
585    }
586}