/rust/registry/src/index.crates.io-1949cf8c6b5b557f/scrypt-0.11.0/src/romix.rs
Line | Count | Source |
1 | | /// Execute the ROMix operation in-place. |
2 | | /// b - the data to operate on |
3 | | /// v - a temporary variable to store the vector V |
4 | | /// t - a temporary variable to store the result of the xor |
5 | | /// n - the scrypt parameter N |
6 | | #[allow(clippy::many_single_char_names)] |
7 | 0 | pub(crate) fn scrypt_ro_mix(b: &mut [u8], v: &mut [u8], t: &mut [u8], n: usize) { |
8 | 0 | fn integerify(x: &[u8], n: usize) -> usize { |
9 | | // n is a power of 2, so n - 1 gives us a bitmask that we can use to perform a calculation |
10 | | // mod n using a simple bitwise and. |
11 | 0 | let mask = n - 1; |
12 | | // This cast is safe since we're going to get the value mod n (which is a power of 2), so we |
13 | | // don't have to care about truncating any of the high bits off |
14 | | //let result = (LittleEndian::read_u32(&x[x.len() - 64..x.len() - 60]) as usize) & mask; |
15 | 0 | let t = u32::from_le_bytes(x[x.len() - 64..x.len() - 60].try_into().unwrap()); |
16 | 0 | (t as usize) & mask |
17 | 0 | } |
18 | | |
19 | 0 | let len = b.len(); |
20 | | |
21 | 0 | for chunk in v.chunks_mut(len) { |
22 | 0 | chunk.copy_from_slice(b); |
23 | 0 | scrypt_block_mix(chunk, b); |
24 | 0 | } |
25 | | |
26 | 0 | for _ in 0..n { |
27 | 0 | let j = integerify(b, n); |
28 | 0 | xor(b, &v[j * len..(j + 1) * len], t); |
29 | 0 | scrypt_block_mix(t, b); |
30 | 0 | } |
31 | 0 | } |
32 | | |
33 | | /// Execute the BlockMix operation |
34 | | /// input - the input vector. The length must be a multiple of 128. |
35 | | /// output - the output vector. Must be the same length as input. |
36 | 0 | fn scrypt_block_mix(input: &[u8], output: &mut [u8]) { |
37 | | use salsa20::{ |
38 | | cipher::{typenum::U4, StreamCipherCore}, |
39 | | SalsaCore, |
40 | | }; |
41 | | |
42 | | type Salsa20_8 = SalsaCore<U4>; |
43 | | |
44 | 0 | let mut x = [0u8; 64]; |
45 | 0 | x.copy_from_slice(&input[input.len() - 64..]); |
46 | | |
47 | 0 | let mut t = [0u8; 64]; |
48 | | |
49 | 0 | for (i, chunk) in input.chunks(64).enumerate() { |
50 | 0 | xor(&x, chunk, &mut t); |
51 | | |
52 | 0 | let mut t2 = [0u32; 16]; |
53 | | |
54 | 0 | for (c, b) in t.chunks_exact(4).zip(t2.iter_mut()) { |
55 | 0 | *b = u32::from_le_bytes(c.try_into().unwrap()); |
56 | 0 | } |
57 | | |
58 | 0 | Salsa20_8::from_raw_state(t2).write_keystream_block((&mut x).into()); |
59 | | |
60 | 0 | let pos = if i % 2 == 0 { |
61 | 0 | (i / 2) * 64 |
62 | | } else { |
63 | 0 | (i / 2) * 64 + input.len() / 2 |
64 | | }; |
65 | | |
66 | 0 | output[pos..pos + 64].copy_from_slice(&x); |
67 | | } |
68 | 0 | } |
69 | | |
70 | 0 | fn xor(x: &[u8], y: &[u8], output: &mut [u8]) { |
71 | 0 | for ((out, &x_i), &y_i) in output.iter_mut().zip(x.iter()).zip(y.iter()) { |
72 | 0 | *out = x_i ^ y_i; |
73 | 0 | } |
74 | 0 | } |