argon2/
block.rs

1// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com>
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9use crate::common;
10use std::fmt;
11use std::fmt::Debug;
12use std::ops::{BitXorAssign, Index, IndexMut};
13
14/// Structure for the (1 KiB) memory block implemented as 128 64-bit words.
15// Blocks are 128-byte aligned to prevent false sharing. This specific alignment value replicates
16// what `crossbeam-utils::CachePadded` does on modern architectures, which either use 128-byte
17// cache lines (aarch64) or pull 64-byte cache lines in pairs (x86-64), without the need for
18// stubbing that type in when  `crossbeam-utils` isn't available. As blocks are fairly large (1
19// KiB), this simplification shouldn't severy affect the (rarer) targets with smaller cache lines.
20#[repr(align(128))]
21pub struct Block([u64; common::QWORDS_IN_BLOCK]);
22
23impl Block {
24    /// Gets the byte slice representation of the block.
25    pub fn as_u8(&self) -> &[u8] {
26        let bytes: &[u8; common::BLOCK_SIZE] = unsafe {
27            &*(&self.0 as *const [u64; common::QWORDS_IN_BLOCK] as *const [u8; common::BLOCK_SIZE])
28        };
29        bytes
30    }
31
32    /// Gets the mutable byte slice representation of the block.
33    pub fn as_u8_mut(&mut self) -> &mut [u8] {
34        let bytes: &mut [u8; common::BLOCK_SIZE] = unsafe {
35            &mut *(&mut self.0 as *mut [u64; common::QWORDS_IN_BLOCK]
36                as *mut [u8; common::BLOCK_SIZE])
37        };
38        bytes
39    }
40
41    /// Copies self to destination.
42    pub fn copy_to(&self, dst: &mut Block) {
43        for (d, s) in dst.0.iter_mut().zip(self.0.iter()) {
44            *d = *s
45        }
46    }
47
48    /// Creates a new block filled with zeros.
49    pub fn zero() -> Block {
50        Block([0u64; common::QWORDS_IN_BLOCK])
51    }
52}
53
54impl<'a> BitXorAssign<&'a Block> for Block {
55    fn bitxor_assign(&mut self, rhs: &Block) {
56        for (s, r) in self.0.iter_mut().zip(rhs.0.iter()) {
57            *s ^= *r
58        }
59    }
60}
61
62impl Clone for Block {
63    fn clone(&self) -> Block {
64        Block(self.0)
65    }
66}
67
68impl Debug for Block {
69    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
70        fmt.debug_list().entries(self.0.iter()).finish()
71    }
72}
73
74impl Eq for Block {}
75
76impl Index<usize> for Block {
77    type Output = u64;
78    fn index(&self, index: usize) -> &u64 {
79        &self.0[index]
80    }
81}
82
83impl IndexMut<usize> for Block {
84    fn index_mut(&mut self, index: usize) -> &mut u64 {
85        &mut self.0[index]
86    }
87}
88
89impl PartialEq for Block {
90    fn eq(&self, other: &Block) -> bool {
91        let mut equal = true;
92        for (s, o) in self.0.iter().zip(other.0.iter()) {
93            if s != o {
94                equal = false;
95            }
96        }
97        equal
98    }
99}
100
101#[cfg(test)]
102mod tests {
103
104    use crate::block::Block;
105    use crate::common;
106
107    #[test]
108    fn as_u8_returns_correct_slice() {
109        let block = Block::zero();
110        let expected = vec![0u8; 1024];
111        let actual = block.as_u8();
112        assert_eq!(actual, expected.as_slice());
113    }
114
115    #[test]
116    fn as_u8_mut_returns_correct_slice() {
117        let mut block = Block::zero();
118        let mut expected = vec![0u8; 1024];
119        let actual = block.as_u8_mut();
120        assert_eq!(actual, expected.as_mut_slice());
121    }
122
123    #[test]
124    fn bitxor_assign_updates_lhs() {
125        let mut lhs = Block([0u64; common::QWORDS_IN_BLOCK]);
126        let rhs = Block([1u64; common::QWORDS_IN_BLOCK]);
127        lhs ^= &rhs;
128        assert_eq!(lhs, rhs);
129    }
130
131    #[test]
132    fn copy_to_copies_block() {
133        let src = Block([1u64; common::QWORDS_IN_BLOCK]);
134        let mut dst = Block([0u64; common::QWORDS_IN_BLOCK]);
135        src.copy_to(&mut dst);
136        assert_eq!(dst, src);
137    }
138
139    #[test]
140    fn clone_clones_block() {
141        let orig = Block([1u64; common::QWORDS_IN_BLOCK]);
142        let copy = orig.clone();
143        assert_eq!(copy, orig);
144    }
145
146    #[test]
147    fn zero_creates_block_will_all_zeros() {
148        let expected = Block([0u64; common::QWORDS_IN_BLOCK]);
149        let actual = Block::zero();
150        assert_eq!(actual, expected);
151    }
152}