Skip to main content

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 (1KB) memory block implemented as 128 64-bit words.
15pub struct Block([u64; common::QWORDS_IN_BLOCK]);
16
17impl Block {
18    /// Gets the byte slice representation of the block.
19    pub fn as_u8(&self) -> &[u8] {
20        let bytes: &[u8; common::BLOCK_SIZE] = unsafe {
21            &*(&self.0 as *const [u64; common::QWORDS_IN_BLOCK] as *const [u8; common::BLOCK_SIZE])
22        };
23        bytes
24    }
25
26    /// Gets the mutable byte slice representation of the block.
27    pub fn as_u8_mut(&mut self) -> &mut [u8] {
28        let bytes: &mut [u8; common::BLOCK_SIZE] = unsafe {
29            &mut *(&mut self.0 as *mut [u64; common::QWORDS_IN_BLOCK]
30                as *mut [u8; common::BLOCK_SIZE])
31        };
32        bytes
33    }
34
35    /// Copies self to destination.
36    pub fn copy_to(&self, dst: &mut Block) {
37        for (d, s) in dst.0.iter_mut().zip(self.0.iter()) {
38            *d = *s
39        }
40    }
41
42    /// Creates a new block filled with zeros.
43    pub fn zero() -> Block {
44        Block([0u64; common::QWORDS_IN_BLOCK])
45    }
46}
47
48impl<'a> BitXorAssign<&'a Block> for Block {
49    fn bitxor_assign(&mut self, rhs: &Block) {
50        for (s, r) in self.0.iter_mut().zip(rhs.0.iter()) {
51            *s ^= *r
52        }
53    }
54}
55
56impl Clone for Block {
57    fn clone(&self) -> Block {
58        Block(self.0)
59    }
60}
61
62impl Debug for Block {
63    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
64        fmt.debug_list().entries(self.0.iter()).finish()
65    }
66}
67
68impl Eq for Block {}
69
70impl Index<usize> for Block {
71    type Output = u64;
72    fn index(&self, index: usize) -> &u64 {
73        &self.0[index]
74    }
75}
76
77impl IndexMut<usize> for Block {
78    fn index_mut(&mut self, index: usize) -> &mut u64 {
79        &mut self.0[index]
80    }
81}
82
83impl PartialEq for Block {
84    fn eq(&self, other: &Block) -> bool {
85        let mut equal = true;
86        for (s, o) in self.0.iter().zip(other.0.iter()) {
87            if s != o {
88                equal = false;
89            }
90        }
91        equal
92    }
93}
94
95#[cfg(test)]
96mod tests {
97
98    use crate::block::Block;
99    use crate::common;
100
101    #[test]
102    fn as_u8_returns_correct_slice() {
103        let block = Block::zero();
104        let expected = vec![0u8; 1024];
105        let actual = block.as_u8();
106        assert_eq!(actual, expected.as_slice());
107    }
108
109    #[test]
110    fn as_u8_mut_returns_correct_slice() {
111        let mut block = Block::zero();
112        let mut expected = vec![0u8; 1024];
113        let actual = block.as_u8_mut();
114        assert_eq!(actual, expected.as_mut_slice());
115    }
116
117    #[test]
118    fn bitxor_assign_updates_lhs() {
119        let mut lhs = Block([0u64; common::QWORDS_IN_BLOCK]);
120        let rhs = Block([1u64; common::QWORDS_IN_BLOCK]);
121        lhs ^= &rhs;
122        assert_eq!(lhs, rhs);
123    }
124
125    #[test]
126    fn copy_to_copies_block() {
127        let src = Block([1u64; common::QWORDS_IN_BLOCK]);
128        let mut dst = Block([0u64; common::QWORDS_IN_BLOCK]);
129        src.copy_to(&mut dst);
130        assert_eq!(dst, src);
131    }
132
133    #[test]
134    fn clone_clones_block() {
135        let orig = Block([1u64; common::QWORDS_IN_BLOCK]);
136        let copy = orig.clone();
137        assert_eq!(copy, orig);
138    }
139
140    #[test]
141    fn zero_creates_block_will_all_zeros() {
142        let expected = Block([0u64; common::QWORDS_IN_BLOCK]);
143        let actual = Block::zero();
144        assert_eq!(actual, expected);
145    }
146}