Coverage Report

Created: 2025-11-28 06:44

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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
}