Skip to content

Commit

Permalink
argon2: move segment length calculation to Memory type (#159)
Browse files Browse the repository at this point in the history
Begins the work of moving calculations about the memory buffer to the
`Memory` type.
  • Loading branch information
tarcieri committed Apr 19, 2021
1 parent a1b7413 commit 8a3f906
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 39 deletions.
25 changes: 13 additions & 12 deletions argon2/src/instance.rs
Expand Up @@ -52,9 +52,6 @@ pub(crate) struct Instance<'a> {
/// Number of passes
passes: u32,

/// Segment length
segment_length: u32,

/// Lane length
lane_length: u32,

Expand Down Expand Up @@ -97,12 +94,13 @@ impl<'a> Instance<'a> {
mut initial_hash: digest::Output<Blake2b>,
memory: Memory<'a>,
) -> Result<Self, Error> {
let lane_length = memory.segment_length() * SYNC_POINTS;

let mut instance = Instance {
version: context.version,
memory,
passes: context.t_cost,
segment_length: context.segment_length(),
lane_length: context.segment_length() * SYNC_POINTS,
lane_length,
lanes: context.lanes,
threads: context.threads,
alg,
Expand Down Expand Up @@ -272,7 +270,7 @@ impl<'a> Instance<'a> {

// Offset of the current block
let mut curr_offset = position.lane * self.lane_length
+ position.slice * self.segment_length
+ position.slice * self.memory.segment_length()
+ starting_index;

let mut prev_offset = if 0 == curr_offset % self.lane_length {
Expand All @@ -283,7 +281,7 @@ impl<'a> Instance<'a> {
curr_offset - 1
};

for i in starting_index..self.segment_length {
for i in starting_index..self.memory.segment_length() {
// 1.1 Rotating prev_offset if needed
if curr_offset % self.lane_length == 1 {
prev_offset = curr_offset - 1;
Expand Down Expand Up @@ -361,16 +359,19 @@ impl<'a> Instance<'a> {
position.index - 1 // all but the previous
} else if same_lane {
// The same lane => add current segment
position.slice * self.segment_length + position.index - 1
position.slice * self.memory.segment_length() + position.index - 1
} else {
position.slice * self.segment_length - if position.index == 0 { 1 } else { 0 }
position.slice * self.memory.segment_length()
- if position.index == 0 { 1 } else { 0 }
}
} else {
// Second pass
if same_lane {
self.lane_length - self.segment_length + position.index - 1
self.lane_length - self.memory.segment_length() + position.index - 1
} else {
self.lane_length - self.segment_length - if position.index == 0 { 1 } else { 0 }
self.lane_length
- self.memory.segment_length()
- if position.index == 0 { 1 } else { 0 }
}
};

Expand All @@ -389,7 +390,7 @@ impl<'a> Instance<'a> {
start_position = if position.slice == SYNC_POINTS - 1 {
0
} else {
(position.slice + 1) * self.segment_length
(position.slice + 1) * self.memory.segment_length()
}
}

Expand Down
31 changes: 11 additions & 20 deletions argon2/src/lib.rs
Expand Up @@ -87,7 +87,11 @@ pub use crate::error::Error;
#[cfg_attr(docsrs, doc(cfg(feature = "password-hash")))]
pub use password_hash::{self, PasswordHash, PasswordHasher, PasswordVerifier};

use crate::{block::Block, instance::Instance, memory::Memory};
use crate::{
block::Block,
instance::Instance,
memory::{Memory, SYNC_POINTS},
};
use blake2::{digest, Blake2b, Digest};
use core::{
convert::TryFrom,
Expand Down Expand Up @@ -149,9 +153,6 @@ pub const MAX_SECRET: usize = 0xFFFFFFFF;
/// Memory block size in bytes
pub const BLOCK_SIZE: usize = 1024;

/// Number of synchronization points between lanes per pass
const SYNC_POINTS: u32 = 4;

/// Argon2d algorithm identifier
#[cfg(feature = "password-hash")]
#[cfg_attr(docsrs, doc(cfg(feature = "password-hash")))]
Expand Down Expand Up @@ -478,15 +479,17 @@ impl<'key> Argon2<'key> {
return Err(Error::AdTooLong);
}

let memory_blocks = (self.segment_length() * self.lanes * SYNC_POINTS) as usize;

// Hashing all inputs
let initial_hash = self.initial_hash(alg, pwd, salt, ad, out);

let segment_length = Memory::segment_length_for_params(self.m_cost, self.lanes);
let blocks_count = (segment_length * self.lanes * SYNC_POINTS) as usize;

// TODO(tarcieri): support for stack-allocated memory blocks (i.e. no alloc)
let mut memory = vec![Block::default(); memory_blocks];
let mut blocks = vec![Block::default(); blocks_count];

Instance::hash(self, alg, initial_hash, Memory::new(&mut memory), out)
let memory = Memory::new(&mut blocks, segment_length);
Instance::hash(self, alg, initial_hash, memory, out)
}

/// Hashes all the inputs into `blockhash[PREHASH_DIGEST_LENGTH]`.
Expand Down Expand Up @@ -521,18 +524,6 @@ impl<'key> Argon2<'key> {
digest.update(ad);
digest.finalize()
}

pub(crate) fn segment_length(&self) -> u32 {
// Align memory size
// Minimum memory_blocks = 8L blocks, where L is the number of lanes
let memory_blocks = if self.m_cost < 2 * SYNC_POINTS * self.lanes {
2 * SYNC_POINTS * self.lanes
} else {
self.m_cost
};

memory_blocks / (self.lanes * SYNC_POINTS)
}
}

#[cfg(feature = "password-hash")]
Expand Down
38 changes: 31 additions & 7 deletions argon2/src/memory.rs
Expand Up @@ -2,21 +2,38 @@

use crate::Block;

/// Number of synchronization points between lanes per pass
pub(crate) const SYNC_POINTS: u32 = 4;

/// Structure containing references to the memory blocks
pub(crate) struct Memory<'a> {
/// Memory blocks
data: &'a mut [Block],

/// Size of the memory in blocks
size: usize,
/// Size of a memory segment in blocks
segment_length: u32,
}

impl<'a> Memory<'a> {
/// Instantiate a new memory struct
pub(crate) fn new(data: &'a mut [Block]) -> Self {
let size = data.len();
/// Align memory size.
///
/// Minimum memory_blocks = 8*`L` blocks, where `L` is the number of lanes.
pub(crate) fn segment_length_for_params(m_cost: u32, lanes: u32) -> u32 {
let memory_blocks = if m_cost < 2 * SYNC_POINTS * lanes {
2 * SYNC_POINTS * lanes
} else {
m_cost
};

memory_blocks / (lanes * SYNC_POINTS)
}

Self { data, size }
/// Instantiate a new memory struct
pub(crate) fn new(data: &'a mut [Block], segment_length: u32) -> Self {
Self {
data,
segment_length,
}
}

/// Get a copy of the block
Expand All @@ -30,7 +47,14 @@ impl<'a> Memory<'a> {
}

/// Size of the memory
#[inline]
pub(crate) fn len(&self) -> usize {
self.size
self.data.len()
}

/// Size of a memory segment
#[inline]
pub(crate) fn segment_length(&self) -> u32 {
self.segment_length
}
}

0 comments on commit 8a3f906

Please sign in to comment.