Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

argon2: add parallelism #547

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions argon2/Cargo.toml
Original file line number Diff line number Diff line change
@@ -21,6 +21,7 @@ base64ct = "1"
blake2 = { version = "=0.11.0-pre.5", default-features = false }

# optional dependencies
rayon = { version = "1.7", optional = true }
password-hash = { version = "0.6.0-rc.0", optional = true }
zeroize = { version = "1", default-features = false, optional = true }

@@ -36,6 +37,7 @@ default = ["alloc", "password-hash", "rand"]
alloc = ["password-hash?/alloc"]
std = ["alloc", "password-hash?/os_rng", "base64ct/std"]

parallel = ["dep:rayon", "std"]
rand = ["password-hash?/rand_core"]
simple = ["password-hash"]
zeroize = ["dep:zeroize"]
200 changes: 101 additions & 99 deletions argon2/src/lib.rs
Original file line number Diff line number Diff line change
@@ -153,6 +153,7 @@ mod algorithm;
mod blake2b_long;
mod block;
mod error;
mod memory;
mod params;
mod version;

@@ -174,6 +175,7 @@ pub use {
use crate::blake2b_long::blake2b_long;
use blake2::{Blake2b512, Digest, digest};
use core::fmt;
use memory::Memory;

#[cfg(all(feature = "alloc", feature = "password-hash"))]
use password_hash::{Decimal, Ident, ParamsString, Salt};
@@ -349,7 +351,7 @@ impl<'key> Argon2<'key> {
mut initial_hash: digest::Output<Blake2b512>,
) -> Result<()> {
let block_count = self.params.block_count();
let memory_blocks = memory_blocks
let mut memory_blocks = memory_blocks
.get_mut(..block_count)
.ok_or(Error::MemoryTooLittle)?;

@@ -383,133 +385,133 @@ impl<'key> Argon2<'key> {

// Run passes on blocks
for pass in 0..iterations {
for slice in 0..SYNC_POINTS {
memory_blocks.for_each_segment(lanes, |mut memory_view, slice, lane| {
let data_independent_addressing = self.algorithm == Algorithm::Argon2i
|| (self.algorithm == Algorithm::Argon2id
&& pass == 0
&& slice < SYNC_POINTS / 2);

for lane in 0..lanes {
let mut address_block = Block::default();
let mut input_block = Block::default();
let zero_block = Block::default();
let mut address_block = Block::default();
let mut input_block = Block::default();
let zero_block = Block::default();

if data_independent_addressing {
input_block.as_mut()[..6].copy_from_slice(&[
pass as u64,
lane as u64,
slice as u64,
block_count as u64,
iterations as u64,
self.algorithm as u64,
]);
}

let first_block = if pass == 0 && slice == 0 {
if data_independent_addressing {
input_block.as_mut()[..6].copy_from_slice(&[
pass as u64,
lane as u64,
slice as u64,
memory_blocks.len() as u64,
iterations as u64,
self.algorithm as u64,
]);
// Generate first set of addresses
self.update_address_block(
&mut address_block,
&mut input_block,
&zero_block,
);
}

let first_block = if pass == 0 && slice == 0 {
if data_independent_addressing {
// Generate first set of addresses
// The first two blocks of each lane are already initialized
2
} else {
0
};

let mut cur_index = lane * lane_length + slice * segment_length + first_block;
let mut prev_index = if slice == 0 && first_block == 0 {
// Last block in current lane
cur_index + lane_length - 1
} else {
// Previous block
cur_index - 1
};

// Fill blocks in the segment
for block in first_block..segment_length {
// Extract entropy
let rand = if data_independent_addressing {
let addres_index = block % ADDRESSES_IN_BLOCK;

if addres_index == 0 {
self.update_address_block(
&mut address_block,
&mut input_block,
&zero_block,
);
}

// The first two blocks of each lane are already initialized
2
address_block.as_ref()[addres_index]
} else {
0
memory_view.get_block(prev_index).as_ref()[0]
};

let mut cur_index = lane * lane_length + slice * segment_length + first_block;
let mut prev_index = if slice == 0 && first_block == 0 {
// Last block in current lane
cur_index + lane_length - 1
// Calculate source block index for compress function
let ref_lane = if pass == 0 && slice == 0 {
// Cannot reference other lanes yet
lane
} else {
// Previous block
cur_index - 1
(rand >> 32) as usize % lanes
};

// Fill blocks in the segment
for block in first_block..segment_length {
// Extract entropy
let rand = if data_independent_addressing {
let addres_index = block % ADDRESSES_IN_BLOCK;

if addres_index == 0 {
self.update_address_block(
&mut address_block,
&mut input_block,
&zero_block,
);
}

address_block.as_ref()[addres_index]
} else {
memory_blocks[prev_index].as_ref()[0]
};

// Calculate source block index for compress function
let ref_lane = if pass == 0 && slice == 0 {
// Cannot reference other lanes yet
lane
} else {
(rand >> 32) as usize % lanes
};

let reference_area_size = if pass == 0 {
// First pass
if slice == 0 {
// First slice
block - 1 // all but the previous
} else if ref_lane == lane {
// The same lane => add current segment
slice * segment_length + block - 1
} else {
slice * segment_length - if block == 0 { 1 } else { 0 }
}
let reference_area_size = if pass == 0 {
// First pass
if slice == 0 {
// First slice
block - 1 // all but the previous
} else if ref_lane == lane {
// The same lane => add current segment
slice * segment_length + block - 1
} else {
// Second pass
if ref_lane == lane {
lane_length - segment_length + block - 1
} else {
lane_length - segment_length - if block == 0 { 1 } else { 0 }
}
};

// 1.2.4. Mapping rand to 0..<reference_area_size-1> and produce
// relative position
let mut map = rand & 0xFFFFFFFF;
map = (map * map) >> 32;
let relative_position = reference_area_size
- 1
- ((reference_area_size as u64 * map) >> 32) as usize;

// 1.2.5 Computing starting position
let start_position = if pass != 0 && slice != SYNC_POINTS - 1 {
(slice + 1) * segment_length
slice * segment_length - if block == 0 { 1 } else { 0 }
}
} else {
// Second pass
if ref_lane == lane {
lane_length - segment_length + block - 1
} else {
0
};
lane_length - segment_length - if block == 0 { 1 } else { 0 }
}
};

let lane_index = (start_position + relative_position) % lane_length;
let ref_index = ref_lane * lane_length + lane_index;
// 1.2.4. Mapping rand to 0..<reference_area_size-1> and produce
// relative position
let mut map = rand & 0xFFFFFFFF;
map = (map * map) >> 32;
let relative_position = reference_area_size
- 1
- ((reference_area_size as u64 * map) >> 32) as usize;

// 1.2.5 Computing starting position
let start_position = if pass != 0 && slice != SYNC_POINTS - 1 {
(slice + 1) * segment_length
} else {
0
};

// Calculate new block
let result =
self.compress(&memory_blocks[prev_index], &memory_blocks[ref_index]);
let lane_index = (start_position + relative_position) % lane_length;
let ref_index = ref_lane * lane_length + lane_index;

if self.version == Version::V0x10 || pass == 0 {
memory_blocks[cur_index] = result;
} else {
memory_blocks[cur_index] ^= &result;
};
// Calculate new block
let result = self.compress(
memory_view.get_block(prev_index),
memory_view.get_block(ref_index),
);

prev_index = cur_index;
cur_index += 1;
}
if self.version == Version::V0x10 || pass == 0 {
*memory_view.get_block_mut(cur_index) = result;
} else {
*memory_view.get_block_mut(cur_index) ^= &result;
};

prev_index = cur_index;
cur_index += 1;
}
}
});
}

Ok(())
Loading