1use crate::block::Block;
10use crate::common;
11use crate::context::Context;
12use crate::memory::Memory;
13use crate::variant::Variant;
14use crate::version::Version;
15use blake2b_simd::Params;
16
17#[derive(Clone, Debug)]
19struct Position {
20 pass: u32,
21 lane: u32,
22 slice: u32,
23 index: u32,
24}
25
26pub fn initialize(context: &Context, memory: &mut Memory) {
28 fill_first_blocks(context, memory, &mut h0(context));
29}
30
31pub fn fill_memory_blocks(context: &Context, memory: &mut Memory) {
33 fill_memory_blocks_st(context, memory);
34}
35
36pub fn finalize(context: &Context, memory: &Memory) -> Vec<u8> {
38 let mut blockhash = memory[context.lane_length - 1].clone();
39 for l in 1..context.config.lanes {
40 let last_block_in_lane = l * context.lane_length + (context.lane_length - 1);
41 blockhash ^= &memory[last_block_in_lane];
42 }
43
44 let mut hash = vec![0u8; context.config.hash_length as usize];
45 hprime(hash.as_mut_slice(), blockhash.as_u8());
46 hash
47}
48
49fn blake2b(out: &mut [u8], input: &[&[u8]]) {
50 let mut blake = Params::new().hash_length(out.len()).to_state();
51 for slice in input {
52 blake.update(slice);
53 }
54 out.copy_from_slice(blake.finalize().as_bytes());
55}
56
57fn f_bla_mka(x: u64, y: u64) -> u64 {
58 let m = 0xFFFF_FFFFu64;
59 let xy = (x & m) * (y & m);
60 x.wrapping_add(y.wrapping_add(xy.wrapping_add(xy)))
61}
62
63fn fill_block(prev_block: &Block, ref_block: &Block, next_block: &mut Block, with_xor: bool) {
64 let mut block_r = ref_block.clone();
65 block_r ^= prev_block;
66 let mut block_tmp = block_r.clone();
67
68 if with_xor {
70 block_tmp ^= next_block;
72 }
75
76 for i in 0..8 {
79 let mut v0 = block_r[16 * i];
80 let mut v1 = block_r[16 * i + 1];
81 let mut v2 = block_r[16 * i + 2];
82 let mut v3 = block_r[16 * i + 3];
83 let mut v4 = block_r[16 * i + 4];
84 let mut v5 = block_r[16 * i + 5];
85 let mut v6 = block_r[16 * i + 6];
86 let mut v7 = block_r[16 * i + 7];
87 let mut v8 = block_r[16 * i + 8];
88 let mut v9 = block_r[16 * i + 9];
89 let mut v10 = block_r[16 * i + 10];
90 let mut v11 = block_r[16 * i + 11];
91 let mut v12 = block_r[16 * i + 12];
92 let mut v13 = block_r[16 * i + 13];
93 let mut v14 = block_r[16 * i + 14];
94 let mut v15 = block_r[16 * i + 15];
95
96 p(
97 &mut v0, &mut v1, &mut v2, &mut v3, &mut v4, &mut v5, &mut v6, &mut v7, &mut v8,
98 &mut v9, &mut v10, &mut v11, &mut v12, &mut v13, &mut v14, &mut v15,
99 );
100
101 block_r[16 * i] = v0;
102 block_r[16 * i + 1] = v1;
103 block_r[16 * i + 2] = v2;
104 block_r[16 * i + 3] = v3;
105 block_r[16 * i + 4] = v4;
106 block_r[16 * i + 5] = v5;
107 block_r[16 * i + 6] = v6;
108 block_r[16 * i + 7] = v7;
109 block_r[16 * i + 8] = v8;
110 block_r[16 * i + 9] = v9;
111 block_r[16 * i + 10] = v10;
112 block_r[16 * i + 11] = v11;
113 block_r[16 * i + 12] = v12;
114 block_r[16 * i + 13] = v13;
115 block_r[16 * i + 14] = v14;
116 block_r[16 * i + 15] = v15;
117 }
118
119 for i in 0..8 {
122 let mut v0 = block_r[2 * i];
123 let mut v1 = block_r[2 * i + 1];
124 let mut v2 = block_r[2 * i + 16];
125 let mut v3 = block_r[2 * i + 17];
126 let mut v4 = block_r[2 * i + 32];
127 let mut v5 = block_r[2 * i + 33];
128 let mut v6 = block_r[2 * i + 48];
129 let mut v7 = block_r[2 * i + 49];
130 let mut v8 = block_r[2 * i + 64];
131 let mut v9 = block_r[2 * i + 65];
132 let mut v10 = block_r[2 * i + 80];
133 let mut v11 = block_r[2 * i + 81];
134 let mut v12 = block_r[2 * i + 96];
135 let mut v13 = block_r[2 * i + 97];
136 let mut v14 = block_r[2 * i + 112];
137 let mut v15 = block_r[2 * i + 113];
138
139 p(
140 &mut v0, &mut v1, &mut v2, &mut v3, &mut v4, &mut v5, &mut v6, &mut v7, &mut v8,
141 &mut v9, &mut v10, &mut v11, &mut v12, &mut v13, &mut v14, &mut v15,
142 );
143
144 block_r[2 * i] = v0;
145 block_r[2 * i + 1] = v1;
146 block_r[2 * i + 16] = v2;
147 block_r[2 * i + 17] = v3;
148 block_r[2 * i + 32] = v4;
149 block_r[2 * i + 33] = v5;
150 block_r[2 * i + 48] = v6;
151 block_r[2 * i + 49] = v7;
152 block_r[2 * i + 64] = v8;
153 block_r[2 * i + 65] = v9;
154 block_r[2 * i + 80] = v10;
155 block_r[2 * i + 81] = v11;
156 block_r[2 * i + 96] = v12;
157 block_r[2 * i + 97] = v13;
158 block_r[2 * i + 112] = v14;
159 block_r[2 * i + 113] = v15;
160 }
161
162 block_tmp.copy_to(next_block);
163 *next_block ^= &block_r;
164}
165
166fn fill_first_blocks(context: &Context, memory: &mut Memory, h0: &mut [u8]) {
167 for lane in 0..context.config.lanes {
168 let start = common::PREHASH_DIGEST_LENGTH;
169 h0[start..(start + 4)].clone_from_slice(&u32::to_le_bytes(0));
171 h0[(start + 4)..(start + 8)].clone_from_slice(&u32::to_le_bytes(lane));
172 hprime(memory[(lane, 0)].as_u8_mut(), &h0);
173
174 h0[start..(start + 4)].clone_from_slice(&u32::to_le_bytes(1));
176 hprime(memory[(lane, 1)].as_u8_mut(), &h0);
177 }
178}
179
180fn fill_memory_blocks_st(context: &Context, memory: &mut Memory) {
181 for p in 0..context.config.time_cost {
182 for s in 0..common::SYNC_POINTS {
183 for l in 0..context.config.lanes {
184 let position = Position {
185 pass: p,
186 lane: l,
187 slice: s,
188 index: 0,
189 };
190 fill_segment(context, &position, memory);
191 }
192 }
193 }
194}
195
196fn fill_segment(context: &Context, position: &Position, memory: &mut Memory) {
197 let mut position = position.clone();
198 let data_independent_addressing = (context.config.variant == Variant::Argon2i)
199 || (context.config.variant == Variant::Argon2id && position.pass == 0)
200 && (position.slice < (common::SYNC_POINTS / 2));
201 let zero_block = Block::zero();
202 let mut input_block = Block::zero();
203 let mut address_block = Block::zero();
204
205 if data_independent_addressing {
206 input_block[0] = position.pass as u64;
207 input_block[1] = position.lane as u64;
208 input_block[2] = position.slice as u64;
209 input_block[3] = context.memory_blocks as u64;
210 input_block[4] = context.config.time_cost as u64;
211 input_block[5] = context.config.variant.as_u64();
212 }
213
214 let mut starting_index = 0u32;
215
216 if position.pass == 0 && position.slice == 0 {
217 starting_index = 2;
218
219 if data_independent_addressing {
221 next_addresses(&mut address_block, &mut input_block, &zero_block);
222 }
223 }
224
225 let mut curr_offset = (position.lane * context.lane_length)
226 + (position.slice * context.segment_length)
227 + starting_index;
228
229 let mut prev_offset = if curr_offset % context.lane_length == 0 {
230 curr_offset + context.lane_length - 1
232 } else {
233 curr_offset - 1
234 };
235
236 let mut pseudo_rand;
237 for i in starting_index..context.segment_length {
238 if curr_offset % context.lane_length == 1 {
240 prev_offset = curr_offset - 1;
241 }
242
243 if data_independent_addressing {
246 if i % common::ADDRESSES_IN_BLOCK == 0 {
247 next_addresses(&mut address_block, &mut input_block, &zero_block);
248 }
249 pseudo_rand = address_block[(i % common::ADDRESSES_IN_BLOCK) as usize];
250 } else {
251 pseudo_rand = memory[prev_offset][0];
252 }
253
254 let ref_lane = if (position.pass == 0) && (position.slice == 0) {
257 position.lane as u64
258 } else {
259 (pseudo_rand >> 32) % context.config.lanes as u64
260 };
261
262 position.index = i;
264 let pseudo_rand_u32 = (pseudo_rand & 0xFFFF_FFFF) as u32;
265 let same_lane = ref_lane == (position.lane as u64);
266 let ref_index = index_alpha(context, &position, pseudo_rand_u32, same_lane);
267
268 let index = context.lane_length as u64 * ref_lane + ref_index as u64;
270 let mut curr_block = memory[curr_offset].clone();
271 {
272 let prev_block = &memory[prev_offset];
273 let ref_block = &memory[index];
274 if context.config.version == Version::Version10 || position.pass == 0 {
275 fill_block(prev_block, ref_block, &mut curr_block, false);
276 } else {
277 fill_block(prev_block, ref_block, &mut curr_block, true);
278 }
279 }
280
281 memory[curr_offset] = curr_block;
282 curr_offset += 1;
283 prev_offset += 1;
284 }
285}
286
287fn g(a: &mut u64, b: &mut u64, c: &mut u64, d: &mut u64) {
288 *a = f_bla_mka(*a, *b);
289 *d = rotr64(*d ^ *a, 32);
290 *c = f_bla_mka(*c, *d);
291 *b = rotr64(*b ^ *c, 24);
292 *a = f_bla_mka(*a, *b);
293 *d = rotr64(*d ^ *a, 16);
294 *c = f_bla_mka(*c, *d);
295 *b = rotr64(*b ^ *c, 63);
296}
297
298fn h0(context: &Context) -> [u8; common::PREHASH_SEED_LENGTH] {
299 let input = [
300 &u32::to_le_bytes(context.config.lanes),
301 &u32::to_le_bytes(context.config.hash_length),
302 &u32::to_le_bytes(context.config.mem_cost),
303 &u32::to_le_bytes(context.config.time_cost),
304 &u32::to_le_bytes(context.config.version.as_u32()),
305 &u32::to_le_bytes(context.config.variant.as_u32()),
306 &len_as_32le(context.pwd),
307 context.pwd,
308 &len_as_32le(context.salt),
309 context.salt,
310 &len_as_32le(context.config.secret),
311 context.config.secret,
312 &len_as_32le(context.config.ad),
313 context.config.ad,
314 ];
315 let mut out = [0u8; common::PREHASH_SEED_LENGTH];
316 blake2b(&mut out[0..common::PREHASH_DIGEST_LENGTH], &input);
317 out
318}
319
320fn hprime(out: &mut [u8], input: &[u8]) {
321 let out_len = out.len();
322 if out_len <= common::BLAKE2B_OUT_LENGTH {
323 blake2b(out, &[&u32::to_le_bytes(out_len as u32), input]);
324 } else {
325 let ai_len = 32;
326 let mut out_buffer = [0u8; common::BLAKE2B_OUT_LENGTH];
327 let mut in_buffer = [0u8; common::BLAKE2B_OUT_LENGTH];
328 blake2b(&mut out_buffer, &[&u32::to_le_bytes(out_len as u32), input]);
329 out[0..ai_len].clone_from_slice(&out_buffer[0..ai_len]);
330 let mut out_pos = ai_len;
331 let mut to_produce = out_len - ai_len;
332
333 while to_produce > common::BLAKE2B_OUT_LENGTH {
334 in_buffer.clone_from_slice(&out_buffer);
335 blake2b(&mut out_buffer, &[&in_buffer]);
336 out[out_pos..out_pos + ai_len].clone_from_slice(&out_buffer[0..ai_len]);
337 out_pos += ai_len;
338 to_produce -= ai_len;
339 }
340 blake2b(&mut out[out_pos..out_len], &[&out_buffer]);
341 }
342}
343
344fn index_alpha(context: &Context, position: &Position, pseudo_rand: u32, same_lane: bool) -> u32 {
345 let reference_area_size: u32 = if position.pass == 0 {
352 if position.slice == 0 {
354 position.index - 1
356 } else if same_lane {
357 position.slice * context.segment_length + position.index - 1
359 } else if position.index == 0 {
360 position.slice * context.segment_length - 1
361 } else {
362 position.slice * context.segment_length
363 }
364 } else {
365 if same_lane {
367 context.lane_length - context.segment_length + position.index - 1
368 } else if position.index == 0 {
369 context.lane_length - context.segment_length - 1
370 } else {
371 context.lane_length - context.segment_length
372 }
373 };
374 let reference_area_size = reference_area_size as u64;
375 let mut relative_position = pseudo_rand as u64;
376 relative_position = (relative_position * relative_position) >> 32;
377 relative_position = reference_area_size - 1 - ((reference_area_size * relative_position) >> 32);
378
379 let start_position: u32 = if position.pass != 0 {
381 if position.slice == common::SYNC_POINTS - 1 {
382 0u32
383 } else {
384 (position.slice + 1) * context.segment_length
385 }
386 } else {
387 0u32
388 };
389 let start_position = start_position as u64;
390
391 ((start_position + relative_position) % context.lane_length as u64) as u32
393}
394
395fn len_as_32le(slice: &[u8]) -> [u8; 4] {
396 u32::to_le_bytes(slice.len() as u32)
397}
398
399fn next_addresses(address_block: &mut Block, input_block: &mut Block, zero_block: &Block) {
400 input_block[6] += 1;
401 fill_block(zero_block, input_block, address_block, false);
402 fill_block(zero_block, &address_block.clone(), address_block, false);
403}
404
405fn p(
406 v0: &mut u64,
407 v1: &mut u64,
408 v2: &mut u64,
409 v3: &mut u64,
410 v4: &mut u64,
411 v5: &mut u64,
412 v6: &mut u64,
413 v7: &mut u64,
414 v8: &mut u64,
415 v9: &mut u64,
416 v10: &mut u64,
417 v11: &mut u64,
418 v12: &mut u64,
419 v13: &mut u64,
420 v14: &mut u64,
421 v15: &mut u64,
422) {
423 g(v0, v4, v8, v12);
424 g(v1, v5, v9, v13);
425 g(v2, v6, v10, v14);
426 g(v3, v7, v11, v15);
427 g(v0, v5, v10, v15);
428 g(v1, v6, v11, v12);
429 g(v2, v7, v8, v13);
430 g(v3, v4, v9, v14);
431}
432
433fn rotr64(w: u64, c: u32) -> u64 {
434 (w >> c) | (w << (64 - c))
435}