mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 12:51:06 +00:00
Bug 1770894 - Patch redox_users with an empty crate. r=emilio
We don't support redox, so we might as well avoid pulling dependencies we'll never need and may pull duplicates. Differential Revision: https://phabricator.services.mozilla.com/D147250
This commit is contained in:
parent
f9d9d6369f
commit
a10c04a7dc
38
Cargo.lock
generated
38
Cargo.lock
generated
@ -498,17 +498,6 @@ dependencies = [
|
||||
"xpcom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blake2b_simd"
|
||||
version = "0.5.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587"
|
||||
dependencies = [
|
||||
"arrayref",
|
||||
"arrayvec 0.5.2",
|
||||
"constant_time_eq",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block"
|
||||
version = "0.1.6"
|
||||
@ -764,12 +753,6 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"
|
||||
|
||||
[[package]]
|
||||
name = "cookie"
|
||||
version = "0.12.0"
|
||||
@ -4282,14 +4265,7 @@ checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce"
|
||||
|
||||
[[package]]
|
||||
name = "redox_users"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"redox_syscall",
|
||||
"rust-argon2",
|
||||
]
|
||||
version = "0.3.999"
|
||||
|
||||
[[package]]
|
||||
name = "regalloc"
|
||||
@ -4431,18 +4407,6 @@ dependencies = [
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-argon2"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb"
|
||||
dependencies = [
|
||||
"base64 0.13.0",
|
||||
"blake2b_simd",
|
||||
"constant_time_eq",
|
||||
"crossbeam-utils 0.8.8",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-ini"
|
||||
version = "0.10.3"
|
||||
|
@ -105,6 +105,9 @@ cfg-if = { path = "build/rust/cfg-if" }
|
||||
# Patch itertools 0.8 to 1.0
|
||||
itertools = { path = "build/rust/itertools" }
|
||||
|
||||
# Patch redox_users to an empty crate
|
||||
redox_users = { path = "build/rust/redox_users" }
|
||||
|
||||
# Patch autocfg to hide rustc output. Workaround for https://github.com/cuviper/autocfg/issues/30
|
||||
autocfg = { path = "third_party/rust/autocfg" }
|
||||
|
||||
|
8
build/rust/redox_users/Cargo.toml
Normal file
8
build/rust/redox_users/Cargo.toml
Normal file
@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "redox_users"
|
||||
version = "0.3.999"
|
||||
edition = "2018"
|
||||
license = "MPL-2.0"
|
||||
|
||||
[lib]
|
||||
path = "lib.rs"
|
3
build/rust/redox_users/lib.rs
Normal file
3
build/rust/redox_users/lib.rs
Normal file
@ -0,0 +1,3 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
@ -1 +0,0 @@
|
||||
{"files":{"Cargo.toml":"b79e2347297dee32b9483747ee3cf145bd60e8c9d14cc02929287dabde4685ff","README.md":"b90c7a163a0fbff29e2c049953968c8cbfe8aa616d7e36775f0a565761dcc671","src/avx2.rs":"b79f36e3a7442d241e3fdf2ec159866aea31b78883660a63cdc9b1a262f18d10","src/blake2bp.rs":"83577d4a22db3b92030d9bd4563aa9ad440f23c64a6ad5f10a9d709f22d50589","src/guts.rs":"1189cab87b18eaaf2abd5bcb3d7d799c75401a312cee6f1f65fdaad30203eb6f","src/lib.rs":"b0404c81988e4de8d8864437c512937d9e888c681ef4739ef2d5db1650bd8766","src/many.rs":"60d07e4d7ad63949fb5432ad05f7c6a525a3eee39d325f7d4e65e901b466be95","src/portable.rs":"a274acd298a394c014096a8214a0dc1db7439d1e920bd2ad75707fadcc501e10","src/sse41.rs":"58e9e2ec97d266e9fb4cfa874f8cfcf5ee046911837824ceea4b99cd4007560b","src/test.rs":"1685eec6fedc30fca1332cbb78c85e6c9b56eca962b6c6343c91ba69eefac754"},"package":"afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587"}
|
37
third_party/rust/blake2b_simd/Cargo.toml
vendored
37
third_party/rust/blake2b_simd/Cargo.toml
vendored
@ -1,37 +0,0 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "blake2b_simd"
|
||||
version = "0.5.11"
|
||||
authors = ["Jack O'Connor"]
|
||||
description = "a pure Rust BLAKE2b implementation with dynamic SIMD"
|
||||
documentation = "https://docs.rs/blake2b_simd"
|
||||
readme = "README.md"
|
||||
keywords = ["blake2b", "blake2bp", "blake2"]
|
||||
license = "MIT"
|
||||
repository = "https://github.com/oconnor663/blake2_simd"
|
||||
[dependencies.arrayref]
|
||||
version = "0.3.5"
|
||||
|
||||
[dependencies.arrayvec]
|
||||
version = "0.5.0"
|
||||
default-features = false
|
||||
|
||||
[dependencies.constant_time_eq]
|
||||
version = "0.1.3"
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = []
|
||||
uninline_portable = []
|
42
third_party/rust/blake2b_simd/README.md
vendored
42
third_party/rust/blake2b_simd/README.md
vendored
@ -1,42 +0,0 @@
|
||||
# blake2b_simd [![GitHub](https://img.shields.io/github/tag/oconnor663/blake2_simd.svg?label=GitHub)](https://github.com/oconnor663/blake2_simd) [![crates.io](https://img.shields.io/crates/v/blake2b_simd.svg)](https://crates.io/crates/blake2b_simd) [![Actions Status](https://github.com/oconnor663/blake2_simd/workflows/tests/badge.svg)](https://github.com/oconnor663/blake2_simd/actions)
|
||||
|
||||
An implementation of the BLAKE2b and BLAKE2bp hash functions. See also
|
||||
[`blake2s_simd`](../blake2s).
|
||||
|
||||
This crate includes:
|
||||
|
||||
- 100% stable Rust.
|
||||
- SIMD implementations based on Samuel Neves' [`blake2-avx2`](https://github.com/sneves/blake2-avx2).
|
||||
These are very fast. For benchmarks, see [the Performance section of the
|
||||
README](https://github.com/oconnor663/blake2_simd#performance).
|
||||
- Portable, safe implementations for other platforms.
|
||||
- Dynamic CPU feature detection. Binaries include multiple implementations by default and
|
||||
choose the fastest one the processor supports at runtime.
|
||||
- All the features from the [the BLAKE2 spec](https://blake2.net/blake2.pdf), like adjustable
|
||||
length, keying, and associated data for tree hashing.
|
||||
- `no_std` support. The `std` Cargo feature is on by default, for CPU feature detection and
|
||||
for implementing `std::io::Write`.
|
||||
- Support for computing multiple BLAKE2b hashes in parallel, matching the efficiency of
|
||||
BLAKE2bp. See the [`many`](many/index.html) module.
|
||||
|
||||
# Example
|
||||
|
||||
```
|
||||
use blake2b_simd::{blake2b, Params};
|
||||
|
||||
let expected = "ca002330e69d3e6b84a46a56a6533fd79d51d97a3bb7cad6c2ff43b354185d6d\
|
||||
c1e723fb3db4ae0737e120378424c714bb982d9dc5bbd7a0ab318240ddd18f8d";
|
||||
let hash = blake2b(b"foo");
|
||||
assert_eq!(expected, &hash.to_hex());
|
||||
|
||||
let hash = Params::new()
|
||||
.hash_length(16)
|
||||
.key(b"The Magic Words are Squeamish Ossifrage")
|
||||
.personal(b"L. P. Waterhouse")
|
||||
.to_state()
|
||||
.update(b"foo")
|
||||
.update(b"bar")
|
||||
.update(b"baz")
|
||||
.finalize();
|
||||
assert_eq!("ee8ff4e9be887297cf79348dc35dab56", &hash.to_hex());
|
||||
```
|
929
third_party/rust/blake2b_simd/src/avx2.rs
vendored
929
third_party/rust/blake2b_simd/src/avx2.rs
vendored
@ -1,929 +0,0 @@
|
||||
#[cfg(target_arch = "x86")]
|
||||
use core::arch::x86::*;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use core::arch::x86_64::*;
|
||||
|
||||
use crate::guts::{
|
||||
assemble_count, count_high, count_low, final_block, flag_word, input_debug_asserts, Finalize,
|
||||
Job, LastNode, Stride,
|
||||
};
|
||||
use crate::{Count, Word, BLOCKBYTES, IV, SIGMA};
|
||||
use arrayref::{array_refs, mut_array_refs};
|
||||
use core::cmp;
|
||||
use core::mem;
|
||||
|
||||
pub const DEGREE: usize = 4;
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn loadu(src: *const [Word; DEGREE]) -> __m256i {
|
||||
// This is an unaligned load, so the pointer cast is allowed.
|
||||
_mm256_loadu_si256(src as *const __m256i)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn storeu(src: __m256i, dest: *mut [Word; DEGREE]) {
|
||||
// This is an unaligned store, so the pointer cast is allowed.
|
||||
_mm256_storeu_si256(dest as *mut __m256i, src)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn loadu_128(mem_addr: &[u8; 16]) -> __m128i {
|
||||
_mm_loadu_si128(mem_addr.as_ptr() as *const __m128i)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn add(a: __m256i, b: __m256i) -> __m256i {
|
||||
_mm256_add_epi64(a, b)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn eq(a: __m256i, b: __m256i) -> __m256i {
|
||||
_mm256_cmpeq_epi64(a, b)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn and(a: __m256i, b: __m256i) -> __m256i {
|
||||
_mm256_and_si256(a, b)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn negate_and(a: __m256i, b: __m256i) -> __m256i {
|
||||
// Note that "and not" implies the reverse of the actual arg order.
|
||||
_mm256_andnot_si256(a, b)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn xor(a: __m256i, b: __m256i) -> __m256i {
|
||||
_mm256_xor_si256(a, b)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn set1(x: u64) -> __m256i {
|
||||
_mm256_set1_epi64x(x as i64)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn set4(a: u64, b: u64, c: u64, d: u64) -> __m256i {
|
||||
_mm256_setr_epi64x(a as i64, b as i64, c as i64, d as i64)
|
||||
}
|
||||
|
||||
// Adapted from https://github.com/rust-lang-nursery/stdsimd/pull/479.
|
||||
macro_rules! _MM_SHUFFLE {
|
||||
($z:expr, $y:expr, $x:expr, $w:expr) => {
|
||||
($z << 6) | ($y << 4) | ($x << 2) | $w
|
||||
};
|
||||
}
|
||||
|
||||
// These rotations are the "simple version". For the "complicated version", see
|
||||
// https://github.com/sneves/blake2-avx2/blob/b3723921f668df09ece52dcd225a36d4a4eea1d9/blake2b-common.h#L43-L46.
|
||||
// For a discussion of the tradeoffs, see
|
||||
// https://github.com/sneves/blake2-avx2/pull/5. In short:
|
||||
// - Due to an LLVM bug (https://bugs.llvm.org/show_bug.cgi?id=44379), this
|
||||
// version performs better on recent x86 chips.
|
||||
// - LLVM is able to optimize this version to AVX-512 rotation instructions
|
||||
// when those are enabled.
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn rot32(x: __m256i) -> __m256i {
|
||||
_mm256_or_si256(_mm256_srli_epi64(x, 32), _mm256_slli_epi64(x, 64 - 32))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn rot24(x: __m256i) -> __m256i {
|
||||
_mm256_or_si256(_mm256_srli_epi64(x, 24), _mm256_slli_epi64(x, 64 - 24))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn rot16(x: __m256i) -> __m256i {
|
||||
_mm256_or_si256(_mm256_srli_epi64(x, 16), _mm256_slli_epi64(x, 64 - 16))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn rot63(x: __m256i) -> __m256i {
|
||||
_mm256_or_si256(_mm256_srli_epi64(x, 63), _mm256_slli_epi64(x, 64 - 63))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn g1(a: &mut __m256i, b: &mut __m256i, c: &mut __m256i, d: &mut __m256i, m: &mut __m256i) {
|
||||
*a = add(*a, *m);
|
||||
*a = add(*a, *b);
|
||||
*d = xor(*d, *a);
|
||||
*d = rot32(*d);
|
||||
*c = add(*c, *d);
|
||||
*b = xor(*b, *c);
|
||||
*b = rot24(*b);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn g2(a: &mut __m256i, b: &mut __m256i, c: &mut __m256i, d: &mut __m256i, m: &mut __m256i) {
|
||||
*a = add(*a, *m);
|
||||
*a = add(*a, *b);
|
||||
*d = xor(*d, *a);
|
||||
*d = rot16(*d);
|
||||
*c = add(*c, *d);
|
||||
*b = xor(*b, *c);
|
||||
*b = rot63(*b);
|
||||
}
|
||||
|
||||
// Note the optimization here of leaving b as the unrotated row, rather than a.
|
||||
// All the message loads below are adjusted to compensate for this. See
|
||||
// discussion at https://github.com/sneves/blake2-avx2/pull/4
|
||||
#[inline(always)]
|
||||
unsafe fn diagonalize(a: &mut __m256i, _b: &mut __m256i, c: &mut __m256i, d: &mut __m256i) {
|
||||
*a = _mm256_permute4x64_epi64(*a, _MM_SHUFFLE!(2, 1, 0, 3));
|
||||
*d = _mm256_permute4x64_epi64(*d, _MM_SHUFFLE!(1, 0, 3, 2));
|
||||
*c = _mm256_permute4x64_epi64(*c, _MM_SHUFFLE!(0, 3, 2, 1));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn undiagonalize(a: &mut __m256i, _b: &mut __m256i, c: &mut __m256i, d: &mut __m256i) {
|
||||
*a = _mm256_permute4x64_epi64(*a, _MM_SHUFFLE!(0, 3, 2, 1));
|
||||
*d = _mm256_permute4x64_epi64(*d, _MM_SHUFFLE!(1, 0, 3, 2));
|
||||
*c = _mm256_permute4x64_epi64(*c, _MM_SHUFFLE!(2, 1, 0, 3));
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn compress_block(
|
||||
block: &[u8; BLOCKBYTES],
|
||||
words: &mut [Word; 8],
|
||||
count: Count,
|
||||
last_block: Word,
|
||||
last_node: Word,
|
||||
) {
|
||||
let (words_low, words_high) = mut_array_refs!(words, DEGREE, DEGREE);
|
||||
let (iv_low, iv_high) = array_refs!(&IV, DEGREE, DEGREE);
|
||||
let mut a = loadu(words_low);
|
||||
let mut b = loadu(words_high);
|
||||
let mut c = loadu(iv_low);
|
||||
let flags = set4(count_low(count), count_high(count), last_block, last_node);
|
||||
let mut d = xor(loadu(iv_high), flags);
|
||||
|
||||
let msg_chunks = array_refs!(block, 16, 16, 16, 16, 16, 16, 16, 16);
|
||||
let m0 = _mm256_broadcastsi128_si256(loadu_128(msg_chunks.0));
|
||||
let m1 = _mm256_broadcastsi128_si256(loadu_128(msg_chunks.1));
|
||||
let m2 = _mm256_broadcastsi128_si256(loadu_128(msg_chunks.2));
|
||||
let m3 = _mm256_broadcastsi128_si256(loadu_128(msg_chunks.3));
|
||||
let m4 = _mm256_broadcastsi128_si256(loadu_128(msg_chunks.4));
|
||||
let m5 = _mm256_broadcastsi128_si256(loadu_128(msg_chunks.5));
|
||||
let m6 = _mm256_broadcastsi128_si256(loadu_128(msg_chunks.6));
|
||||
let m7 = _mm256_broadcastsi128_si256(loadu_128(msg_chunks.7));
|
||||
|
||||
let iv0 = a;
|
||||
let iv1 = b;
|
||||
let mut t0;
|
||||
let mut t1;
|
||||
let mut b0;
|
||||
|
||||
// round 1
|
||||
t0 = _mm256_unpacklo_epi64(m0, m1);
|
||||
t1 = _mm256_unpacklo_epi64(m2, m3);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g1(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
t0 = _mm256_unpackhi_epi64(m0, m1);
|
||||
t1 = _mm256_unpackhi_epi64(m2, m3);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g2(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
diagonalize(&mut a, &mut b, &mut c, &mut d);
|
||||
t0 = _mm256_unpacklo_epi64(m7, m4);
|
||||
t1 = _mm256_unpacklo_epi64(m5, m6);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g1(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
t0 = _mm256_unpackhi_epi64(m7, m4);
|
||||
t1 = _mm256_unpackhi_epi64(m5, m6);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g2(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
undiagonalize(&mut a, &mut b, &mut c, &mut d);
|
||||
|
||||
// round 2
|
||||
t0 = _mm256_unpacklo_epi64(m7, m2);
|
||||
t1 = _mm256_unpackhi_epi64(m4, m6);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g1(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
t0 = _mm256_unpacklo_epi64(m5, m4);
|
||||
t1 = _mm256_alignr_epi8(m3, m7, 8);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g2(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
diagonalize(&mut a, &mut b, &mut c, &mut d);
|
||||
t0 = _mm256_unpackhi_epi64(m2, m0);
|
||||
t1 = _mm256_blend_epi32(m5, m0, 0x33);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g1(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
t0 = _mm256_alignr_epi8(m6, m1, 8);
|
||||
t1 = _mm256_blend_epi32(m3, m1, 0x33);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g2(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
undiagonalize(&mut a, &mut b, &mut c, &mut d);
|
||||
|
||||
// round 3
|
||||
t0 = _mm256_alignr_epi8(m6, m5, 8);
|
||||
t1 = _mm256_unpackhi_epi64(m2, m7);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g1(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
t0 = _mm256_unpacklo_epi64(m4, m0);
|
||||
t1 = _mm256_blend_epi32(m6, m1, 0x33);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g2(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
diagonalize(&mut a, &mut b, &mut c, &mut d);
|
||||
t0 = _mm256_alignr_epi8(m5, m4, 8);
|
||||
t1 = _mm256_unpackhi_epi64(m1, m3);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g1(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
t0 = _mm256_unpacklo_epi64(m2, m7);
|
||||
t1 = _mm256_blend_epi32(m0, m3, 0x33);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g2(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
undiagonalize(&mut a, &mut b, &mut c, &mut d);
|
||||
|
||||
// round 4
|
||||
t0 = _mm256_unpackhi_epi64(m3, m1);
|
||||
t1 = _mm256_unpackhi_epi64(m6, m5);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g1(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
t0 = _mm256_unpackhi_epi64(m4, m0);
|
||||
t1 = _mm256_unpacklo_epi64(m6, m7);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g2(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
diagonalize(&mut a, &mut b, &mut c, &mut d);
|
||||
t0 = _mm256_alignr_epi8(m1, m7, 8);
|
||||
t1 = _mm256_shuffle_epi32(m2, _MM_SHUFFLE!(1, 0, 3, 2));
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g1(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
t0 = _mm256_unpacklo_epi64(m4, m3);
|
||||
t1 = _mm256_unpacklo_epi64(m5, m0);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g2(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
undiagonalize(&mut a, &mut b, &mut c, &mut d);
|
||||
|
||||
// round 5
|
||||
t0 = _mm256_unpackhi_epi64(m4, m2);
|
||||
t1 = _mm256_unpacklo_epi64(m1, m5);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g1(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
t0 = _mm256_blend_epi32(m3, m0, 0x33);
|
||||
t1 = _mm256_blend_epi32(m7, m2, 0x33);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g2(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
diagonalize(&mut a, &mut b, &mut c, &mut d);
|
||||
t0 = _mm256_alignr_epi8(m7, m1, 8);
|
||||
t1 = _mm256_alignr_epi8(m3, m5, 8);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g1(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
t0 = _mm256_unpackhi_epi64(m6, m0);
|
||||
t1 = _mm256_unpacklo_epi64(m6, m4);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g2(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
undiagonalize(&mut a, &mut b, &mut c, &mut d);
|
||||
|
||||
// round 6
|
||||
t0 = _mm256_unpacklo_epi64(m1, m3);
|
||||
t1 = _mm256_unpacklo_epi64(m0, m4);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g1(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
t0 = _mm256_unpacklo_epi64(m6, m5);
|
||||
t1 = _mm256_unpackhi_epi64(m5, m1);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g2(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
diagonalize(&mut a, &mut b, &mut c, &mut d);
|
||||
t0 = _mm256_alignr_epi8(m2, m0, 8);
|
||||
t1 = _mm256_unpackhi_epi64(m3, m7);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g1(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
t0 = _mm256_unpackhi_epi64(m4, m6);
|
||||
t1 = _mm256_alignr_epi8(m7, m2, 8);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g2(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
undiagonalize(&mut a, &mut b, &mut c, &mut d);
|
||||
|
||||
// round 7
|
||||
t0 = _mm256_blend_epi32(m0, m6, 0x33);
|
||||
t1 = _mm256_unpacklo_epi64(m7, m2);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g1(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
t0 = _mm256_unpackhi_epi64(m2, m7);
|
||||
t1 = _mm256_alignr_epi8(m5, m6, 8);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g2(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
diagonalize(&mut a, &mut b, &mut c, &mut d);
|
||||
t0 = _mm256_unpacklo_epi64(m4, m0);
|
||||
t1 = _mm256_blend_epi32(m4, m3, 0x33);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g1(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
t0 = _mm256_unpackhi_epi64(m5, m3);
|
||||
t1 = _mm256_shuffle_epi32(m1, _MM_SHUFFLE!(1, 0, 3, 2));
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g2(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
undiagonalize(&mut a, &mut b, &mut c, &mut d);
|
||||
|
||||
// round 8
|
||||
t0 = _mm256_unpackhi_epi64(m6, m3);
|
||||
t1 = _mm256_blend_epi32(m1, m6, 0x33);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g1(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
t0 = _mm256_alignr_epi8(m7, m5, 8);
|
||||
t1 = _mm256_unpackhi_epi64(m0, m4);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g2(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
diagonalize(&mut a, &mut b, &mut c, &mut d);
|
||||
t0 = _mm256_blend_epi32(m2, m1, 0x33);
|
||||
t1 = _mm256_alignr_epi8(m4, m7, 8);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g1(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
t0 = _mm256_unpacklo_epi64(m5, m0);
|
||||
t1 = _mm256_unpacklo_epi64(m2, m3);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g2(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
undiagonalize(&mut a, &mut b, &mut c, &mut d);
|
||||
|
||||
// round 9
|
||||
t0 = _mm256_unpacklo_epi64(m3, m7);
|
||||
t1 = _mm256_alignr_epi8(m0, m5, 8);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g1(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
t0 = _mm256_unpackhi_epi64(m7, m4);
|
||||
t1 = _mm256_alignr_epi8(m4, m1, 8);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g2(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
diagonalize(&mut a, &mut b, &mut c, &mut d);
|
||||
t0 = _mm256_unpacklo_epi64(m5, m6);
|
||||
t1 = _mm256_unpackhi_epi64(m6, m0);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g1(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
t0 = _mm256_alignr_epi8(m1, m2, 8);
|
||||
t1 = _mm256_alignr_epi8(m2, m3, 8);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g2(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
undiagonalize(&mut a, &mut b, &mut c, &mut d);
|
||||
|
||||
// round 10
|
||||
t0 = _mm256_unpacklo_epi64(m5, m4);
|
||||
t1 = _mm256_unpackhi_epi64(m3, m0);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g1(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
t0 = _mm256_unpacklo_epi64(m1, m2);
|
||||
t1 = _mm256_blend_epi32(m2, m3, 0x33);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g2(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
diagonalize(&mut a, &mut b, &mut c, &mut d);
|
||||
t0 = _mm256_unpackhi_epi64(m6, m7);
|
||||
t1 = _mm256_unpackhi_epi64(m4, m1);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g1(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
t0 = _mm256_blend_epi32(m5, m0, 0x33);
|
||||
t1 = _mm256_unpacklo_epi64(m7, m6);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g2(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
undiagonalize(&mut a, &mut b, &mut c, &mut d);
|
||||
|
||||
// round 11
|
||||
t0 = _mm256_unpacklo_epi64(m0, m1);
|
||||
t1 = _mm256_unpacklo_epi64(m2, m3);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g1(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
t0 = _mm256_unpackhi_epi64(m0, m1);
|
||||
t1 = _mm256_unpackhi_epi64(m2, m3);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g2(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
diagonalize(&mut a, &mut b, &mut c, &mut d);
|
||||
t0 = _mm256_unpacklo_epi64(m7, m4);
|
||||
t1 = _mm256_unpacklo_epi64(m5, m6);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g1(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
t0 = _mm256_unpackhi_epi64(m7, m4);
|
||||
t1 = _mm256_unpackhi_epi64(m5, m6);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g2(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
undiagonalize(&mut a, &mut b, &mut c, &mut d);
|
||||
|
||||
// round 12
|
||||
t0 = _mm256_unpacklo_epi64(m7, m2);
|
||||
t1 = _mm256_unpackhi_epi64(m4, m6);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g1(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
t0 = _mm256_unpacklo_epi64(m5, m4);
|
||||
t1 = _mm256_alignr_epi8(m3, m7, 8);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g2(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
diagonalize(&mut a, &mut b, &mut c, &mut d);
|
||||
t0 = _mm256_unpackhi_epi64(m2, m0);
|
||||
t1 = _mm256_blend_epi32(m5, m0, 0x33);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g1(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
t0 = _mm256_alignr_epi8(m6, m1, 8);
|
||||
t1 = _mm256_blend_epi32(m3, m1, 0x33);
|
||||
b0 = _mm256_blend_epi32(t0, t1, 0xF0);
|
||||
g2(&mut a, &mut b, &mut c, &mut d, &mut b0);
|
||||
undiagonalize(&mut a, &mut b, &mut c, &mut d);
|
||||
|
||||
a = xor(a, c);
|
||||
b = xor(b, d);
|
||||
a = xor(a, iv0);
|
||||
b = xor(b, iv1);
|
||||
|
||||
storeu(a, words_low);
|
||||
storeu(b, words_high);
|
||||
}
|
||||
|
||||
#[target_feature(enable = "avx2")]
|
||||
pub unsafe fn compress1_loop(
|
||||
input: &[u8],
|
||||
words: &mut [Word; 8],
|
||||
mut count: Count,
|
||||
last_node: LastNode,
|
||||
finalize: Finalize,
|
||||
stride: Stride,
|
||||
) {
|
||||
input_debug_asserts(input, finalize);
|
||||
|
||||
let mut local_words = *words;
|
||||
|
||||
let mut fin_offset = input.len().saturating_sub(1);
|
||||
fin_offset -= fin_offset % stride.padded_blockbytes();
|
||||
let mut buf = [0; BLOCKBYTES];
|
||||
let (fin_block, fin_len, _) = final_block(input, fin_offset, &mut buf, stride);
|
||||
let fin_last_block = flag_word(finalize.yes());
|
||||
let fin_last_node = flag_word(finalize.yes() && last_node.yes());
|
||||
|
||||
let mut offset = 0;
|
||||
loop {
|
||||
let block;
|
||||
let count_delta;
|
||||
let last_block;
|
||||
let last_node;
|
||||
if offset == fin_offset {
|
||||
block = fin_block;
|
||||
count_delta = fin_len;
|
||||
last_block = fin_last_block;
|
||||
last_node = fin_last_node;
|
||||
} else {
|
||||
// This unsafe cast avoids bounds checks. There's guaranteed to be
|
||||
// enough input because `offset < fin_offset`.
|
||||
block = &*(input.as_ptr().add(offset) as *const [u8; BLOCKBYTES]);
|
||||
count_delta = BLOCKBYTES;
|
||||
last_block = flag_word(false);
|
||||
last_node = flag_word(false);
|
||||
};
|
||||
|
||||
count = count.wrapping_add(count_delta as Count);
|
||||
compress_block(block, &mut local_words, count, last_block, last_node);
|
||||
|
||||
// Check for termination before bumping the offset, to avoid overflow.
|
||||
if offset == fin_offset {
|
||||
break;
|
||||
}
|
||||
|
||||
offset += stride.padded_blockbytes();
|
||||
}
|
||||
|
||||
*words = local_words;
|
||||
}
|
||||
|
||||
// Performance note: Factoring out a G function here doesn't hurt performance,
|
||||
// unlike in the case of BLAKE2s where it hurts substantially. In fact, on my
|
||||
// machine, it helps a tiny bit. But the difference it tiny, so I'm going to
|
||||
// stick to the approach used by https://github.com/sneves/blake2-avx2
|
||||
// until/unless I can be sure the (tiny) improvement is consistent across
|
||||
// different Intel microarchitectures. Smaller code size is nice, but a
|
||||
// divergence between the BLAKE2b and BLAKE2s implementations is less nice.
|
||||
#[inline(always)]
|
||||
unsafe fn round(v: &mut [__m256i; 16], m: &[__m256i; 16], r: usize) {
|
||||
v[0] = add(v[0], m[SIGMA[r][0] as usize]);
|
||||
v[1] = add(v[1], m[SIGMA[r][2] as usize]);
|
||||
v[2] = add(v[2], m[SIGMA[r][4] as usize]);
|
||||
v[3] = add(v[3], m[SIGMA[r][6] as usize]);
|
||||
v[0] = add(v[0], v[4]);
|
||||
v[1] = add(v[1], v[5]);
|
||||
v[2] = add(v[2], v[6]);
|
||||
v[3] = add(v[3], v[7]);
|
||||
v[12] = xor(v[12], v[0]);
|
||||
v[13] = xor(v[13], v[1]);
|
||||
v[14] = xor(v[14], v[2]);
|
||||
v[15] = xor(v[15], v[3]);
|
||||
v[12] = rot32(v[12]);
|
||||
v[13] = rot32(v[13]);
|
||||
v[14] = rot32(v[14]);
|
||||
v[15] = rot32(v[15]);
|
||||
v[8] = add(v[8], v[12]);
|
||||
v[9] = add(v[9], v[13]);
|
||||
v[10] = add(v[10], v[14]);
|
||||
v[11] = add(v[11], v[15]);
|
||||
v[4] = xor(v[4], v[8]);
|
||||
v[5] = xor(v[5], v[9]);
|
||||
v[6] = xor(v[6], v[10]);
|
||||
v[7] = xor(v[7], v[11]);
|
||||
v[4] = rot24(v[4]);
|
||||
v[5] = rot24(v[5]);
|
||||
v[6] = rot24(v[6]);
|
||||
v[7] = rot24(v[7]);
|
||||
v[0] = add(v[0], m[SIGMA[r][1] as usize]);
|
||||
v[1] = add(v[1], m[SIGMA[r][3] as usize]);
|
||||
v[2] = add(v[2], m[SIGMA[r][5] as usize]);
|
||||
v[3] = add(v[3], m[SIGMA[r][7] as usize]);
|
||||
v[0] = add(v[0], v[4]);
|
||||
v[1] = add(v[1], v[5]);
|
||||
v[2] = add(v[2], v[6]);
|
||||
v[3] = add(v[3], v[7]);
|
||||
v[12] = xor(v[12], v[0]);
|
||||
v[13] = xor(v[13], v[1]);
|
||||
v[14] = xor(v[14], v[2]);
|
||||
v[15] = xor(v[15], v[3]);
|
||||
v[12] = rot16(v[12]);
|
||||
v[13] = rot16(v[13]);
|
||||
v[14] = rot16(v[14]);
|
||||
v[15] = rot16(v[15]);
|
||||
v[8] = add(v[8], v[12]);
|
||||
v[9] = add(v[9], v[13]);
|
||||
v[10] = add(v[10], v[14]);
|
||||
v[11] = add(v[11], v[15]);
|
||||
v[4] = xor(v[4], v[8]);
|
||||
v[5] = xor(v[5], v[9]);
|
||||
v[6] = xor(v[6], v[10]);
|
||||
v[7] = xor(v[7], v[11]);
|
||||
v[4] = rot63(v[4]);
|
||||
v[5] = rot63(v[5]);
|
||||
v[6] = rot63(v[6]);
|
||||
v[7] = rot63(v[7]);
|
||||
|
||||
v[0] = add(v[0], m[SIGMA[r][8] as usize]);
|
||||
v[1] = add(v[1], m[SIGMA[r][10] as usize]);
|
||||
v[2] = add(v[2], m[SIGMA[r][12] as usize]);
|
||||
v[3] = add(v[3], m[SIGMA[r][14] as usize]);
|
||||
v[0] = add(v[0], v[5]);
|
||||
v[1] = add(v[1], v[6]);
|
||||
v[2] = add(v[2], v[7]);
|
||||
v[3] = add(v[3], v[4]);
|
||||
v[15] = xor(v[15], v[0]);
|
||||
v[12] = xor(v[12], v[1]);
|
||||
v[13] = xor(v[13], v[2]);
|
||||
v[14] = xor(v[14], v[3]);
|
||||
v[15] = rot32(v[15]);
|
||||
v[12] = rot32(v[12]);
|
||||
v[13] = rot32(v[13]);
|
||||
v[14] = rot32(v[14]);
|
||||
v[10] = add(v[10], v[15]);
|
||||
v[11] = add(v[11], v[12]);
|
||||
v[8] = add(v[8], v[13]);
|
||||
v[9] = add(v[9], v[14]);
|
||||
v[5] = xor(v[5], v[10]);
|
||||
v[6] = xor(v[6], v[11]);
|
||||
v[7] = xor(v[7], v[8]);
|
||||
v[4] = xor(v[4], v[9]);
|
||||
v[5] = rot24(v[5]);
|
||||
v[6] = rot24(v[6]);
|
||||
v[7] = rot24(v[7]);
|
||||
v[4] = rot24(v[4]);
|
||||
v[0] = add(v[0], m[SIGMA[r][9] as usize]);
|
||||
v[1] = add(v[1], m[SIGMA[r][11] as usize]);
|
||||
v[2] = add(v[2], m[SIGMA[r][13] as usize]);
|
||||
v[3] = add(v[3], m[SIGMA[r][15] as usize]);
|
||||
v[0] = add(v[0], v[5]);
|
||||
v[1] = add(v[1], v[6]);
|
||||
v[2] = add(v[2], v[7]);
|
||||
v[3] = add(v[3], v[4]);
|
||||
v[15] = xor(v[15], v[0]);
|
||||
v[12] = xor(v[12], v[1]);
|
||||
v[13] = xor(v[13], v[2]);
|
||||
v[14] = xor(v[14], v[3]);
|
||||
v[15] = rot16(v[15]);
|
||||
v[12] = rot16(v[12]);
|
||||
v[13] = rot16(v[13]);
|
||||
v[14] = rot16(v[14]);
|
||||
v[10] = add(v[10], v[15]);
|
||||
v[11] = add(v[11], v[12]);
|
||||
v[8] = add(v[8], v[13]);
|
||||
v[9] = add(v[9], v[14]);
|
||||
v[5] = xor(v[5], v[10]);
|
||||
v[6] = xor(v[6], v[11]);
|
||||
v[7] = xor(v[7], v[8]);
|
||||
v[4] = xor(v[4], v[9]);
|
||||
v[5] = rot63(v[5]);
|
||||
v[6] = rot63(v[6]);
|
||||
v[7] = rot63(v[7]);
|
||||
v[4] = rot63(v[4]);
|
||||
}
|
||||
|
||||
// We'd rather make this a regular function with #[inline(always)], but for
|
||||
// some reason that blows up compile times by about 10 seconds, at least in
|
||||
// some cases (BLAKE2b avx2.rs). This macro seems to get the same performance
|
||||
// result, without the compile time issue.
|
||||
macro_rules! compress4_transposed {
|
||||
(
|
||||
$h_vecs:expr,
|
||||
$msg_vecs:expr,
|
||||
$count_low:expr,
|
||||
$count_high:expr,
|
||||
$lastblock:expr,
|
||||
$lastnode:expr,
|
||||
) => {
|
||||
let h_vecs: &mut [__m256i; 8] = $h_vecs;
|
||||
let msg_vecs: &[__m256i; 16] = $msg_vecs;
|
||||
let count_low: __m256i = $count_low;
|
||||
let count_high: __m256i = $count_high;
|
||||
let lastblock: __m256i = $lastblock;
|
||||
let lastnode: __m256i = $lastnode;
|
||||
|
||||
let mut v = [
|
||||
h_vecs[0],
|
||||
h_vecs[1],
|
||||
h_vecs[2],
|
||||
h_vecs[3],
|
||||
h_vecs[4],
|
||||
h_vecs[5],
|
||||
h_vecs[6],
|
||||
h_vecs[7],
|
||||
set1(IV[0]),
|
||||
set1(IV[1]),
|
||||
set1(IV[2]),
|
||||
set1(IV[3]),
|
||||
xor(set1(IV[4]), count_low),
|
||||
xor(set1(IV[5]), count_high),
|
||||
xor(set1(IV[6]), lastblock),
|
||||
xor(set1(IV[7]), lastnode),
|
||||
];
|
||||
|
||||
round(&mut v, &msg_vecs, 0);
|
||||
round(&mut v, &msg_vecs, 1);
|
||||
round(&mut v, &msg_vecs, 2);
|
||||
round(&mut v, &msg_vecs, 3);
|
||||
round(&mut v, &msg_vecs, 4);
|
||||
round(&mut v, &msg_vecs, 5);
|
||||
round(&mut v, &msg_vecs, 6);
|
||||
round(&mut v, &msg_vecs, 7);
|
||||
round(&mut v, &msg_vecs, 8);
|
||||
round(&mut v, &msg_vecs, 9);
|
||||
round(&mut v, &msg_vecs, 10);
|
||||
round(&mut v, &msg_vecs, 11);
|
||||
|
||||
h_vecs[0] = xor(xor(h_vecs[0], v[0]), v[8]);
|
||||
h_vecs[1] = xor(xor(h_vecs[1], v[1]), v[9]);
|
||||
h_vecs[2] = xor(xor(h_vecs[2], v[2]), v[10]);
|
||||
h_vecs[3] = xor(xor(h_vecs[3], v[3]), v[11]);
|
||||
h_vecs[4] = xor(xor(h_vecs[4], v[4]), v[12]);
|
||||
h_vecs[5] = xor(xor(h_vecs[5], v[5]), v[13]);
|
||||
h_vecs[6] = xor(xor(h_vecs[6], v[6]), v[14]);
|
||||
h_vecs[7] = xor(xor(h_vecs[7], v[7]), v[15]);
|
||||
};
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn interleave128(a: __m256i, b: __m256i) -> (__m256i, __m256i) {
|
||||
(
|
||||
_mm256_permute2x128_si256(a, b, 0x20),
|
||||
_mm256_permute2x128_si256(a, b, 0x31),
|
||||
)
|
||||
}
|
||||
|
||||
// There are several ways to do a transposition. We could do it naively, with 8 separate
|
||||
// _mm256_set_epi64x instructions, referencing each of the 64 words explicitly. Or we could copy
|
||||
// the vecs into contiguous storage and then use gather instructions. This third approach is to use
|
||||
// a series of unpack instructions to interleave the vectors. In my benchmarks, interleaving is the
|
||||
// fastest approach. To test this, run `cargo +nightly bench --bench libtest load_4` in the
|
||||
// https://github.com/oconnor663/bao_experiments repo.
|
||||
#[inline(always)]
|
||||
unsafe fn transpose_vecs(
|
||||
vec_a: __m256i,
|
||||
vec_b: __m256i,
|
||||
vec_c: __m256i,
|
||||
vec_d: __m256i,
|
||||
) -> [__m256i; DEGREE] {
|
||||
// Interleave 64-bit lates. The low unpack is lanes 00/22 and the high is 11/33.
|
||||
let ab_02 = _mm256_unpacklo_epi64(vec_a, vec_b);
|
||||
let ab_13 = _mm256_unpackhi_epi64(vec_a, vec_b);
|
||||
let cd_02 = _mm256_unpacklo_epi64(vec_c, vec_d);
|
||||
let cd_13 = _mm256_unpackhi_epi64(vec_c, vec_d);
|
||||
|
||||
// Interleave 128-bit lanes.
|
||||
let (abcd_0, abcd_2) = interleave128(ab_02, cd_02);
|
||||
let (abcd_1, abcd_3) = interleave128(ab_13, cd_13);
|
||||
|
||||
[abcd_0, abcd_1, abcd_2, abcd_3]
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn transpose_state_vecs(jobs: &[Job; DEGREE]) -> [__m256i; 8] {
|
||||
// Load all the state words into transposed vectors, where the first vector
|
||||
// has the first word of each state, etc. Transposing once at the beginning
|
||||
// and once at the end is more efficient that repeating it for each block.
|
||||
let words0 = array_refs!(&jobs[0].words, DEGREE, DEGREE);
|
||||
let words1 = array_refs!(&jobs[1].words, DEGREE, DEGREE);
|
||||
let words2 = array_refs!(&jobs[2].words, DEGREE, DEGREE);
|
||||
let words3 = array_refs!(&jobs[3].words, DEGREE, DEGREE);
|
||||
let [h0, h1, h2, h3] = transpose_vecs(
|
||||
loadu(words0.0),
|
||||
loadu(words1.0),
|
||||
loadu(words2.0),
|
||||
loadu(words3.0),
|
||||
);
|
||||
let [h4, h5, h6, h7] = transpose_vecs(
|
||||
loadu(words0.1),
|
||||
loadu(words1.1),
|
||||
loadu(words2.1),
|
||||
loadu(words3.1),
|
||||
);
|
||||
[h0, h1, h2, h3, h4, h5, h6, h7]
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn untranspose_state_vecs(h_vecs: &[__m256i; 8], jobs: &mut [Job; DEGREE]) {
|
||||
// Un-transpose the updated state vectors back into the caller's arrays.
|
||||
let [job0, job1, job2, job3] = jobs;
|
||||
let words0 = mut_array_refs!(&mut job0.words, DEGREE, DEGREE);
|
||||
let words1 = mut_array_refs!(&mut job1.words, DEGREE, DEGREE);
|
||||
let words2 = mut_array_refs!(&mut job2.words, DEGREE, DEGREE);
|
||||
let words3 = mut_array_refs!(&mut job3.words, DEGREE, DEGREE);
|
||||
let out = transpose_vecs(h_vecs[0], h_vecs[1], h_vecs[2], h_vecs[3]);
|
||||
storeu(out[0], words0.0);
|
||||
storeu(out[1], words1.0);
|
||||
storeu(out[2], words2.0);
|
||||
storeu(out[3], words3.0);
|
||||
let out = transpose_vecs(h_vecs[4], h_vecs[5], h_vecs[6], h_vecs[7]);
|
||||
storeu(out[0], words0.1);
|
||||
storeu(out[1], words1.1);
|
||||
storeu(out[2], words2.1);
|
||||
storeu(out[3], words3.1);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn transpose_msg_vecs(blocks: [*const [u8; BLOCKBYTES]; DEGREE]) -> [__m256i; 16] {
|
||||
// These input arrays have no particular alignment, so we use unaligned
|
||||
// loads to read from them.
|
||||
let block0 = blocks[0] as *const [Word; DEGREE];
|
||||
let block1 = blocks[1] as *const [Word; DEGREE];
|
||||
let block2 = blocks[2] as *const [Word; DEGREE];
|
||||
let block3 = blocks[3] as *const [Word; DEGREE];
|
||||
let [m0, m1, m2, m3] = transpose_vecs(
|
||||
loadu(block0.add(0)),
|
||||
loadu(block1.add(0)),
|
||||
loadu(block2.add(0)),
|
||||
loadu(block3.add(0)),
|
||||
);
|
||||
let [m4, m5, m6, m7] = transpose_vecs(
|
||||
loadu(block0.add(1)),
|
||||
loadu(block1.add(1)),
|
||||
loadu(block2.add(1)),
|
||||
loadu(block3.add(1)),
|
||||
);
|
||||
let [m8, m9, m10, m11] = transpose_vecs(
|
||||
loadu(block0.add(2)),
|
||||
loadu(block1.add(2)),
|
||||
loadu(block2.add(2)),
|
||||
loadu(block3.add(2)),
|
||||
);
|
||||
let [m12, m13, m14, m15] = transpose_vecs(
|
||||
loadu(block0.add(3)),
|
||||
loadu(block1.add(3)),
|
||||
loadu(block2.add(3)),
|
||||
loadu(block3.add(3)),
|
||||
);
|
||||
[
|
||||
m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15,
|
||||
]
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn load_counts(jobs: &[Job; DEGREE]) -> (__m256i, __m256i) {
|
||||
(
|
||||
set4(
|
||||
count_low(jobs[0].count),
|
||||
count_low(jobs[1].count),
|
||||
count_low(jobs[2].count),
|
||||
count_low(jobs[3].count),
|
||||
),
|
||||
set4(
|
||||
count_high(jobs[0].count),
|
||||
count_high(jobs[1].count),
|
||||
count_high(jobs[2].count),
|
||||
count_high(jobs[3].count),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn store_counts(jobs: &mut [Job; DEGREE], low: __m256i, high: __m256i) {
|
||||
let low_ints: [Word; DEGREE] = mem::transmute(low);
|
||||
let high_ints: [Word; DEGREE] = mem::transmute(high);
|
||||
for i in 0..DEGREE {
|
||||
jobs[i].count = assemble_count(low_ints[i], high_ints[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn add_to_counts(lo: &mut __m256i, hi: &mut __m256i, delta: __m256i) {
|
||||
// If the low counts reach zero, that means they wrapped, unless the delta
|
||||
// was also zero.
|
||||
*lo = add(*lo, delta);
|
||||
let lo_reached_zero = eq(*lo, set1(0));
|
||||
let delta_was_zero = eq(delta, set1(0));
|
||||
let hi_inc = and(set1(1), negate_and(delta_was_zero, lo_reached_zero));
|
||||
*hi = add(*hi, hi_inc);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn flags_vec(flags: [bool; DEGREE]) -> __m256i {
|
||||
set4(
|
||||
flag_word(flags[0]),
|
||||
flag_word(flags[1]),
|
||||
flag_word(flags[2]),
|
||||
flag_word(flags[3]),
|
||||
)
|
||||
}
|
||||
|
||||
#[target_feature(enable = "avx2")]
|
||||
pub unsafe fn compress4_loop(jobs: &mut [Job; DEGREE], finalize: Finalize, stride: Stride) {
|
||||
// If we're not finalizing, there can't be a partial block at the end.
|
||||
for job in jobs.iter() {
|
||||
input_debug_asserts(job.input, finalize);
|
||||
}
|
||||
|
||||
let msg_ptrs = [
|
||||
jobs[0].input.as_ptr(),
|
||||
jobs[1].input.as_ptr(),
|
||||
jobs[2].input.as_ptr(),
|
||||
jobs[3].input.as_ptr(),
|
||||
];
|
||||
let mut h_vecs = transpose_state_vecs(&jobs);
|
||||
let (mut counts_lo, mut counts_hi) = load_counts(&jobs);
|
||||
|
||||
// Prepare the final blocks (note, which could be empty if the input is
|
||||
// empty). Do all this before entering the main loop.
|
||||
let min_len = jobs.iter().map(|job| job.input.len()).min().unwrap();
|
||||
let mut fin_offset = min_len.saturating_sub(1);
|
||||
fin_offset -= fin_offset % stride.padded_blockbytes();
|
||||
// Performance note, making these buffers mem::uninitialized() seems to
|
||||
// cause problems in the optimizer.
|
||||
let mut buf0: [u8; BLOCKBYTES] = [0; BLOCKBYTES];
|
||||
let mut buf1: [u8; BLOCKBYTES] = [0; BLOCKBYTES];
|
||||
let mut buf2: [u8; BLOCKBYTES] = [0; BLOCKBYTES];
|
||||
let mut buf3: [u8; BLOCKBYTES] = [0; BLOCKBYTES];
|
||||
let (block0, len0, finalize0) = final_block(jobs[0].input, fin_offset, &mut buf0, stride);
|
||||
let (block1, len1, finalize1) = final_block(jobs[1].input, fin_offset, &mut buf1, stride);
|
||||
let (block2, len2, finalize2) = final_block(jobs[2].input, fin_offset, &mut buf2, stride);
|
||||
let (block3, len3, finalize3) = final_block(jobs[3].input, fin_offset, &mut buf3, stride);
|
||||
let fin_blocks: [*const [u8; BLOCKBYTES]; DEGREE] = [block0, block1, block2, block3];
|
||||
let fin_counts_delta = set4(len0 as Word, len1 as Word, len2 as Word, len3 as Word);
|
||||
let fin_last_block;
|
||||
let fin_last_node;
|
||||
if finalize.yes() {
|
||||
fin_last_block = flags_vec([finalize0, finalize1, finalize2, finalize3]);
|
||||
fin_last_node = flags_vec([
|
||||
finalize0 && jobs[0].last_node.yes(),
|
||||
finalize1 && jobs[1].last_node.yes(),
|
||||
finalize2 && jobs[2].last_node.yes(),
|
||||
finalize3 && jobs[3].last_node.yes(),
|
||||
]);
|
||||
} else {
|
||||
fin_last_block = set1(0);
|
||||
fin_last_node = set1(0);
|
||||
}
|
||||
|
||||
// The main loop.
|
||||
let mut offset = 0;
|
||||
loop {
|
||||
let blocks;
|
||||
let counts_delta;
|
||||
let last_block;
|
||||
let last_node;
|
||||
if offset == fin_offset {
|
||||
blocks = fin_blocks;
|
||||
counts_delta = fin_counts_delta;
|
||||
last_block = fin_last_block;
|
||||
last_node = fin_last_node;
|
||||
} else {
|
||||
blocks = [
|
||||
msg_ptrs[0].add(offset) as *const [u8; BLOCKBYTES],
|
||||
msg_ptrs[1].add(offset) as *const [u8; BLOCKBYTES],
|
||||
msg_ptrs[2].add(offset) as *const [u8; BLOCKBYTES],
|
||||
msg_ptrs[3].add(offset) as *const [u8; BLOCKBYTES],
|
||||
];
|
||||
counts_delta = set1(BLOCKBYTES as Word);
|
||||
last_block = set1(0);
|
||||
last_node = set1(0);
|
||||
};
|
||||
|
||||
let m_vecs = transpose_msg_vecs(blocks);
|
||||
add_to_counts(&mut counts_lo, &mut counts_hi, counts_delta);
|
||||
compress4_transposed!(
|
||||
&mut h_vecs,
|
||||
&m_vecs,
|
||||
counts_lo,
|
||||
counts_hi,
|
||||
last_block,
|
||||
last_node,
|
||||
);
|
||||
|
||||
// Check for termination before bumping the offset, to avoid overflow.
|
||||
if offset == fin_offset {
|
||||
break;
|
||||
}
|
||||
|
||||
offset += stride.padded_blockbytes();
|
||||
}
|
||||
|
||||
// Write out the results.
|
||||
untranspose_state_vecs(&h_vecs, &mut *jobs);
|
||||
store_counts(&mut *jobs, counts_lo, counts_hi);
|
||||
let max_consumed = offset.saturating_add(stride.padded_blockbytes());
|
||||
for job in jobs.iter_mut() {
|
||||
let consumed = cmp::min(max_consumed, job.input.len());
|
||||
job.input = &job.input[consumed..];
|
||||
}
|
||||
}
|
570
third_party/rust/blake2b_simd/src/blake2bp.rs
vendored
570
third_party/rust/blake2b_simd/src/blake2bp.rs
vendored
@ -1,570 +0,0 @@
|
||||
//! BLAKE2bp, a variant of BLAKE2b that uses SIMD more efficiently.
|
||||
//!
|
||||
//! The AVX2 implementation of BLAKE2bp is about twice as fast that of BLAKE2b.
|
||||
//! However, note that it's a different hash function, and it gives a different
|
||||
//! hash from BLAKE2b for the same input.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```
|
||||
//! use blake2b_simd::blake2bp;
|
||||
//!
|
||||
//! let hash = blake2bp::Params::new()
|
||||
//! .hash_length(16)
|
||||
//! .key(b"The Magic Words are Squeamish Ossifrage")
|
||||
//! .to_state()
|
||||
//! .update(b"foo")
|
||||
//! .update(b"bar")
|
||||
//! .update(b"baz")
|
||||
//! .finalize();
|
||||
//! assert_eq!("e69c7d2c42a5ac14948772231c68c552", &hash.to_hex());
|
||||
//! ```
|
||||
|
||||
use crate::guts::{Finalize, Implementation, Job, LastNode, Stride};
|
||||
use crate::many;
|
||||
use crate::Count;
|
||||
use crate::Hash;
|
||||
use crate::Word;
|
||||
use crate::BLOCKBYTES;
|
||||
use crate::KEYBYTES;
|
||||
use crate::OUTBYTES;
|
||||
use core::cmp;
|
||||
use core::fmt;
|
||||
use core::mem::size_of;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use std;
|
||||
|
||||
pub(crate) const DEGREE: usize = 4;
|
||||
|
||||
/// Compute the BLAKE2bp hash of a slice of bytes all at once, using default
|
||||
/// parameters.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use blake2b_simd::blake2bp::blake2bp;
|
||||
/// let expected = "8ca9ccee7946afcb686fe7556628b5ba1bf9a691da37ca58cd049354d99f3704\
|
||||
/// 2c007427e5f219b9ab5063707ec6823872dee413ee014b4d02f2ebb6abb5f643";
|
||||
/// let hash = blake2bp(b"foo");
|
||||
/// assert_eq!(expected, &hash.to_hex());
|
||||
/// ```
|
||||
pub fn blake2bp(input: &[u8]) -> Hash {
|
||||
Params::new().hash(input)
|
||||
}
|
||||
|
||||
/// A parameter builder for BLAKE2bp, just like the [`Params`](../struct.Params.html) type for
|
||||
/// BLAKE2b.
|
||||
///
|
||||
/// This builder only supports configuring the hash length and a secret key. This matches the
|
||||
/// options provided by the [reference
|
||||
/// implementation](https://github.com/BLAKE2/BLAKE2/blob/320c325437539ae91091ce62efec1913cd8093c2/ref/blake2.h#L162-L165).
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use blake2b_simd::blake2bp;
|
||||
/// let mut state = blake2bp::Params::new().hash_length(32).to_state();
|
||||
/// ```
|
||||
#[derive(Clone)]
|
||||
pub struct Params {
|
||||
hash_length: u8,
|
||||
key_length: u8,
|
||||
key: [u8; KEYBYTES],
|
||||
implementation: Implementation,
|
||||
}
|
||||
|
||||
impl Params {
|
||||
/// Equivalent to `Params::default()`.
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
hash_length: OUTBYTES as u8,
|
||||
key_length: 0,
|
||||
key: [0; KEYBYTES],
|
||||
implementation: Implementation::detect(),
|
||||
}
|
||||
}
|
||||
|
||||
fn to_words(&self) -> ([[Word; 8]; DEGREE], [Word; 8]) {
|
||||
let mut base_params = crate::Params::new();
|
||||
base_params
|
||||
.hash_length(self.hash_length as usize)
|
||||
.key(&self.key[..self.key_length as usize])
|
||||
.fanout(DEGREE as u8)
|
||||
.max_depth(2)
|
||||
.max_leaf_length(0)
|
||||
// Note that inner_hash_length is always OUTBYTES, regardless of the hash_length
|
||||
// parameter. This isn't documented in the spec, but it matches the behavior of the
|
||||
// reference implementation: https://github.com/BLAKE2/BLAKE2/blob/320c325437539ae91091ce62efec1913cd8093c2/ref/blake2bp-ref.c#L55
|
||||
.inner_hash_length(OUTBYTES);
|
||||
let leaf_words = |worker_index| {
|
||||
base_params
|
||||
.clone()
|
||||
.node_offset(worker_index)
|
||||
.node_depth(0)
|
||||
// Note that setting the last_node flag here has no effect,
|
||||
// because it isn't included in the state words.
|
||||
.to_words()
|
||||
};
|
||||
let leaf_words = [leaf_words(0), leaf_words(1), leaf_words(2), leaf_words(3)];
|
||||
let root_words = base_params
|
||||
.clone()
|
||||
.node_offset(0)
|
||||
.node_depth(1)
|
||||
// Note that setting the last_node flag here has no effect, because
|
||||
// it isn't included in the state words. Also note that because
|
||||
// we're only preserving its state words, the root node won't hash
|
||||
// any key bytes.
|
||||
.to_words();
|
||||
(leaf_words, root_words)
|
||||
}
|
||||
|
||||
/// Hash an input all at once with these parameters.
|
||||
pub fn hash(&self, input: &[u8]) -> Hash {
|
||||
// If there's a key, just fall back to using the State.
|
||||
if self.key_length > 0 {
|
||||
return self.to_state().update(input).finalize();
|
||||
}
|
||||
let (mut leaf_words, mut root_words) = self.to_words();
|
||||
// Hash each leaf in parallel.
|
||||
let jobs = leaf_words.iter_mut().enumerate().map(|(i, words)| {
|
||||
let input_start = cmp::min(input.len(), i * BLOCKBYTES);
|
||||
Job {
|
||||
input: &input[input_start..],
|
||||
words,
|
||||
count: 0,
|
||||
last_node: if i == DEGREE - 1 {
|
||||
LastNode::Yes
|
||||
} else {
|
||||
LastNode::No
|
||||
},
|
||||
}
|
||||
});
|
||||
many::compress_many(jobs, self.implementation, Finalize::Yes, Stride::Parallel);
|
||||
// Hash each leaf into the root.
|
||||
finalize_root_words(
|
||||
&leaf_words,
|
||||
&mut root_words,
|
||||
self.hash_length,
|
||||
self.implementation,
|
||||
)
|
||||
}
|
||||
|
||||
/// Construct a BLAKE2bp `State` object based on these parameters.
|
||||
pub fn to_state(&self) -> State {
|
||||
State::with_params(self)
|
||||
}
|
||||
|
||||
/// Set the length of the final hash, from 1 to `OUTBYTES` (64). Apart from controlling the
|
||||
/// length of the final `Hash`, this is also associated data, and changing it will result in a
|
||||
/// totally different hash.
|
||||
pub fn hash_length(&mut self, length: usize) -> &mut Self {
|
||||
assert!(
|
||||
1 <= length && length <= OUTBYTES,
|
||||
"Bad hash length: {}",
|
||||
length
|
||||
);
|
||||
self.hash_length = length as u8;
|
||||
self
|
||||
}
|
||||
|
||||
/// Use a secret key, so that BLAKE2bp acts as a MAC. The maximum key length is `KEYBYTES`
|
||||
/// (64). An empty key is equivalent to having no key at all.
|
||||
pub fn key(&mut self, key: &[u8]) -> &mut Self {
|
||||
assert!(key.len() <= KEYBYTES, "Bad key length: {}", key.len());
|
||||
self.key_length = key.len() as u8;
|
||||
self.key = [0; KEYBYTES];
|
||||
self.key[..key.len()].copy_from_slice(key);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Params {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Params {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Params {{ hash_length: {}, key_length: {} }}",
|
||||
self.hash_length,
|
||||
// NB: Don't print the key itself. Debug shouldn't leak secrets.
|
||||
self.key_length,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// An incremental hasher for BLAKE2bp, just like the [`State`](../struct.State.html) type for
|
||||
/// BLAKE2b.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use blake2b_simd::blake2bp;
|
||||
///
|
||||
/// let mut state = blake2bp::State::new();
|
||||
/// state.update(b"foo");
|
||||
/// state.update(b"bar");
|
||||
/// let hash = state.finalize();
|
||||
///
|
||||
/// let expected = "e654427b6ef02949471712263e59071abbb6aa94855674c1daeed6cfaf127c33\
|
||||
/// dfa3205f7f7f71e4f0673d25fa82a368488911f446bccd323af3ab03f53e56e5";
|
||||
/// assert_eq!(expected, &hash.to_hex());
|
||||
/// ```
|
||||
#[derive(Clone)]
|
||||
pub struct State {
|
||||
leaf_words: [[Word; 8]; DEGREE],
|
||||
root_words: [Word; 8],
|
||||
// Note that this buffer is twice as large as what compress4 needs. That guarantees that we
|
||||
// have enough input when we compress to know we don't need to finalize any of the leaves.
|
||||
buf: [u8; 2 * DEGREE * BLOCKBYTES],
|
||||
buf_len: u16,
|
||||
// Note that this is the *per-leaf* count.
|
||||
count: Count,
|
||||
hash_length: u8,
|
||||
implementation: Implementation,
|
||||
is_keyed: bool,
|
||||
}
|
||||
|
||||
impl State {
|
||||
/// Equivalent to `State::default()` or `Params::default().to_state()`.
|
||||
pub fn new() -> Self {
|
||||
Self::with_params(&Params::default())
|
||||
}
|
||||
|
||||
fn with_params(params: &Params) -> Self {
|
||||
let (leaf_words, root_words) = params.to_words();
|
||||
|
||||
// If a key is set, initalize the buffer to contain the key bytes. Note
|
||||
// that only the leaves hash key bytes. The root doesn't, even though
|
||||
// the key length it still set in its parameters. Again this isn't
|
||||
// documented in the spec, but it matches the behavior of the reference
|
||||
// implementation:
|
||||
// https://github.com/BLAKE2/BLAKE2/blob/320c325437539ae91091ce62efec1913cd8093c2/ref/blake2bp-ref.c#L128
|
||||
// This particular behavior (though not the inner hash length behavior
|
||||
// above) is also corroborated by the official test vectors; see
|
||||
// tests/vector_tests.rs.
|
||||
let mut buf = [0; 2 * DEGREE * BLOCKBYTES];
|
||||
let mut buf_len = 0;
|
||||
if params.key_length > 0 {
|
||||
for i in 0..DEGREE {
|
||||
let keybytes = ¶ms.key[..params.key_length as usize];
|
||||
buf[i * BLOCKBYTES..][..keybytes.len()].copy_from_slice(keybytes);
|
||||
buf_len = BLOCKBYTES * DEGREE;
|
||||
}
|
||||
}
|
||||
|
||||
Self {
|
||||
leaf_words,
|
||||
root_words,
|
||||
buf,
|
||||
buf_len: buf_len as u16,
|
||||
count: 0, // count gets updated in self.compress()
|
||||
hash_length: params.hash_length,
|
||||
implementation: params.implementation,
|
||||
is_keyed: params.key_length > 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_buf(&mut self, input: &mut &[u8]) {
|
||||
let take = cmp::min(self.buf.len() - self.buf_len as usize, input.len());
|
||||
self.buf[self.buf_len as usize..][..take].copy_from_slice(&input[..take]);
|
||||
self.buf_len += take as u16;
|
||||
*input = &input[take..];
|
||||
}
|
||||
|
||||
fn compress_to_leaves(
|
||||
leaves: &mut [[Word; 8]; DEGREE],
|
||||
input: &[u8],
|
||||
count: &mut Count,
|
||||
implementation: Implementation,
|
||||
) {
|
||||
// Input is assumed to be an even number of blocks for each leaf. Since
|
||||
// we're not finilizing, debug asserts will fire otherwise.
|
||||
let jobs = leaves.iter_mut().enumerate().map(|(i, words)| {
|
||||
Job {
|
||||
input: &input[i * BLOCKBYTES..],
|
||||
words,
|
||||
count: *count,
|
||||
last_node: LastNode::No, // irrelevant when not finalizing
|
||||
}
|
||||
});
|
||||
many::compress_many(jobs, implementation, Finalize::No, Stride::Parallel);
|
||||
// Note that count is the bytes input *per-leaf*.
|
||||
*count = count.wrapping_add((input.len() / DEGREE) as Count);
|
||||
}
|
||||
|
||||
/// Add input to the hash. You can call `update` any number of times.
|
||||
pub fn update(&mut self, mut input: &[u8]) -> &mut Self {
|
||||
// If we have a partial buffer, try to complete it. If we complete it and there's more
|
||||
// input waiting, we need to compress to make more room. However, because we need to be
|
||||
// sure that *none* of the leaves would need to be finalized as part of this round of
|
||||
// compression, we need to buffer more than we would for BLAKE2b.
|
||||
if self.buf_len > 0 {
|
||||
self.fill_buf(&mut input);
|
||||
// The buffer is large enough for two compressions. If we've filled
|
||||
// the buffer and there's still more input coming, then we have to
|
||||
// do at least one compression. If there's enough input still
|
||||
// coming that all the leaves are guaranteed to get more, do both
|
||||
// compressions in the buffer. Otherwise, do just one and shift the
|
||||
// back half of the buffer to the front.
|
||||
if !input.is_empty() {
|
||||
if input.len() > (DEGREE - 1) * BLOCKBYTES {
|
||||
// Enough input coming to do both compressions.
|
||||
Self::compress_to_leaves(
|
||||
&mut self.leaf_words,
|
||||
&self.buf,
|
||||
&mut self.count,
|
||||
self.implementation,
|
||||
);
|
||||
self.buf_len = 0;
|
||||
} else {
|
||||
// Only enough input coming for one compression.
|
||||
Self::compress_to_leaves(
|
||||
&mut self.leaf_words,
|
||||
&self.buf[..DEGREE * BLOCKBYTES],
|
||||
&mut self.count,
|
||||
self.implementation,
|
||||
);
|
||||
self.buf_len = (DEGREE * BLOCKBYTES) as u16;
|
||||
let (buf_front, buf_back) = self.buf.split_at_mut(DEGREE * BLOCKBYTES);
|
||||
buf_front.copy_from_slice(buf_back);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Now we directly compress as much input as possible, without copying
|
||||
// it into the buffer. We need to make sure we buffer at least one byte
|
||||
// for each of the leaves, so that we know we don't need to finalize
|
||||
// them.
|
||||
let needed_tail = (DEGREE - 1) * BLOCKBYTES + 1;
|
||||
let mut bulk_bytes = input.len().saturating_sub(needed_tail);
|
||||
bulk_bytes -= bulk_bytes % (DEGREE * BLOCKBYTES);
|
||||
if bulk_bytes > 0 {
|
||||
Self::compress_to_leaves(
|
||||
&mut self.leaf_words,
|
||||
&input[..bulk_bytes],
|
||||
&mut self.count,
|
||||
self.implementation,
|
||||
);
|
||||
input = &input[bulk_bytes..];
|
||||
}
|
||||
|
||||
// Buffer any remaining input, to be either compressed or finalized in
|
||||
// a subsequent call.
|
||||
self.fill_buf(&mut input);
|
||||
debug_assert_eq!(0, input.len());
|
||||
self
|
||||
}
|
||||
|
||||
/// Finalize the state and return a `Hash`. This method is idempotent, and calling it multiple
|
||||
/// times will give the same result. It's also possible to `update` with more input in between.
|
||||
pub fn finalize(&self) -> Hash {
|
||||
// Hash whatever's remaining in the buffer and finalize the leaves.
|
||||
let buf_len = self.buf_len as usize;
|
||||
let mut leaves_copy = self.leaf_words;
|
||||
let jobs = leaves_copy
|
||||
.iter_mut()
|
||||
.enumerate()
|
||||
.map(|(leaf_index, leaf_words)| {
|
||||
let input = &self.buf[cmp::min(leaf_index * BLOCKBYTES, buf_len)..buf_len];
|
||||
Job {
|
||||
input,
|
||||
words: leaf_words,
|
||||
count: self.count,
|
||||
last_node: if leaf_index == DEGREE - 1 {
|
||||
LastNode::Yes
|
||||
} else {
|
||||
LastNode::No
|
||||
},
|
||||
}
|
||||
});
|
||||
many::compress_many(jobs, self.implementation, Finalize::Yes, Stride::Parallel);
|
||||
|
||||
// Concatenate each leaf into the root and hash that.
|
||||
let mut root_words_copy = self.root_words;
|
||||
finalize_root_words(
|
||||
&leaves_copy,
|
||||
&mut root_words_copy,
|
||||
self.hash_length,
|
||||
self.implementation,
|
||||
)
|
||||
}
|
||||
|
||||
/// Return the total number of bytes input so far.
|
||||
///
|
||||
/// Note that `count` doesn't include the bytes of the key block, if any.
|
||||
/// It's exactly the total number of input bytes fed to `update`.
|
||||
pub fn count(&self) -> Count {
|
||||
// Remember that self.count is *per-leaf*.
|
||||
let mut ret = self
|
||||
.count
|
||||
.wrapping_mul(DEGREE as Count)
|
||||
.wrapping_add(self.buf_len as Count);
|
||||
if self.is_keyed {
|
||||
ret -= (DEGREE * BLOCKBYTES) as Count;
|
||||
}
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::io::Write for State {
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
self.update(buf);
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for State {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"State {{ count: {}, hash_length: {} }}",
|
||||
self.count(),
|
||||
self.hash_length,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for State {
|
||||
fn default() -> Self {
|
||||
Self::with_params(&Params::default())
|
||||
}
|
||||
}
|
||||
|
||||
// Compress each of the four finalized hashes into the root words as input,
|
||||
// using two compressions. Note that even if a future version of this
|
||||
// implementation supports the hash_length parameter and sets it as associated
|
||||
// data for all nodes, this step must still use the untruncated output of each
|
||||
// leaf. Note also that, as mentioned above, the root node doesn't hash any key
|
||||
// bytes.
|
||||
fn finalize_root_words(
|
||||
leaf_words: &[[Word; 8]; DEGREE],
|
||||
root_words: &mut [Word; 8],
|
||||
hash_length: u8,
|
||||
imp: Implementation,
|
||||
) -> Hash {
|
||||
debug_assert_eq!(OUTBYTES, 8 * size_of::<Word>());
|
||||
let mut block = [0; DEGREE * OUTBYTES];
|
||||
for (word, chunk) in leaf_words
|
||||
.iter()
|
||||
.flat_map(|words| words.iter())
|
||||
.zip(block.chunks_exact_mut(size_of::<Word>()))
|
||||
{
|
||||
chunk.copy_from_slice(&word.to_le_bytes());
|
||||
}
|
||||
imp.compress1_loop(
|
||||
&block,
|
||||
root_words,
|
||||
0,
|
||||
LastNode::Yes,
|
||||
Finalize::Yes,
|
||||
Stride::Serial,
|
||||
);
|
||||
Hash {
|
||||
bytes: crate::state_words_to_bytes(&root_words),
|
||||
len: hash_length,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn force_portable(params: &mut Params) {
|
||||
params.implementation = Implementation::portable();
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub(crate) mod test {
|
||||
use super::*;
|
||||
use crate::paint_test_input;
|
||||
|
||||
// This is a simple reference implementation without the complicated buffering or parameter
|
||||
// support of the real implementation. We need this because the official test vectors don't
|
||||
// include any inputs large enough to exercise all the branches in the buffering logic.
|
||||
fn blake2bp_reference(input: &[u8]) -> Hash {
|
||||
let mut leaves = arrayvec::ArrayVec::<[_; DEGREE]>::new();
|
||||
for leaf_index in 0..DEGREE {
|
||||
leaves.push(
|
||||
crate::Params::new()
|
||||
.fanout(DEGREE as u8)
|
||||
.max_depth(2)
|
||||
.node_offset(leaf_index as u64)
|
||||
.inner_hash_length(OUTBYTES)
|
||||
.to_state(),
|
||||
);
|
||||
}
|
||||
leaves[DEGREE - 1].set_last_node(true);
|
||||
for (i, chunk) in input.chunks(BLOCKBYTES).enumerate() {
|
||||
leaves[i % DEGREE].update(chunk);
|
||||
}
|
||||
let mut root = crate::Params::new()
|
||||
.fanout(DEGREE as u8)
|
||||
.max_depth(2)
|
||||
.node_depth(1)
|
||||
.inner_hash_length(OUTBYTES)
|
||||
.last_node(true)
|
||||
.to_state();
|
||||
for leaf in &mut leaves {
|
||||
root.update(leaf.finalize().as_bytes());
|
||||
}
|
||||
root.finalize()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_against_reference() {
|
||||
let mut buf = [0; 21 * BLOCKBYTES];
|
||||
paint_test_input(&mut buf);
|
||||
// - 8 blocks is just enought to fill the double buffer.
|
||||
// - 9 blocks triggers the "perform one compression on the double buffer" case.
|
||||
// - 11 blocks is the largest input where only one compression may be performed, on the
|
||||
// first half of the buffer, because there's not enough input to avoid needing to
|
||||
// finalize the second half.
|
||||
// - 12 blocks triggers the "perform both compressions in the double buffer" case.
|
||||
// - 15 blocks is the largest input where, after compressing 8 blocks from the buffer,
|
||||
// there's not enough input to hash directly from memory.
|
||||
// - 16 blocks triggers "after emptying the buffer, hash directly from memory".
|
||||
for num_blocks in 0..=20 {
|
||||
for &extra in &[0, 1, BLOCKBYTES - 1] {
|
||||
for &portable in &[false, true] {
|
||||
// eprintln!("\ncase -----");
|
||||
// dbg!(num_blocks);
|
||||
// dbg!(extra);
|
||||
// dbg!(portable);
|
||||
|
||||
// First hash the input all at once, as a sanity check.
|
||||
let mut params = Params::new();
|
||||
if portable {
|
||||
force_portable(&mut params);
|
||||
}
|
||||
let input = &buf[..num_blocks * BLOCKBYTES + extra];
|
||||
let expected = blake2bp_reference(&input);
|
||||
let mut state = params.to_state();
|
||||
let found = state.update(input).finalize();
|
||||
assert_eq!(expected, found);
|
||||
|
||||
// Then, do it again, but buffer 1 byte of input first. That causes the buffering
|
||||
// branch to trigger.
|
||||
let mut state = params.to_state();
|
||||
let maybe_one = cmp::min(1, input.len());
|
||||
state.update(&input[..maybe_one]);
|
||||
assert_eq!(maybe_one as Count, state.count());
|
||||
// Do a throwaway finalize here to check for idempotency.
|
||||
state.finalize();
|
||||
state.update(&input[maybe_one..]);
|
||||
assert_eq!(input.len() as Count, state.count());
|
||||
let found = state.finalize();
|
||||
assert_eq!(expected, found);
|
||||
|
||||
// Finally, do it again with the all-at-once interface.
|
||||
assert_eq!(expected, blake2bp(input));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
565
third_party/rust/blake2b_simd/src/guts.rs
vendored
565
third_party/rust/blake2b_simd/src/guts.rs
vendored
@ -1,565 +0,0 @@
|
||||
use crate::*;
|
||||
use arrayref::array_ref;
|
||||
use core::cmp;
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
pub const MAX_DEGREE: usize = 4;
|
||||
|
||||
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
pub const MAX_DEGREE: usize = 1;
|
||||
|
||||
// Variants other than Portable are unreachable in no_std, unless CPU features
|
||||
// are explicitly enabled for the build with e.g. RUSTFLAGS="-C target-feature=avx2".
|
||||
// This might change in the future if is_x86_feature_detected moves into libcore.
|
||||
#[allow(dead_code)]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
enum Platform {
|
||||
Portable,
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
SSE41,
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
AVX2,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct Implementation(Platform);
|
||||
|
||||
impl Implementation {
|
||||
pub fn detect() -> Self {
|
||||
// Try the different implementations in order of how fast/modern they
|
||||
// are. Currently on non-x86, everything just uses portable.
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
{
|
||||
if let Some(avx2_impl) = Self::avx2_if_supported() {
|
||||
return avx2_impl;
|
||||
}
|
||||
}
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
{
|
||||
if let Some(sse41_impl) = Self::sse41_if_supported() {
|
||||
return sse41_impl;
|
||||
}
|
||||
}
|
||||
Self::portable()
|
||||
}
|
||||
|
||||
pub fn portable() -> Self {
|
||||
Implementation(Platform::Portable)
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
#[allow(unreachable_code)]
|
||||
pub fn sse41_if_supported() -> Option<Self> {
|
||||
// Check whether SSE4.1 support is assumed by the build.
|
||||
#[cfg(target_feature = "sse4.1")]
|
||||
{
|
||||
return Some(Implementation(Platform::SSE41));
|
||||
}
|
||||
// Otherwise dynamically check for support if we can.
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
if is_x86_feature_detected!("sse4.1") {
|
||||
return Some(Implementation(Platform::SSE41));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
#[allow(unreachable_code)]
|
||||
pub fn avx2_if_supported() -> Option<Self> {
|
||||
// Check whether AVX2 support is assumed by the build.
|
||||
#[cfg(target_feature = "avx2")]
|
||||
{
|
||||
return Some(Implementation(Platform::AVX2));
|
||||
}
|
||||
// Otherwise dynamically check for support if we can.
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
if is_x86_feature_detected!("avx2") {
|
||||
return Some(Implementation(Platform::AVX2));
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn degree(&self) -> usize {
|
||||
match self.0 {
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
Platform::AVX2 => avx2::DEGREE,
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
Platform::SSE41 => sse41::DEGREE,
|
||||
Platform::Portable => 1,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compress1_loop(
|
||||
&self,
|
||||
input: &[u8],
|
||||
words: &mut [Word; 8],
|
||||
count: Count,
|
||||
last_node: LastNode,
|
||||
finalize: Finalize,
|
||||
stride: Stride,
|
||||
) {
|
||||
match self.0 {
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
Platform::AVX2 => unsafe {
|
||||
avx2::compress1_loop(input, words, count, last_node, finalize, stride);
|
||||
},
|
||||
// Note that there's an SSE version of compress1 in the official C
|
||||
// implementation, but I haven't ported it yet.
|
||||
_ => {
|
||||
portable::compress1_loop(input, words, count, last_node, finalize, stride);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compress2_loop(&self, jobs: &mut [Job; 2], finalize: Finalize, stride: Stride) {
|
||||
match self.0 {
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
Platform::AVX2 | Platform::SSE41 => unsafe {
|
||||
sse41::compress2_loop(jobs, finalize, stride)
|
||||
},
|
||||
_ => panic!("unsupported"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compress4_loop(&self, jobs: &mut [Job; 4], finalize: Finalize, stride: Stride) {
|
||||
match self.0 {
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
Platform::AVX2 => unsafe { avx2::compress4_loop(jobs, finalize, stride) },
|
||||
_ => panic!("unsupported"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Job<'a, 'b> {
|
||||
pub input: &'a [u8],
|
||||
pub words: &'b mut [Word; 8],
|
||||
pub count: Count,
|
||||
pub last_node: LastNode,
|
||||
}
|
||||
|
||||
impl<'a, 'b> core::fmt::Debug for Job<'a, 'b> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
// NB: Don't print the words. Leaking them would allow length extension.
|
||||
write!(
|
||||
f,
|
||||
"Job {{ input_len: {}, count: {}, last_node: {} }}",
|
||||
self.input.len(),
|
||||
self.count,
|
||||
self.last_node.yes(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Finalize could just be a bool, but this is easier to read at callsites.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum Finalize {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
impl Finalize {
|
||||
pub fn yes(&self) -> bool {
|
||||
match self {
|
||||
Finalize::Yes => true,
|
||||
Finalize::No => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Like Finalize, this is easier to read at callsites.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum LastNode {
|
||||
Yes,
|
||||
No,
|
||||
}
|
||||
|
||||
impl LastNode {
|
||||
pub fn yes(&self) -> bool {
|
||||
match self {
|
||||
LastNode::Yes => true,
|
||||
LastNode::No => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum Stride {
|
||||
Serial, // BLAKE2b/BLAKE2s
|
||||
Parallel, // BLAKE2bp/BLAKE2sp
|
||||
}
|
||||
|
||||
impl Stride {
|
||||
pub fn padded_blockbytes(&self) -> usize {
|
||||
match self {
|
||||
Stride::Serial => BLOCKBYTES,
|
||||
Stride::Parallel => blake2bp::DEGREE * BLOCKBYTES,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn count_low(count: Count) -> Word {
|
||||
count as Word
|
||||
}
|
||||
|
||||
pub(crate) fn count_high(count: Count) -> Word {
|
||||
(count >> 8 * size_of::<Word>()) as Word
|
||||
}
|
||||
|
||||
pub(crate) fn assemble_count(low: Word, high: Word) -> Count {
|
||||
low as Count + ((high as Count) << 8 * size_of::<Word>())
|
||||
}
|
||||
|
||||
pub(crate) fn flag_word(flag: bool) -> Word {
|
||||
if flag {
|
||||
!0
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
// Pull a array reference at the given offset straight from the input, if
|
||||
// there's a full block of input available. If there's only a partial block,
|
||||
// copy it into the provided buffer, and return an array reference that. Along
|
||||
// with the array, return the number of bytes of real input, and whether the
|
||||
// input can be finalized (i.e. whether there aren't any more bytes after this
|
||||
// block). Note that this is written so that the optimizer can elide bounds
|
||||
// checks, see: https://godbolt.org/z/0hH2bC
|
||||
pub fn final_block<'a>(
|
||||
input: &'a [u8],
|
||||
offset: usize,
|
||||
buffer: &'a mut [u8; BLOCKBYTES],
|
||||
stride: Stride,
|
||||
) -> (&'a [u8; BLOCKBYTES], usize, bool) {
|
||||
let capped_offset = cmp::min(offset, input.len());
|
||||
let offset_slice = &input[capped_offset..];
|
||||
if offset_slice.len() >= BLOCKBYTES {
|
||||
let block = array_ref!(offset_slice, 0, BLOCKBYTES);
|
||||
let should_finalize = offset_slice.len() <= stride.padded_blockbytes();
|
||||
(block, BLOCKBYTES, should_finalize)
|
||||
} else {
|
||||
// Copy the final block to the front of the block buffer. The rest of
|
||||
// the buffer is assumed to be initialized to zero.
|
||||
buffer[..offset_slice.len()].copy_from_slice(offset_slice);
|
||||
(buffer, offset_slice.len(), true)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn input_debug_asserts(input: &[u8], finalize: Finalize) {
|
||||
// If we're not finalizing, the input must not be empty, and it must be an
|
||||
// even multiple of the block size.
|
||||
if !finalize.yes() {
|
||||
debug_assert!(!input.is_empty());
|
||||
debug_assert_eq!(0, input.len() % BLOCKBYTES);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use arrayvec::ArrayVec;
|
||||
use core::mem::size_of;
|
||||
|
||||
#[test]
|
||||
fn test_detection() {
|
||||
assert_eq!(Platform::Portable, Implementation::portable().0);
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
if is_x86_feature_detected!("avx2") {
|
||||
assert_eq!(Platform::AVX2, Implementation::detect().0);
|
||||
assert_eq!(
|
||||
Platform::AVX2,
|
||||
Implementation::avx2_if_supported().unwrap().0
|
||||
);
|
||||
assert_eq!(
|
||||
Platform::SSE41,
|
||||
Implementation::sse41_if_supported().unwrap().0
|
||||
);
|
||||
} else if is_x86_feature_detected!("sse4.1") {
|
||||
assert_eq!(Platform::SSE41, Implementation::detect().0);
|
||||
assert!(Implementation::avx2_if_supported().is_none());
|
||||
assert_eq!(
|
||||
Platform::SSE41,
|
||||
Implementation::sse41_if_supported().unwrap().0
|
||||
);
|
||||
} else {
|
||||
assert_eq!(Platform::Portable, Implementation::detect().0);
|
||||
assert!(Implementation::avx2_if_supported().is_none());
|
||||
assert!(Implementation::sse41_if_supported().is_none());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Move all of these case tests into the implementation files.
|
||||
fn exercise_cases<F>(mut f: F)
|
||||
where
|
||||
F: FnMut(Stride, usize, LastNode, Finalize, Count),
|
||||
{
|
||||
// Chose counts to hit the relevant overflow cases.
|
||||
let counts = &[
|
||||
(0 as Count),
|
||||
((1 as Count) << (8 * size_of::<Word>())) - BLOCKBYTES as Count,
|
||||
(0 as Count).wrapping_sub(BLOCKBYTES as Count),
|
||||
];
|
||||
for &stride in &[Stride::Serial, Stride::Parallel] {
|
||||
let lengths = [
|
||||
0,
|
||||
1,
|
||||
BLOCKBYTES - 1,
|
||||
BLOCKBYTES,
|
||||
BLOCKBYTES + 1,
|
||||
2 * BLOCKBYTES - 1,
|
||||
2 * BLOCKBYTES,
|
||||
2 * BLOCKBYTES + 1,
|
||||
stride.padded_blockbytes() - 1,
|
||||
stride.padded_blockbytes(),
|
||||
stride.padded_blockbytes() + 1,
|
||||
2 * stride.padded_blockbytes() - 1,
|
||||
2 * stride.padded_blockbytes(),
|
||||
2 * stride.padded_blockbytes() + 1,
|
||||
];
|
||||
for &length in &lengths {
|
||||
for &last_node in &[LastNode::No, LastNode::Yes] {
|
||||
for &finalize in &[Finalize::No, Finalize::Yes] {
|
||||
if !finalize.yes() && (length == 0 || length % BLOCKBYTES != 0) {
|
||||
// Skip these cases, they're invalid.
|
||||
continue;
|
||||
}
|
||||
for &count in counts {
|
||||
// eprintln!("\ncase -----");
|
||||
// dbg!(stride);
|
||||
// dbg!(length);
|
||||
// dbg!(last_node);
|
||||
// dbg!(finalize);
|
||||
// dbg!(count);
|
||||
|
||||
f(stride, length, last_node, finalize, count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn initial_test_words(input_index: usize) -> [Word; 8] {
|
||||
crate::Params::new()
|
||||
.node_offset(input_index as u64)
|
||||
.to_words()
|
||||
}
|
||||
|
||||
// Use the portable implementation, one block at a time, to compute the
|
||||
// final state words expected for a given test case.
|
||||
fn reference_compression(
|
||||
input: &[u8],
|
||||
stride: Stride,
|
||||
last_node: LastNode,
|
||||
finalize: Finalize,
|
||||
mut count: Count,
|
||||
input_index: usize,
|
||||
) -> [Word; 8] {
|
||||
let mut words = initial_test_words(input_index);
|
||||
let mut offset = 0;
|
||||
while offset == 0 || offset < input.len() {
|
||||
let block_size = cmp::min(BLOCKBYTES, input.len() - offset);
|
||||
let maybe_finalize = if offset + stride.padded_blockbytes() < input.len() {
|
||||
Finalize::No
|
||||
} else {
|
||||
finalize
|
||||
};
|
||||
portable::compress1_loop(
|
||||
&input[offset..][..block_size],
|
||||
&mut words,
|
||||
count,
|
||||
last_node,
|
||||
maybe_finalize,
|
||||
Stride::Serial,
|
||||
);
|
||||
offset += stride.padded_blockbytes();
|
||||
count = count.wrapping_add(BLOCKBYTES as Count);
|
||||
}
|
||||
words
|
||||
}
|
||||
|
||||
// For various loop lengths and finalization parameters, make sure that the
|
||||
// implementation gives the same answer as the portable implementation does
|
||||
// when invoked one block at a time. (So even the portable implementation
|
||||
// itself is being tested here, to make sure its loop is correct.) Note
|
||||
// that this doesn't include any fixed test vectors; those are taken from
|
||||
// the blake2-kat.json file (copied from upstream) and tested elsewhere.
|
||||
fn exercise_compress1_loop(implementation: Implementation) {
|
||||
let mut input = [0; 100 * BLOCKBYTES];
|
||||
paint_test_input(&mut input);
|
||||
|
||||
exercise_cases(|stride, length, last_node, finalize, count| {
|
||||
let reference_words =
|
||||
reference_compression(&input[..length], stride, last_node, finalize, count, 0);
|
||||
|
||||
let mut test_words = initial_test_words(0);
|
||||
implementation.compress1_loop(
|
||||
&input[..length],
|
||||
&mut test_words,
|
||||
count,
|
||||
last_node,
|
||||
finalize,
|
||||
stride,
|
||||
);
|
||||
assert_eq!(reference_words, test_words);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compress1_loop_portable() {
|
||||
exercise_compress1_loop(Implementation::portable());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
fn test_compress1_loop_sse41() {
|
||||
// Currently this just falls back to portable, but we test it anyway.
|
||||
if let Some(imp) = Implementation::sse41_if_supported() {
|
||||
exercise_compress1_loop(imp);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
fn test_compress1_loop_avx2() {
|
||||
if let Some(imp) = Implementation::avx2_if_supported() {
|
||||
exercise_compress1_loop(imp);
|
||||
}
|
||||
}
|
||||
|
||||
// I use ArrayVec everywhere in here becuase currently these tests pass
|
||||
// under no_std. I might decide that's not worth maintaining at some point,
|
||||
// since really all we care about with no_std is that the library builds,
|
||||
// but for now it's here. Everything is keyed off of this N constant so
|
||||
// that it's easy to copy the code to exercise_compress4_loop.
|
||||
fn exercise_compress2_loop(implementation: Implementation) {
|
||||
const N: usize = 2;
|
||||
|
||||
let mut input_buffer = [0; 100 * BLOCKBYTES];
|
||||
paint_test_input(&mut input_buffer);
|
||||
let mut inputs = ArrayVec::<[_; N]>::new();
|
||||
for i in 0..N {
|
||||
inputs.push(&input_buffer[i..]);
|
||||
}
|
||||
|
||||
exercise_cases(|stride, length, last_node, finalize, count| {
|
||||
let mut reference_words = ArrayVec::<[_; N]>::new();
|
||||
for i in 0..N {
|
||||
let words = reference_compression(
|
||||
&inputs[i][..length],
|
||||
stride,
|
||||
last_node,
|
||||
finalize,
|
||||
count.wrapping_add((i * BLOCKBYTES) as Count),
|
||||
i,
|
||||
);
|
||||
reference_words.push(words);
|
||||
}
|
||||
|
||||
let mut test_words = ArrayVec::<[_; N]>::new();
|
||||
for i in 0..N {
|
||||
test_words.push(initial_test_words(i));
|
||||
}
|
||||
let mut jobs = ArrayVec::<[_; N]>::new();
|
||||
for (i, words) in test_words.iter_mut().enumerate() {
|
||||
jobs.push(Job {
|
||||
input: &inputs[i][..length],
|
||||
words,
|
||||
count: count.wrapping_add((i * BLOCKBYTES) as Count),
|
||||
last_node,
|
||||
});
|
||||
}
|
||||
let mut jobs = jobs.into_inner().expect("full");
|
||||
implementation.compress2_loop(&mut jobs, finalize, stride);
|
||||
|
||||
for i in 0..N {
|
||||
assert_eq!(reference_words[i], test_words[i], "words {} unequal", i);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
fn test_compress2_loop_sse41() {
|
||||
if let Some(imp) = Implementation::sse41_if_supported() {
|
||||
exercise_compress2_loop(imp);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
fn test_compress2_loop_avx2() {
|
||||
// Currently this just falls back to SSE4.1, but we test it anyway.
|
||||
if let Some(imp) = Implementation::avx2_if_supported() {
|
||||
exercise_compress2_loop(imp);
|
||||
}
|
||||
}
|
||||
|
||||
// Copied from exercise_compress2_loop, with a different value of N and an
|
||||
// interior call to compress4_loop.
|
||||
fn exercise_compress4_loop(implementation: Implementation) {
|
||||
const N: usize = 4;
|
||||
|
||||
let mut input_buffer = [0; 100 * BLOCKBYTES];
|
||||
paint_test_input(&mut input_buffer);
|
||||
let mut inputs = ArrayVec::<[_; N]>::new();
|
||||
for i in 0..N {
|
||||
inputs.push(&input_buffer[i..]);
|
||||
}
|
||||
|
||||
exercise_cases(|stride, length, last_node, finalize, count| {
|
||||
let mut reference_words = ArrayVec::<[_; N]>::new();
|
||||
for i in 0..N {
|
||||
let words = reference_compression(
|
||||
&inputs[i][..length],
|
||||
stride,
|
||||
last_node,
|
||||
finalize,
|
||||
count.wrapping_add((i * BLOCKBYTES) as Count),
|
||||
i,
|
||||
);
|
||||
reference_words.push(words);
|
||||
}
|
||||
|
||||
let mut test_words = ArrayVec::<[_; N]>::new();
|
||||
for i in 0..N {
|
||||
test_words.push(initial_test_words(i));
|
||||
}
|
||||
let mut jobs = ArrayVec::<[_; N]>::new();
|
||||
for (i, words) in test_words.iter_mut().enumerate() {
|
||||
jobs.push(Job {
|
||||
input: &inputs[i][..length],
|
||||
words,
|
||||
count: count.wrapping_add((i * BLOCKBYTES) as Count),
|
||||
last_node,
|
||||
});
|
||||
}
|
||||
let mut jobs = jobs.into_inner().expect("full");
|
||||
implementation.compress4_loop(&mut jobs, finalize, stride);
|
||||
|
||||
for i in 0..N {
|
||||
assert_eq!(reference_words[i], test_words[i], "words {} unequal", i);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
fn test_compress4_loop_avx2() {
|
||||
if let Some(imp) = Implementation::avx2_if_supported() {
|
||||
exercise_compress4_loop(imp);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sanity_check_count_size() {
|
||||
assert_eq!(size_of::<Count>(), 2 * size_of::<Word>());
|
||||
}
|
||||
}
|
674
third_party/rust/blake2b_simd/src/lib.rs
vendored
674
third_party/rust/blake2b_simd/src/lib.rs
vendored
@ -1,674 +0,0 @@
|
||||
//! [![GitHub](https://img.shields.io/github/tag/oconnor663/blake2_simd.svg?label=GitHub)](https://github.com/oconnor663/blake2_simd) [![crates.io](https://img.shields.io/crates/v/blake2b_simd.svg)](https://crates.io/crates/blake2b_simd) [![Actions Status](https://github.com/oconnor663/blake2_simd/workflows/tests/badge.svg)](https://github.com/oconnor663/blake2_simd/actions)
|
||||
//!
|
||||
//! An implementation of the BLAKE2b and BLAKE2bp hash functions. See also
|
||||
//! [`blake2s_simd`](https://docs.rs/blake2s_simd).
|
||||
//!
|
||||
//! This crate includes:
|
||||
//!
|
||||
//! - 100% stable Rust.
|
||||
//! - SIMD implementations based on Samuel Neves' [`blake2-avx2`](https://github.com/sneves/blake2-avx2).
|
||||
//! These are very fast. For benchmarks, see [the Performance section of the
|
||||
//! README](https://github.com/oconnor663/blake2_simd#performance).
|
||||
//! - Portable, safe implementations for other platforms.
|
||||
//! - Dynamic CPU feature detection. Binaries include multiple implementations by default and
|
||||
//! choose the fastest one the processor supports at runtime.
|
||||
//! - All the features from the [the BLAKE2 spec](https://blake2.net/blake2.pdf), like adjustable
|
||||
//! length, keying, and associated data for tree hashing.
|
||||
//! - `no_std` support. The `std` Cargo feature is on by default, for CPU feature detection and
|
||||
//! for implementing `std::io::Write`.
|
||||
//! - Support for computing multiple BLAKE2b hashes in parallel, matching the efficiency of
|
||||
//! BLAKE2bp. See the [`many`](many/index.html) module.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```
|
||||
//! use blake2b_simd::{blake2b, Params};
|
||||
//!
|
||||
//! let expected = "ca002330e69d3e6b84a46a56a6533fd79d51d97a3bb7cad6c2ff43b354185d6d\
|
||||
//! c1e723fb3db4ae0737e120378424c714bb982d9dc5bbd7a0ab318240ddd18f8d";
|
||||
//! let hash = blake2b(b"foo");
|
||||
//! assert_eq!(expected, &hash.to_hex());
|
||||
//!
|
||||
//! let hash = Params::new()
|
||||
//! .hash_length(16)
|
||||
//! .key(b"The Magic Words are Squeamish Ossifrage")
|
||||
//! .personal(b"L. P. Waterhouse")
|
||||
//! .to_state()
|
||||
//! .update(b"foo")
|
||||
//! .update(b"bar")
|
||||
//! .update(b"baz")
|
||||
//! .finalize();
|
||||
//! assert_eq!("ee8ff4e9be887297cf79348dc35dab56", &hash.to_hex());
|
||||
//! ```
|
||||
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
use arrayref::{array_refs, mut_array_refs};
|
||||
use core::cmp;
|
||||
use core::fmt;
|
||||
use core::mem::size_of;
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
mod avx2;
|
||||
mod portable;
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
mod sse41;
|
||||
|
||||
pub mod blake2bp;
|
||||
mod guts;
|
||||
pub mod many;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
type Word = u64;
|
||||
type Count = u128;
|
||||
|
||||
/// The max hash length.
|
||||
pub const OUTBYTES: usize = 8 * size_of::<Word>();
|
||||
/// The max key length.
|
||||
pub const KEYBYTES: usize = 8 * size_of::<Word>();
|
||||
/// The max salt length.
|
||||
pub const SALTBYTES: usize = 2 * size_of::<Word>();
|
||||
/// The max personalization length.
|
||||
pub const PERSONALBYTES: usize = 2 * size_of::<Word>();
|
||||
/// The number input bytes passed to each call to the compression function. Small benchmarks need
|
||||
/// to use an even multiple of `BLOCKBYTES`, or else their apparent throughput will be low.
|
||||
pub const BLOCKBYTES: usize = 16 * size_of::<Word>();
|
||||
|
||||
const IV: [Word; 8] = [
|
||||
0x6A09E667F3BCC908,
|
||||
0xBB67AE8584CAA73B,
|
||||
0x3C6EF372FE94F82B,
|
||||
0xA54FF53A5F1D36F1,
|
||||
0x510E527FADE682D1,
|
||||
0x9B05688C2B3E6C1F,
|
||||
0x1F83D9ABFB41BD6B,
|
||||
0x5BE0CD19137E2179,
|
||||
];
|
||||
|
||||
const SIGMA: [[u8; 16]; 12] = [
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
|
||||
[14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
|
||||
[11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
|
||||
[7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
|
||||
[9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
|
||||
[2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
|
||||
[12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11],
|
||||
[13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
|
||||
[6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
|
||||
[10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
|
||||
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
|
||||
[14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
|
||||
];
|
||||
|
||||
/// Compute the BLAKE2b hash of a slice of bytes all at once, using default
|
||||
/// parameters.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use blake2b_simd::{blake2b, Params};
|
||||
/// let expected = "ca002330e69d3e6b84a46a56a6533fd79d51d97a3bb7cad6c2ff43b354185d6d\
|
||||
/// c1e723fb3db4ae0737e120378424c714bb982d9dc5bbd7a0ab318240ddd18f8d";
|
||||
/// let hash = blake2b(b"foo");
|
||||
/// assert_eq!(expected, &hash.to_hex());
|
||||
/// ```
|
||||
pub fn blake2b(input: &[u8]) -> Hash {
|
||||
Params::new().hash(input)
|
||||
}
|
||||
|
||||
/// A parameter builder that exposes all the non-default BLAKE2 features.
|
||||
///
|
||||
/// Apart from `hash_length`, which controls the length of the final `Hash`,
|
||||
/// all of these parameters are just associated data that gets mixed with the
|
||||
/// input. For more details, see [the BLAKE2 spec](https://blake2.net/blake2.pdf).
|
||||
///
|
||||
/// Several of the parameters have a valid range defined in the spec and
|
||||
/// documented below. Trying to set an invalid parameter will panic.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use blake2b_simd::Params;
|
||||
/// // Create a Params object with a secret key and a non-default length.
|
||||
/// let mut params = Params::new();
|
||||
/// params.key(b"my secret key");
|
||||
/// params.hash_length(16);
|
||||
///
|
||||
/// // Use those params to hash an input all at once.
|
||||
/// let hash = params.hash(b"my input");
|
||||
///
|
||||
/// // Or use those params to build an incremental State.
|
||||
/// let mut state = params.to_state();
|
||||
/// ```
|
||||
#[derive(Clone)]
|
||||
pub struct Params {
|
||||
hash_length: u8,
|
||||
key_length: u8,
|
||||
key_block: [u8; BLOCKBYTES],
|
||||
salt: [u8; SALTBYTES],
|
||||
personal: [u8; PERSONALBYTES],
|
||||
fanout: u8,
|
||||
max_depth: u8,
|
||||
max_leaf_length: u32,
|
||||
node_offset: u64,
|
||||
node_depth: u8,
|
||||
inner_hash_length: u8,
|
||||
last_node: guts::LastNode,
|
||||
implementation: guts::Implementation,
|
||||
}
|
||||
|
||||
impl Params {
|
||||
/// Equivalent to `Params::default()`.
|
||||
#[inline]
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
hash_length: OUTBYTES as u8,
|
||||
key_length: 0,
|
||||
key_block: [0; BLOCKBYTES],
|
||||
salt: [0; SALTBYTES],
|
||||
personal: [0; PERSONALBYTES],
|
||||
// NOTE: fanout and max_depth don't default to zero!
|
||||
fanout: 1,
|
||||
max_depth: 1,
|
||||
max_leaf_length: 0,
|
||||
node_offset: 0,
|
||||
node_depth: 0,
|
||||
inner_hash_length: 0,
|
||||
last_node: guts::LastNode::No,
|
||||
implementation: guts::Implementation::detect(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn to_words(&self) -> [Word; 8] {
|
||||
let (salt_left, salt_right) = array_refs!(&self.salt, SALTBYTES / 2, SALTBYTES / 2);
|
||||
let (personal_left, personal_right) =
|
||||
array_refs!(&self.personal, PERSONALBYTES / 2, PERSONALBYTES / 2);
|
||||
[
|
||||
IV[0]
|
||||
^ self.hash_length as u64
|
||||
^ (self.key_length as u64) << 8
|
||||
^ (self.fanout as u64) << 16
|
||||
^ (self.max_depth as u64) << 24
|
||||
^ (self.max_leaf_length as u64) << 32,
|
||||
IV[1] ^ self.node_offset,
|
||||
IV[2] ^ self.node_depth as u64 ^ (self.inner_hash_length as u64) << 8,
|
||||
IV[3],
|
||||
IV[4] ^ Word::from_le_bytes(*salt_left),
|
||||
IV[5] ^ Word::from_le_bytes(*salt_right),
|
||||
IV[6] ^ Word::from_le_bytes(*personal_left),
|
||||
IV[7] ^ Word::from_le_bytes(*personal_right),
|
||||
]
|
||||
}
|
||||
|
||||
/// Hash an input all at once with these parameters.
|
||||
#[inline]
|
||||
pub fn hash(&self, input: &[u8]) -> Hash {
|
||||
// If there's a key, just fall back to using the State.
|
||||
if self.key_length > 0 {
|
||||
return self.to_state().update(input).finalize();
|
||||
}
|
||||
let mut words = self.to_words();
|
||||
self.implementation.compress1_loop(
|
||||
input,
|
||||
&mut words,
|
||||
0,
|
||||
self.last_node,
|
||||
guts::Finalize::Yes,
|
||||
guts::Stride::Serial,
|
||||
);
|
||||
Hash {
|
||||
bytes: state_words_to_bytes(&words),
|
||||
len: self.hash_length,
|
||||
}
|
||||
}
|
||||
|
||||
/// Construct a `State` object based on these parameters, for hashing input
|
||||
/// incrementally.
|
||||
pub fn to_state(&self) -> State {
|
||||
State::with_params(self)
|
||||
}
|
||||
|
||||
/// Set the length of the final hash in bytes, from 1 to `OUTBYTES` (64). Apart from
|
||||
/// controlling the length of the final `Hash`, this is also associated data, and changing it
|
||||
/// will result in a totally different hash.
|
||||
#[inline]
|
||||
pub fn hash_length(&mut self, length: usize) -> &mut Self {
|
||||
assert!(
|
||||
1 <= length && length <= OUTBYTES,
|
||||
"Bad hash length: {}",
|
||||
length
|
||||
);
|
||||
self.hash_length = length as u8;
|
||||
self
|
||||
}
|
||||
|
||||
/// Use a secret key, so that BLAKE2 acts as a MAC. The maximum key length is `KEYBYTES` (64).
|
||||
/// An empty key is equivalent to having no key at all.
|
||||
#[inline]
|
||||
pub fn key(&mut self, key: &[u8]) -> &mut Self {
|
||||
assert!(key.len() <= KEYBYTES, "Bad key length: {}", key.len());
|
||||
self.key_length = key.len() as u8;
|
||||
self.key_block = [0; BLOCKBYTES];
|
||||
self.key_block[..key.len()].copy_from_slice(key);
|
||||
self
|
||||
}
|
||||
|
||||
/// At most `SALTBYTES` (16). Shorter salts are padded with null bytes. An empty salt is
|
||||
/// equivalent to having no salt at all.
|
||||
#[inline]
|
||||
pub fn salt(&mut self, salt: &[u8]) -> &mut Self {
|
||||
assert!(salt.len() <= SALTBYTES, "Bad salt length: {}", salt.len());
|
||||
self.salt = [0; SALTBYTES];
|
||||
self.salt[..salt.len()].copy_from_slice(salt);
|
||||
self
|
||||
}
|
||||
|
||||
/// At most `PERSONALBYTES` (16). Shorter personalizations are padded with null bytes. An empty
|
||||
/// personalization is equivalent to having no personalization at all.
|
||||
#[inline]
|
||||
pub fn personal(&mut self, personalization: &[u8]) -> &mut Self {
|
||||
assert!(
|
||||
personalization.len() <= PERSONALBYTES,
|
||||
"Bad personalization length: {}",
|
||||
personalization.len()
|
||||
);
|
||||
self.personal = [0; PERSONALBYTES];
|
||||
self.personal[..personalization.len()].copy_from_slice(personalization);
|
||||
self
|
||||
}
|
||||
|
||||
/// From 0 (meaning unlimited) to 255. The default is 1 (meaning sequential).
|
||||
#[inline]
|
||||
pub fn fanout(&mut self, fanout: u8) -> &mut Self {
|
||||
self.fanout = fanout;
|
||||
self
|
||||
}
|
||||
|
||||
/// From 0 (meaning BLAKE2X B2 hashes), through 1 (the default, meaning sequential) to 255 (meaning unlimited).
|
||||
#[inline]
|
||||
pub fn max_depth(&mut self, depth: u8) -> &mut Self {
|
||||
self.max_depth = depth;
|
||||
self
|
||||
}
|
||||
|
||||
/// From 0 (the default, meaning unlimited or sequential) to `2^32 - 1`.
|
||||
#[inline]
|
||||
pub fn max_leaf_length(&mut self, length: u32) -> &mut Self {
|
||||
self.max_leaf_length = length;
|
||||
self
|
||||
}
|
||||
|
||||
/// From 0 (the default, meaning first, leftmost, leaf, or sequential) to `2^64 - 1`.
|
||||
#[inline]
|
||||
pub fn node_offset(&mut self, offset: u64) -> &mut Self {
|
||||
self.node_offset = offset;
|
||||
self
|
||||
}
|
||||
|
||||
/// From 0 (the default, meaning leaf or sequential) to 255.
|
||||
#[inline]
|
||||
pub fn node_depth(&mut self, depth: u8) -> &mut Self {
|
||||
self.node_depth = depth;
|
||||
self
|
||||
}
|
||||
|
||||
/// From 0 (the default, meaning sequential) to `OUTBYTES` (64).
|
||||
#[inline]
|
||||
pub fn inner_hash_length(&mut self, length: usize) -> &mut Self {
|
||||
assert!(length <= OUTBYTES, "Bad inner hash length: {}", length);
|
||||
self.inner_hash_length = length as u8;
|
||||
self
|
||||
}
|
||||
|
||||
/// Indicates the rightmost node in a row. This can also be changed on the
|
||||
/// `State` object, potentially after hashing has begun. See
|
||||
/// [`State::set_last_node`].
|
||||
///
|
||||
/// [`State::set_last_node`]: struct.State.html#method.set_last_node
|
||||
#[inline]
|
||||
pub fn last_node(&mut self, last_node: bool) -> &mut Self {
|
||||
self.last_node = if last_node {
|
||||
guts::LastNode::Yes
|
||||
} else {
|
||||
guts::LastNode::No
|
||||
};
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Params {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Params {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"Params {{ hash_length: {}, key_length: {}, salt: {:?}, personal: {:?}, fanout: {}, \
|
||||
max_depth: {}, max_leaf_length: {}, node_offset: {}, node_depth: {}, \
|
||||
inner_hash_length: {}, last_node: {} }}",
|
||||
self.hash_length,
|
||||
// NB: Don't print the key itself. Debug shouldn't leak secrets.
|
||||
self.key_length,
|
||||
&self.salt,
|
||||
&self.personal,
|
||||
self.fanout,
|
||||
self.max_depth,
|
||||
self.max_leaf_length,
|
||||
self.node_offset,
|
||||
self.node_depth,
|
||||
self.inner_hash_length,
|
||||
self.last_node.yes(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// An incremental hasher for BLAKE2b.
|
||||
///
|
||||
/// To construct a `State` with non-default parameters, see `Params::to_state`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use blake2b_simd::{State, blake2b};
|
||||
///
|
||||
/// let mut state = blake2b_simd::State::new();
|
||||
///
|
||||
/// state.update(b"foo");
|
||||
/// assert_eq!(blake2b(b"foo"), state.finalize());
|
||||
///
|
||||
/// state.update(b"bar");
|
||||
/// assert_eq!(blake2b(b"foobar"), state.finalize());
|
||||
/// ```
|
||||
#[derive(Clone)]
|
||||
pub struct State {
|
||||
words: [Word; 8],
|
||||
count: Count,
|
||||
buf: [u8; BLOCKBYTES],
|
||||
buflen: u8,
|
||||
last_node: guts::LastNode,
|
||||
hash_length: u8,
|
||||
implementation: guts::Implementation,
|
||||
is_keyed: bool,
|
||||
}
|
||||
|
||||
impl State {
|
||||
/// Equivalent to `State::default()` or `Params::default().to_state()`.
|
||||
pub fn new() -> Self {
|
||||
Self::with_params(&Params::default())
|
||||
}
|
||||
|
||||
fn with_params(params: &Params) -> Self {
|
||||
let mut state = Self {
|
||||
words: params.to_words(),
|
||||
count: 0,
|
||||
buf: [0; BLOCKBYTES],
|
||||
buflen: 0,
|
||||
last_node: params.last_node,
|
||||
hash_length: params.hash_length,
|
||||
implementation: params.implementation,
|
||||
is_keyed: params.key_length > 0,
|
||||
};
|
||||
if state.is_keyed {
|
||||
state.buf = params.key_block;
|
||||
state.buflen = state.buf.len() as u8;
|
||||
}
|
||||
state
|
||||
}
|
||||
|
||||
fn fill_buf(&mut self, input: &mut &[u8]) {
|
||||
let take = cmp::min(BLOCKBYTES - self.buflen as usize, input.len());
|
||||
self.buf[self.buflen as usize..self.buflen as usize + take].copy_from_slice(&input[..take]);
|
||||
self.buflen += take as u8;
|
||||
*input = &input[take..];
|
||||
}
|
||||
|
||||
// If the state already has some input in its buffer, try to fill the buffer and perform a
|
||||
// compression. However, only do the compression if there's more input coming, otherwise it
|
||||
// will give the wrong hash it the caller finalizes immediately after.
|
||||
fn compress_buffer_if_possible(&mut self, input: &mut &[u8]) {
|
||||
if self.buflen > 0 {
|
||||
self.fill_buf(input);
|
||||
if !input.is_empty() {
|
||||
self.implementation.compress1_loop(
|
||||
&self.buf,
|
||||
&mut self.words,
|
||||
self.count,
|
||||
self.last_node,
|
||||
guts::Finalize::No,
|
||||
guts::Stride::Serial,
|
||||
);
|
||||
self.count = self.count.wrapping_add(BLOCKBYTES as Count);
|
||||
self.buflen = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Add input to the hash. You can call `update` any number of times.
|
||||
pub fn update(&mut self, mut input: &[u8]) -> &mut Self {
|
||||
// If we have a partial buffer, try to complete it.
|
||||
self.compress_buffer_if_possible(&mut input);
|
||||
// While there's more than a block of input left (which also means we cleared the buffer
|
||||
// above), compress blocks directly without copying.
|
||||
let mut end = input.len().saturating_sub(1);
|
||||
end -= end % BLOCKBYTES;
|
||||
if end > 0 {
|
||||
self.implementation.compress1_loop(
|
||||
&input[..end],
|
||||
&mut self.words,
|
||||
self.count,
|
||||
self.last_node,
|
||||
guts::Finalize::No,
|
||||
guts::Stride::Serial,
|
||||
);
|
||||
self.count = self.count.wrapping_add(end as Count);
|
||||
input = &input[end..];
|
||||
}
|
||||
// Buffer any remaining input, to be either compressed or finalized in a subsequent call.
|
||||
// Note that this represents some copying overhead, which in theory we could avoid in
|
||||
// all-at-once setting. A function hardcoded for exactly BLOCKSIZE input bytes is about 10%
|
||||
// faster than using this implementation for the same input.
|
||||
self.fill_buf(&mut input);
|
||||
self
|
||||
}
|
||||
|
||||
/// Finalize the state and return a `Hash`. This method is idempotent, and calling it multiple
|
||||
/// times will give the same result. It's also possible to `update` with more input in between.
|
||||
pub fn finalize(&self) -> Hash {
|
||||
let mut words_copy = self.words;
|
||||
self.implementation.compress1_loop(
|
||||
&self.buf[..self.buflen as usize],
|
||||
&mut words_copy,
|
||||
self.count,
|
||||
self.last_node,
|
||||
guts::Finalize::Yes,
|
||||
guts::Stride::Serial,
|
||||
);
|
||||
Hash {
|
||||
bytes: state_words_to_bytes(&words_copy),
|
||||
len: self.hash_length,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set a flag indicating that this is the last node of its level in a tree hash. This is
|
||||
/// equivalent to [`Params::last_node`], except that it can be set at any time before calling
|
||||
/// `finalize`. That allows callers to begin hashing a node without knowing ahead of time
|
||||
/// whether it's the last in its level. For more details about the intended use of this flag
|
||||
/// [the BLAKE2 spec].
|
||||
///
|
||||
/// [`Params::last_node`]: struct.Params.html#method.last_node
|
||||
/// [the BLAKE2 spec]: https://blake2.net/blake2.pdf
|
||||
pub fn set_last_node(&mut self, last_node: bool) -> &mut Self {
|
||||
self.last_node = if last_node {
|
||||
guts::LastNode::Yes
|
||||
} else {
|
||||
guts::LastNode::No
|
||||
};
|
||||
self
|
||||
}
|
||||
|
||||
/// Return the total number of bytes input so far.
|
||||
///
|
||||
/// Note that `count` doesn't include the bytes of the key block, if any.
|
||||
/// It's exactly the total number of input bytes fed to `update`.
|
||||
pub fn count(&self) -> Count {
|
||||
let mut ret = self.count.wrapping_add(self.buflen as Count);
|
||||
if self.is_keyed {
|
||||
ret -= BLOCKBYTES as Count;
|
||||
}
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn state_words_to_bytes(state_words: &[Word; 8]) -> [u8; OUTBYTES] {
|
||||
let mut bytes = [0; OUTBYTES];
|
||||
{
|
||||
const W: usize = size_of::<Word>();
|
||||
let refs = mut_array_refs!(&mut bytes, W, W, W, W, W, W, W, W);
|
||||
*refs.0 = state_words[0].to_le_bytes();
|
||||
*refs.1 = state_words[1].to_le_bytes();
|
||||
*refs.2 = state_words[2].to_le_bytes();
|
||||
*refs.3 = state_words[3].to_le_bytes();
|
||||
*refs.4 = state_words[4].to_le_bytes();
|
||||
*refs.5 = state_words[5].to_le_bytes();
|
||||
*refs.6 = state_words[6].to_le_bytes();
|
||||
*refs.7 = state_words[7].to_le_bytes();
|
||||
}
|
||||
bytes
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
impl std::io::Write for State {
|
||||
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
|
||||
self.update(buf);
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> std::io::Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for State {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
// NB: Don't print the words. Leaking them would allow length extension.
|
||||
write!(
|
||||
f,
|
||||
"State {{ count: {}, hash_length: {}, last_node: {} }}",
|
||||
self.count(),
|
||||
self.hash_length,
|
||||
self.last_node.yes(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for State {
|
||||
fn default() -> Self {
|
||||
Self::with_params(&Params::default())
|
||||
}
|
||||
}
|
||||
|
||||
type HexString = arrayvec::ArrayString<[u8; 2 * OUTBYTES]>;
|
||||
|
||||
/// A finalized BLAKE2 hash, with constant-time equality.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Hash {
|
||||
bytes: [u8; OUTBYTES],
|
||||
len: u8,
|
||||
}
|
||||
|
||||
impl Hash {
|
||||
/// Convert the hash to a byte slice. Note that if you're using BLAKE2 as a MAC, you need
|
||||
/// constant time equality, which `&[u8]` doesn't provide.
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
&self.bytes[..self.len as usize]
|
||||
}
|
||||
|
||||
/// Convert the hash to a byte array. Note that if you're using BLAKE2 as a
|
||||
/// MAC, you need constant time equality, which arrays don't provide. This
|
||||
/// panics in debug mode if the length of the hash isn't `OUTBYTES`.
|
||||
#[inline]
|
||||
pub fn as_array(&self) -> &[u8; OUTBYTES] {
|
||||
debug_assert_eq!(self.len as usize, OUTBYTES);
|
||||
&self.bytes
|
||||
}
|
||||
|
||||
/// Convert the hash to a lowercase hexadecimal
|
||||
/// [`ArrayString`](https://docs.rs/arrayvec/0.4/arrayvec/struct.ArrayString.html).
|
||||
pub fn to_hex(&self) -> HexString {
|
||||
bytes_to_hex(self.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
fn bytes_to_hex(bytes: &[u8]) -> HexString {
|
||||
let mut s = arrayvec::ArrayString::new();
|
||||
let table = b"0123456789abcdef";
|
||||
for &b in bytes {
|
||||
s.push(table[(b >> 4) as usize] as char);
|
||||
s.push(table[(b & 0xf) as usize] as char);
|
||||
}
|
||||
s
|
||||
}
|
||||
|
||||
/// This implementation is constant time, if the two hashes are the same length.
|
||||
impl PartialEq for Hash {
|
||||
fn eq(&self, other: &Hash) -> bool {
|
||||
constant_time_eq::constant_time_eq(&self.as_bytes(), &other.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
/// This implementation is constant time, if the slice is the same length as the hash.
|
||||
impl PartialEq<[u8]> for Hash {
|
||||
fn eq(&self, other: &[u8]) -> bool {
|
||||
constant_time_eq::constant_time_eq(&self.as_bytes(), other)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Hash {}
|
||||
|
||||
impl AsRef<[u8]> for Hash {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
self.as_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Hash {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Hash(0x{})", self.to_hex())
|
||||
}
|
||||
}
|
||||
|
||||
// Paint a byte pattern that won't repeat, so that we don't accidentally miss
|
||||
// buffer offset bugs. This is the same as what Bao uses in its tests.
|
||||
#[cfg(test)]
|
||||
fn paint_test_input(buf: &mut [u8]) {
|
||||
let mut offset = 0;
|
||||
let mut counter: u32 = 1;
|
||||
while offset < buf.len() {
|
||||
let bytes = counter.to_le_bytes();
|
||||
let take = cmp::min(bytes.len(), buf.len() - offset);
|
||||
buf[offset..][..take].copy_from_slice(&bytes[..take]);
|
||||
counter += 1;
|
||||
offset += take;
|
||||
}
|
||||
}
|
||||
|
||||
// This module is pub for internal benchmarks only. Please don't use it.
|
||||
#[doc(hidden)]
|
||||
pub mod benchmarks {
|
||||
use super::*;
|
||||
|
||||
pub fn force_portable(params: &mut Params) {
|
||||
params.implementation = guts::Implementation::portable();
|
||||
}
|
||||
|
||||
pub fn force_portable_blake2bp(params: &mut blake2bp::Params) {
|
||||
blake2bp::force_portable(params);
|
||||
}
|
||||
}
|
529
third_party/rust/blake2b_simd/src/many.rs
vendored
529
third_party/rust/blake2b_simd/src/many.rs
vendored
@ -1,529 +0,0 @@
|
||||
//! Interfaces for hashing multiple inputs at once, using SIMD more
|
||||
//! efficiently.
|
||||
//!
|
||||
//! The throughput of these interfaces is comparable to BLAKE2bp, about twice
|
||||
//! the throughput of regular BLAKE2b when AVX2 is available.
|
||||
//!
|
||||
//! These interfaces can accept any number of inputs, and the implementation
|
||||
//! does its best to parallelize them. In general, the more inputs you can pass
|
||||
//! in at once the better. If you need to batch your inputs in smaller groups,
|
||||
//! see the [`degree`](fn.degree.html) function for a good batch size.
|
||||
//!
|
||||
//! The implementation keeps working in parallel even when inputs are of
|
||||
//! different lengths, by managing a working set of jobs whose input isn't yet
|
||||
//! exhausted. However, if one or two inputs are much longer than the others,
|
||||
//! and they're encountered only at the end, there might not be any remaining
|
||||
//! work to parallelize them with. In this case, sorting the inputs
|
||||
//! longest-first can improve parallelism.
|
||||
//!
|
||||
//! # Example
|
||||
//!
|
||||
//! ```
|
||||
//! use blake2b_simd::{blake2b, State, many::update_many};
|
||||
//!
|
||||
//! let mut states = [
|
||||
//! State::new(),
|
||||
//! State::new(),
|
||||
//! State::new(),
|
||||
//! State::new(),
|
||||
//! ];
|
||||
//!
|
||||
//! let inputs = [
|
||||
//! &b"foo"[..],
|
||||
//! &b"bar"[..],
|
||||
//! &b"baz"[..],
|
||||
//! &b"bing"[..],
|
||||
//! ];
|
||||
//!
|
||||
//! update_many(states.iter_mut().zip(inputs.iter()));
|
||||
//!
|
||||
//! for (state, input) in states.iter_mut().zip(inputs.iter()) {
|
||||
//! assert_eq!(blake2b(input), state.finalize());
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
use crate::guts::{self, Finalize, Implementation, Job, LastNode, Stride};
|
||||
use crate::state_words_to_bytes;
|
||||
use crate::Count;
|
||||
use crate::Hash;
|
||||
use crate::Params;
|
||||
use crate::State;
|
||||
use crate::Word;
|
||||
use crate::BLOCKBYTES;
|
||||
use arrayref::array_mut_ref;
|
||||
use arrayvec::ArrayVec;
|
||||
use core::fmt;
|
||||
|
||||
/// The largest possible value of [`degree`](fn.degree.html) on the target
|
||||
/// platform.
|
||||
///
|
||||
/// Note that this constant reflects the parallelism degree supported by this
|
||||
/// crate, so it will change over time as support is added or removed. For
|
||||
/// example, when Rust stabilizes AVX-512 support and this crate adds an
|
||||
/// AVX-512 implementation, this constant will double on x86 targets. If that
|
||||
/// implementation is an optional feature (e.g. because it's nightly-only), the
|
||||
/// value of this constant will depend on that optional feature also.
|
||||
pub const MAX_DEGREE: usize = guts::MAX_DEGREE;
|
||||
|
||||
/// The parallelism degree of the implementation, detected at runtime. If you
|
||||
/// hash your inputs in small batches, making the batch size a multiple of
|
||||
/// `degree` will generally give good performance.
|
||||
///
|
||||
/// For example, an x86 processor that supports AVX2 can compute four BLAKE2b
|
||||
/// hashes in parallel, so `degree` returns 4 on that machine. If you call
|
||||
/// [`hash_many`] with only three inputs, that's not enough to use the AVX2
|
||||
/// implementation, and your average throughput will be lower. Likewise if you
|
||||
/// call it with five inputs of equal length, the first four will be hashed in
|
||||
/// parallel with AVX2, but the last one will have to be hashed by itself, and
|
||||
/// again your average throughput will be lower.
|
||||
///
|
||||
/// As noted in the module level docs, performance is more complicated if your
|
||||
/// inputs are of different lengths. When parallelizing long and short inputs
|
||||
/// together, the longer ones will have bytes left over, and the implementation
|
||||
/// will try to parallelize those leftover bytes with subsequent inputs. The
|
||||
/// more inputs available in that case, the more the implementation will be
|
||||
/// able to parallelize.
|
||||
///
|
||||
/// If you need a constant batch size, for example to collect inputs in an
|
||||
/// array, see [`MAX_DEGREE`].
|
||||
///
|
||||
/// [`hash_many`]: fn.hash_many.html
|
||||
/// [`MAX_DEGREE`]: constant.MAX_DEGREE.html
|
||||
pub fn degree() -> usize {
|
||||
guts::Implementation::detect().degree()
|
||||
}
|
||||
|
||||
type JobsVec<'a, 'b> = ArrayVec<[Job<'a, 'b>; guts::MAX_DEGREE]>;
|
||||
|
||||
#[inline(always)]
|
||||
fn fill_jobs_vec<'a, 'b>(
|
||||
jobs_iter: &mut impl Iterator<Item = Job<'a, 'b>>,
|
||||
vec: &mut JobsVec<'a, 'b>,
|
||||
target_len: usize,
|
||||
) {
|
||||
while vec.len() < target_len {
|
||||
if let Some(job) = jobs_iter.next() {
|
||||
vec.push(job);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn evict_finished<'a, 'b>(vec: &mut JobsVec<'a, 'b>, num_jobs: usize) {
|
||||
// Iterate backwards so that removal doesn't cause an out-of-bounds panic.
|
||||
for i in (0..num_jobs).rev() {
|
||||
// Note that is_empty() is only valid because we know all these jobs
|
||||
// have been run at least once. Otherwise we could confuse the empty
|
||||
// input for a finished job, which would be incorrect.
|
||||
//
|
||||
// Avoid a panic branch here in release mode.
|
||||
debug_assert!(vec.len() > i);
|
||||
if vec.len() > i && vec[i].input.is_empty() {
|
||||
// Note that calling pop_at() repeatedly has some overhead, because
|
||||
// later elements need to be shifted up. However, the JobsVec is
|
||||
// small, and this approach guarantees that jobs are encountered in
|
||||
// order.
|
||||
vec.pop_at(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn compress_many<'a, 'b, I>(
|
||||
jobs: I,
|
||||
imp: Implementation,
|
||||
finalize: Finalize,
|
||||
stride: Stride,
|
||||
) where
|
||||
I: IntoIterator<Item = Job<'a, 'b>>,
|
||||
{
|
||||
// Fuse is important for correctness, since each of these blocks tries to
|
||||
// advance the iterator, even if a previous block emptied it.
|
||||
let mut jobs_iter = jobs.into_iter().fuse();
|
||||
let mut jobs_vec = JobsVec::new();
|
||||
|
||||
if imp.degree() >= 4 {
|
||||
loop {
|
||||
fill_jobs_vec(&mut jobs_iter, &mut jobs_vec, 4);
|
||||
if jobs_vec.len() < 4 {
|
||||
break;
|
||||
}
|
||||
let jobs_array = array_mut_ref!(jobs_vec, 0, 4);
|
||||
imp.compress4_loop(jobs_array, finalize, stride);
|
||||
evict_finished(&mut jobs_vec, 4);
|
||||
}
|
||||
}
|
||||
|
||||
if imp.degree() >= 2 {
|
||||
loop {
|
||||
fill_jobs_vec(&mut jobs_iter, &mut jobs_vec, 2);
|
||||
if jobs_vec.len() < 2 {
|
||||
break;
|
||||
}
|
||||
let jobs_array = array_mut_ref!(jobs_vec, 0, 2);
|
||||
imp.compress2_loop(jobs_array, finalize, stride);
|
||||
evict_finished(&mut jobs_vec, 2);
|
||||
}
|
||||
}
|
||||
|
||||
for job in jobs_vec.into_iter().chain(jobs_iter) {
|
||||
let Job {
|
||||
input,
|
||||
words,
|
||||
count,
|
||||
last_node,
|
||||
} = job;
|
||||
imp.compress1_loop(input, words, count, last_node, finalize, stride);
|
||||
}
|
||||
}
|
||||
|
||||
/// Update any number of `State` objects at once.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use blake2b_simd::{blake2b, State, many::update_many};
|
||||
///
|
||||
/// let mut states = [
|
||||
/// State::new(),
|
||||
/// State::new(),
|
||||
/// State::new(),
|
||||
/// State::new(),
|
||||
/// ];
|
||||
///
|
||||
/// let inputs = [
|
||||
/// &b"foo"[..],
|
||||
/// &b"bar"[..],
|
||||
/// &b"baz"[..],
|
||||
/// &b"bing"[..],
|
||||
/// ];
|
||||
///
|
||||
/// update_many(states.iter_mut().zip(inputs.iter()));
|
||||
///
|
||||
/// for (state, input) in states.iter_mut().zip(inputs.iter()) {
|
||||
/// assert_eq!(blake2b(input), state.finalize());
|
||||
/// }
|
||||
/// ```
|
||||
pub fn update_many<'a, 'b, I, T>(pairs: I)
|
||||
where
|
||||
I: IntoIterator<Item = (&'a mut State, &'b T)>,
|
||||
T: 'b + AsRef<[u8]> + ?Sized,
|
||||
{
|
||||
// Get the guts::Implementation from the first state, if any.
|
||||
let mut peekable_pairs = pairs.into_iter().peekable();
|
||||
let implementation = if let Some((state, _)) = peekable_pairs.peek() {
|
||||
state.implementation
|
||||
} else {
|
||||
// No work items, just short circuit.
|
||||
return;
|
||||
};
|
||||
|
||||
// Adapt the pairs iterator into a Jobs iterator, but skip over the Jobs
|
||||
// where there's not actually any work to do (e.g. because there's not much
|
||||
// input and it's all just going in the State buffer).
|
||||
let jobs = peekable_pairs.flat_map(|(state, input_t)| {
|
||||
let mut input = input_t.as_ref();
|
||||
// For each pair, if the State has some input in its buffer, try to
|
||||
// finish that buffer. If there wasn't enough input to do that --
|
||||
// or if the input was empty to begin with -- skip this pair.
|
||||
state.compress_buffer_if_possible(&mut input);
|
||||
if input.is_empty() {
|
||||
return None;
|
||||
}
|
||||
// Now we know the buffer is empty and there's more input. Make sure we
|
||||
// buffer the final block, because update() doesn't finalize.
|
||||
let mut last_block_start = input.len() - 1;
|
||||
last_block_start -= last_block_start % BLOCKBYTES;
|
||||
let (blocks, last_block) = input.split_at(last_block_start);
|
||||
state.buf[..last_block.len()].copy_from_slice(last_block);
|
||||
state.buflen = last_block.len() as u8;
|
||||
// Finally, if the full blocks slice is non-empty, prepare that job for
|
||||
// compression, and bump the State count.
|
||||
if blocks.is_empty() {
|
||||
None
|
||||
} else {
|
||||
let count = state.count;
|
||||
state.count = state.count.wrapping_add(blocks.len() as Count);
|
||||
Some(Job {
|
||||
input: blocks,
|
||||
words: &mut state.words,
|
||||
count,
|
||||
last_node: state.last_node,
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
// Run all the Jobs in the iterator.
|
||||
compress_many(jobs, implementation, Finalize::No, Stride::Serial);
|
||||
}
|
||||
|
||||
/// A job for the [`hash_many`] function. After calling [`hash_many`] on a
|
||||
/// collection of `HashManyJob` objects, you can call [`to_hash`] on each job
|
||||
/// to get the result.
|
||||
///
|
||||
/// [`hash_many`]: fn.hash_many.html
|
||||
/// [`to_hash`]: struct.HashManyJob.html#method.to_hash
|
||||
#[derive(Clone)]
|
||||
pub struct HashManyJob<'a> {
|
||||
words: [Word; 8],
|
||||
count: Count,
|
||||
last_node: LastNode,
|
||||
hash_length: u8,
|
||||
input: &'a [u8],
|
||||
finished: bool,
|
||||
implementation: guts::Implementation,
|
||||
}
|
||||
|
||||
impl<'a> HashManyJob<'a> {
|
||||
/// Construct a new `HashManyJob` from a set of hashing parameters and an
|
||||
/// input.
|
||||
#[inline]
|
||||
pub fn new(params: &Params, input: &'a [u8]) -> Self {
|
||||
let mut words = params.to_words();
|
||||
let mut count = 0;
|
||||
let mut finished = false;
|
||||
// If we have key bytes, compress them into the state words. If there's
|
||||
// no additional input, this compression needs to finalize and set
|
||||
// finished=true.
|
||||
if params.key_length > 0 {
|
||||
let mut finalization = Finalize::No;
|
||||
if input.is_empty() {
|
||||
finalization = Finalize::Yes;
|
||||
finished = true;
|
||||
}
|
||||
params.implementation.compress1_loop(
|
||||
¶ms.key_block,
|
||||
&mut words,
|
||||
0,
|
||||
params.last_node,
|
||||
finalization,
|
||||
Stride::Serial,
|
||||
);
|
||||
count = BLOCKBYTES as Count;
|
||||
}
|
||||
Self {
|
||||
words,
|
||||
count,
|
||||
last_node: params.last_node,
|
||||
hash_length: params.hash_length,
|
||||
input,
|
||||
finished,
|
||||
implementation: params.implementation,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the hash from a finished job. If you call this before calling
|
||||
/// [`hash_many`], it will panic in debug mode.
|
||||
///
|
||||
/// [`hash_many`]: fn.hash_many.html
|
||||
#[inline]
|
||||
pub fn to_hash(&self) -> Hash {
|
||||
debug_assert!(self.finished, "job hasn't been run yet");
|
||||
Hash {
|
||||
bytes: state_words_to_bytes(&self.words),
|
||||
len: self.hash_length,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> fmt::Debug for HashManyJob<'a> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
// NB: Don't print the words. Leaking them would allow length extension.
|
||||
write!(
|
||||
f,
|
||||
"HashManyJob {{ count: {}, hash_length: {}, last_node: {}, input_len: {} }}",
|
||||
self.count,
|
||||
self.hash_length,
|
||||
self.last_node.yes(),
|
||||
self.input.len(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Hash any number of complete inputs all at once.
|
||||
///
|
||||
/// This is slightly more efficient than using `update_many` with `State`
|
||||
/// objects, because it doesn't need to do any buffering.
|
||||
///
|
||||
/// Running `hash_many` on the same `HashManyJob` object more than once has no
|
||||
/// effect.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use blake2b_simd::{blake2b, Params, many::{HashManyJob, hash_many}};
|
||||
///
|
||||
/// let inputs = [
|
||||
/// &b"foo"[..],
|
||||
/// &b"bar"[..],
|
||||
/// &b"baz"[..],
|
||||
/// &b"bing"[..],
|
||||
/// ];
|
||||
///
|
||||
/// let mut params = Params::new();
|
||||
/// params.hash_length(16);
|
||||
///
|
||||
/// let mut jobs = [
|
||||
/// HashManyJob::new(¶ms, inputs[0]),
|
||||
/// HashManyJob::new(¶ms, inputs[1]),
|
||||
/// HashManyJob::new(¶ms, inputs[2]),
|
||||
/// HashManyJob::new(¶ms, inputs[3]),
|
||||
/// ];
|
||||
///
|
||||
/// hash_many(jobs.iter_mut());
|
||||
///
|
||||
/// for (input, job) in inputs.iter().zip(jobs.iter()) {
|
||||
/// let expected = params.hash(input);
|
||||
/// assert_eq!(expected, job.to_hash());
|
||||
/// }
|
||||
/// ```
|
||||
pub fn hash_many<'a, 'b, I>(hash_many_jobs: I)
|
||||
where
|
||||
'b: 'a,
|
||||
I: IntoIterator<Item = &'a mut HashManyJob<'b>>,
|
||||
{
|
||||
// Get the guts::Implementation from the first job, if any.
|
||||
let mut peekable_jobs = hash_many_jobs.into_iter().peekable();
|
||||
let implementation = if let Some(job) = peekable_jobs.peek() {
|
||||
job.implementation
|
||||
} else {
|
||||
// No work items, just short circuit.
|
||||
return;
|
||||
};
|
||||
|
||||
// In the jobs iterator, skip HashManyJobs that have already been run. This
|
||||
// is less because we actually expect callers to call hash_many twice
|
||||
// (though they're allowed to if they want), and more because
|
||||
// HashManyJob::new might need to finalize if there are key bytes but no
|
||||
// input. Tying the job lifetime to the Params reference is an alternative,
|
||||
// but I've found it too constraining in practice. We could also put key
|
||||
// bytes in every HashManyJob, but that would add unnecessary storage and
|
||||
// zeroing for all callers.
|
||||
let unfinished_jobs = peekable_jobs.into_iter().filter(|j| !j.finished);
|
||||
let jobs = unfinished_jobs.map(|j| {
|
||||
j.finished = true;
|
||||
Job {
|
||||
input: j.input,
|
||||
words: &mut j.words,
|
||||
count: j.count,
|
||||
last_node: j.last_node,
|
||||
}
|
||||
});
|
||||
compress_many(jobs, implementation, Finalize::Yes, Stride::Serial);
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::guts;
|
||||
use crate::paint_test_input;
|
||||
use crate::BLOCKBYTES;
|
||||
use arrayvec::ArrayVec;
|
||||
|
||||
#[test]
|
||||
fn test_degree() {
|
||||
assert!(degree() <= MAX_DEGREE);
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
#[cfg(feature = "std")]
|
||||
{
|
||||
if is_x86_feature_detected!("avx2") {
|
||||
assert!(degree() >= 4);
|
||||
}
|
||||
if is_x86_feature_detected!("sse4.1") {
|
||||
assert!(degree() >= 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_hash_many() {
|
||||
// Use a length of inputs that will exercise all of the power-of-two loops.
|
||||
const LEN: usize = 2 * guts::MAX_DEGREE - 1;
|
||||
|
||||
// Rerun LEN inputs LEN different times, with the empty input starting in a
|
||||
// different spot each time.
|
||||
let mut input = [0; LEN * BLOCKBYTES];
|
||||
paint_test_input(&mut input);
|
||||
for start_offset in 0..LEN {
|
||||
let mut inputs: [&[u8]; LEN] = [&[]; LEN];
|
||||
for i in 0..LEN {
|
||||
let chunks = (i + start_offset) % LEN;
|
||||
inputs[i] = &input[..chunks * BLOCKBYTES];
|
||||
}
|
||||
|
||||
let mut params: ArrayVec<[Params; LEN]> = ArrayVec::new();
|
||||
for i in 0..LEN {
|
||||
let mut p = Params::new();
|
||||
p.node_offset(i as u64);
|
||||
if i % 2 == 1 {
|
||||
p.last_node(true);
|
||||
p.key(b"foo");
|
||||
}
|
||||
params.push(p);
|
||||
}
|
||||
|
||||
let mut jobs: ArrayVec<[HashManyJob; LEN]> = ArrayVec::new();
|
||||
for i in 0..LEN {
|
||||
jobs.push(HashManyJob::new(¶ms[i], inputs[i]));
|
||||
}
|
||||
|
||||
hash_many(&mut jobs);
|
||||
|
||||
// Check the outputs.
|
||||
for i in 0..LEN {
|
||||
let expected = params[i].hash(inputs[i]);
|
||||
assert_eq!(expected, jobs[i].to_hash());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_update_many() {
|
||||
// Use a length of inputs that will exercise all of the power-of-two loops.
|
||||
const LEN: usize = 2 * guts::MAX_DEGREE - 1;
|
||||
|
||||
// Rerun LEN inputs LEN different times, with the empty input starting in a
|
||||
// different spot each time.
|
||||
let mut input = [0; LEN * BLOCKBYTES];
|
||||
paint_test_input(&mut input);
|
||||
for start_offset in 0..LEN {
|
||||
let mut inputs: [&[u8]; LEN] = [&[]; LEN];
|
||||
for i in 0..LEN {
|
||||
let chunks = (i + start_offset) % LEN;
|
||||
inputs[i] = &input[..chunks * BLOCKBYTES];
|
||||
}
|
||||
|
||||
let mut params: ArrayVec<[Params; LEN]> = ArrayVec::new();
|
||||
for i in 0..LEN {
|
||||
let mut p = Params::new();
|
||||
p.node_offset(i as u64);
|
||||
if i % 2 == 1 {
|
||||
p.last_node(true);
|
||||
p.key(b"foo");
|
||||
}
|
||||
params.push(p);
|
||||
}
|
||||
|
||||
let mut states: ArrayVec<[State; LEN]> = ArrayVec::new();
|
||||
for i in 0..LEN {
|
||||
states.push(params[i].to_state());
|
||||
}
|
||||
|
||||
// Run each input twice through, to exercise buffering.
|
||||
update_many(states.iter_mut().zip(inputs.iter()));
|
||||
update_many(states.iter_mut().zip(inputs.iter()));
|
||||
|
||||
// Check the outputs.
|
||||
for i in 0..LEN {
|
||||
let mut reference_state = params[i].to_state();
|
||||
// Again, run the input twice.
|
||||
reference_state.update(inputs[i]);
|
||||
reference_state.update(inputs[i]);
|
||||
assert_eq!(reference_state.finalize(), states[i].finalize());
|
||||
assert_eq!(2 * inputs[i].len() as Count, states[i].count());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
168
third_party/rust/blake2b_simd/src/portable.rs
vendored
168
third_party/rust/blake2b_simd/src/portable.rs
vendored
@ -1,168 +0,0 @@
|
||||
use arrayref::{array_ref, array_refs};
|
||||
|
||||
use super::*;
|
||||
use crate::guts::{
|
||||
count_high, count_low, final_block, flag_word, input_debug_asserts, Finalize, LastNode, Stride,
|
||||
};
|
||||
|
||||
// G is the mixing function, called eight times per round in the compression
|
||||
// function. V is the 16-word state vector of the compression function, usually
|
||||
// described as a 4x4 matrix. A, B, C, and D are the mixing indices, set by the
|
||||
// caller first to the four columns of V, and then to its four diagonals. X and
|
||||
// Y are words of input, chosen by the caller according to the message
|
||||
// schedule, SIGMA.
|
||||
#[inline(always)]
|
||||
fn g(v: &mut [Word; 16], a: usize, b: usize, c: usize, d: usize, x: Word, y: Word) {
|
||||
v[a] = v[a].wrapping_add(v[b]).wrapping_add(x);
|
||||
v[d] = (v[d] ^ v[a]).rotate_right(32);
|
||||
v[c] = v[c].wrapping_add(v[d]);
|
||||
v[b] = (v[b] ^ v[c]).rotate_right(24);
|
||||
v[a] = v[a].wrapping_add(v[b]).wrapping_add(y);
|
||||
v[d] = (v[d] ^ v[a]).rotate_right(16);
|
||||
v[c] = v[c].wrapping_add(v[d]);
|
||||
v[b] = (v[b] ^ v[c]).rotate_right(63);
|
||||
}
|
||||
|
||||
// This is too much inlining for some small chips like ARM Cortex-M0, so the
|
||||
// uninline_portable feature is provided to disable it.
|
||||
#[cfg_attr(not(feature = "uninline_portable"), inline(always))]
|
||||
fn round(r: usize, m: &[Word; 16], v: &mut [Word; 16]) {
|
||||
// Select the message schedule based on the round.
|
||||
let s = SIGMA[r];
|
||||
|
||||
// Mix the columns.
|
||||
g(v, 0, 4, 8, 12, m[s[0] as usize], m[s[1] as usize]);
|
||||
g(v, 1, 5, 9, 13, m[s[2] as usize], m[s[3] as usize]);
|
||||
g(v, 2, 6, 10, 14, m[s[4] as usize], m[s[5] as usize]);
|
||||
g(v, 3, 7, 11, 15, m[s[6] as usize], m[s[7] as usize]);
|
||||
|
||||
// Mix the rows.
|
||||
g(v, 0, 5, 10, 15, m[s[8] as usize], m[s[9] as usize]);
|
||||
g(v, 1, 6, 11, 12, m[s[10] as usize], m[s[11] as usize]);
|
||||
g(v, 2, 7, 8, 13, m[s[12] as usize], m[s[13] as usize]);
|
||||
g(v, 3, 4, 9, 14, m[s[14] as usize], m[s[15] as usize]);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn compress_block(
|
||||
block: &[u8; BLOCKBYTES],
|
||||
words: &mut [Word; 8],
|
||||
count: Count,
|
||||
last_block: Word,
|
||||
last_node: Word,
|
||||
) {
|
||||
// Initialize the compression state.
|
||||
let mut v = [
|
||||
words[0],
|
||||
words[1],
|
||||
words[2],
|
||||
words[3],
|
||||
words[4],
|
||||
words[5],
|
||||
words[6],
|
||||
words[7],
|
||||
IV[0],
|
||||
IV[1],
|
||||
IV[2],
|
||||
IV[3],
|
||||
IV[4] ^ count_low(count),
|
||||
IV[5] ^ count_high(count),
|
||||
IV[6] ^ last_block,
|
||||
IV[7] ^ last_node,
|
||||
];
|
||||
|
||||
// Parse the message bytes as ints in little endian order.
|
||||
const W: usize = size_of::<Word>();
|
||||
let msg_refs = array_refs!(block, W, W, W, W, W, W, W, W, W, W, W, W, W, W, W, W);
|
||||
let m = [
|
||||
Word::from_le_bytes(*msg_refs.0),
|
||||
Word::from_le_bytes(*msg_refs.1),
|
||||
Word::from_le_bytes(*msg_refs.2),
|
||||
Word::from_le_bytes(*msg_refs.3),
|
||||
Word::from_le_bytes(*msg_refs.4),
|
||||
Word::from_le_bytes(*msg_refs.5),
|
||||
Word::from_le_bytes(*msg_refs.6),
|
||||
Word::from_le_bytes(*msg_refs.7),
|
||||
Word::from_le_bytes(*msg_refs.8),
|
||||
Word::from_le_bytes(*msg_refs.9),
|
||||
Word::from_le_bytes(*msg_refs.10),
|
||||
Word::from_le_bytes(*msg_refs.11),
|
||||
Word::from_le_bytes(*msg_refs.12),
|
||||
Word::from_le_bytes(*msg_refs.13),
|
||||
Word::from_le_bytes(*msg_refs.14),
|
||||
Word::from_le_bytes(*msg_refs.15),
|
||||
];
|
||||
|
||||
round(0, &m, &mut v);
|
||||
round(1, &m, &mut v);
|
||||
round(2, &m, &mut v);
|
||||
round(3, &m, &mut v);
|
||||
round(4, &m, &mut v);
|
||||
round(5, &m, &mut v);
|
||||
round(6, &m, &mut v);
|
||||
round(7, &m, &mut v);
|
||||
round(8, &m, &mut v);
|
||||
round(9, &m, &mut v);
|
||||
round(10, &m, &mut v);
|
||||
round(11, &m, &mut v);
|
||||
|
||||
words[0] ^= v[0] ^ v[8];
|
||||
words[1] ^= v[1] ^ v[9];
|
||||
words[2] ^= v[2] ^ v[10];
|
||||
words[3] ^= v[3] ^ v[11];
|
||||
words[4] ^= v[4] ^ v[12];
|
||||
words[5] ^= v[5] ^ v[13];
|
||||
words[6] ^= v[6] ^ v[14];
|
||||
words[7] ^= v[7] ^ v[15];
|
||||
}
|
||||
|
||||
pub fn compress1_loop(
|
||||
input: &[u8],
|
||||
words: &mut [Word; 8],
|
||||
mut count: Count,
|
||||
last_node: LastNode,
|
||||
finalize: Finalize,
|
||||
stride: Stride,
|
||||
) {
|
||||
input_debug_asserts(input, finalize);
|
||||
|
||||
let mut local_words = *words;
|
||||
|
||||
let mut fin_offset = input.len().saturating_sub(1);
|
||||
fin_offset -= fin_offset % stride.padded_blockbytes();
|
||||
let mut buf = [0; BLOCKBYTES];
|
||||
let (fin_block, fin_len, _) = final_block(input, fin_offset, &mut buf, stride);
|
||||
let fin_last_block = flag_word(finalize.yes());
|
||||
let fin_last_node = flag_word(finalize.yes() && last_node.yes());
|
||||
|
||||
let mut offset = 0;
|
||||
loop {
|
||||
let block;
|
||||
let count_delta;
|
||||
let last_block;
|
||||
let last_node;
|
||||
if offset == fin_offset {
|
||||
block = fin_block;
|
||||
count_delta = fin_len;
|
||||
last_block = fin_last_block;
|
||||
last_node = fin_last_node;
|
||||
} else {
|
||||
block = array_ref!(input, offset, BLOCKBYTES);
|
||||
count_delta = BLOCKBYTES;
|
||||
last_block = flag_word(false);
|
||||
last_node = flag_word(false);
|
||||
};
|
||||
|
||||
count = count.wrapping_add(count_delta as Count);
|
||||
compress_block(block, &mut local_words, count, last_block, last_node);
|
||||
|
||||
// Check for termination before bumping the offset, to avoid overflow.
|
||||
if offset == fin_offset {
|
||||
break;
|
||||
}
|
||||
|
||||
offset += stride.padded_blockbytes();
|
||||
}
|
||||
|
||||
*words = local_words;
|
||||
}
|
461
third_party/rust/blake2b_simd/src/sse41.rs
vendored
461
third_party/rust/blake2b_simd/src/sse41.rs
vendored
@ -1,461 +0,0 @@
|
||||
#[cfg(target_arch = "x86")]
|
||||
use core::arch::x86::*;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use core::arch::x86_64::*;
|
||||
|
||||
use crate::guts::{
|
||||
assemble_count, count_high, count_low, final_block, flag_word, input_debug_asserts, Finalize,
|
||||
Job, Stride,
|
||||
};
|
||||
use crate::{Word, BLOCKBYTES, IV, SIGMA};
|
||||
use arrayref::{array_refs, mut_array_refs};
|
||||
use core::cmp;
|
||||
use core::mem;
|
||||
|
||||
pub const DEGREE: usize = 2;
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn loadu(src: *const [Word; DEGREE]) -> __m128i {
|
||||
// This is an unaligned load, so the pointer cast is allowed.
|
||||
_mm_loadu_si128(src as *const __m128i)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn storeu(src: __m128i, dest: *mut [Word; DEGREE]) {
|
||||
// This is an unaligned store, so the pointer cast is allowed.
|
||||
_mm_storeu_si128(dest as *mut __m128i, src)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn add(a: __m128i, b: __m128i) -> __m128i {
|
||||
_mm_add_epi64(a, b)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn eq(a: __m128i, b: __m128i) -> __m128i {
|
||||
_mm_cmpeq_epi64(a, b)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn and(a: __m128i, b: __m128i) -> __m128i {
|
||||
_mm_and_si128(a, b)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn negate_and(a: __m128i, b: __m128i) -> __m128i {
|
||||
// Note that "and not" implies the reverse of the actual arg order.
|
||||
_mm_andnot_si128(a, b)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn xor(a: __m128i, b: __m128i) -> __m128i {
|
||||
_mm_xor_si128(a, b)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn set1(x: u64) -> __m128i {
|
||||
_mm_set1_epi64x(x as i64)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn set2(a: u64, b: u64) -> __m128i {
|
||||
// There's no _mm_setr_epi64x, so note the arg order is backwards.
|
||||
_mm_set_epi64x(b as i64, a as i64)
|
||||
}
|
||||
|
||||
// Adapted from https://github.com/rust-lang-nursery/stdsimd/pull/479.
|
||||
macro_rules! _MM_SHUFFLE {
|
||||
($z:expr, $y:expr, $x:expr, $w:expr) => {
|
||||
($z << 6) | ($y << 4) | ($x << 2) | $w
|
||||
};
|
||||
}
|
||||
|
||||
// These rotations are the "simple version". For the "complicated version", see
|
||||
// https://github.com/sneves/blake2-avx2/blob/b3723921f668df09ece52dcd225a36d4a4eea1d9/blake2b-common.h#L43-L46.
|
||||
// For a discussion of the tradeoffs, see
|
||||
// https://github.com/sneves/blake2-avx2/pull/5. In short:
|
||||
// - Due to an LLVM bug (https://bugs.llvm.org/show_bug.cgi?id=44379), this
|
||||
// version performs better on recent x86 chips.
|
||||
// - LLVM is able to optimize this version to AVX-512 rotation instructions
|
||||
// when those are enabled.
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn rot32(x: __m128i) -> __m128i {
|
||||
_mm_or_si128(_mm_srli_epi64(x, 32), _mm_slli_epi64(x, 64 - 32))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn rot24(x: __m128i) -> __m128i {
|
||||
_mm_or_si128(_mm_srli_epi64(x, 24), _mm_slli_epi64(x, 64 - 24))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn rot16(x: __m128i) -> __m128i {
|
||||
_mm_or_si128(_mm_srli_epi64(x, 16), _mm_slli_epi64(x, 64 - 16))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn rot63(x: __m128i) -> __m128i {
|
||||
_mm_or_si128(_mm_srli_epi64(x, 63), _mm_slli_epi64(x, 64 - 63))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn round(v: &mut [__m128i; 16], m: &[__m128i; 16], r: usize) {
|
||||
v[0] = add(v[0], m[SIGMA[r][0] as usize]);
|
||||
v[1] = add(v[1], m[SIGMA[r][2] as usize]);
|
||||
v[2] = add(v[2], m[SIGMA[r][4] as usize]);
|
||||
v[3] = add(v[3], m[SIGMA[r][6] as usize]);
|
||||
v[0] = add(v[0], v[4]);
|
||||
v[1] = add(v[1], v[5]);
|
||||
v[2] = add(v[2], v[6]);
|
||||
v[3] = add(v[3], v[7]);
|
||||
v[12] = xor(v[12], v[0]);
|
||||
v[13] = xor(v[13], v[1]);
|
||||
v[14] = xor(v[14], v[2]);
|
||||
v[15] = xor(v[15], v[3]);
|
||||
v[12] = rot32(v[12]);
|
||||
v[13] = rot32(v[13]);
|
||||
v[14] = rot32(v[14]);
|
||||
v[15] = rot32(v[15]);
|
||||
v[8] = add(v[8], v[12]);
|
||||
v[9] = add(v[9], v[13]);
|
||||
v[10] = add(v[10], v[14]);
|
||||
v[11] = add(v[11], v[15]);
|
||||
v[4] = xor(v[4], v[8]);
|
||||
v[5] = xor(v[5], v[9]);
|
||||
v[6] = xor(v[6], v[10]);
|
||||
v[7] = xor(v[7], v[11]);
|
||||
v[4] = rot24(v[4]);
|
||||
v[5] = rot24(v[5]);
|
||||
v[6] = rot24(v[6]);
|
||||
v[7] = rot24(v[7]);
|
||||
v[0] = add(v[0], m[SIGMA[r][1] as usize]);
|
||||
v[1] = add(v[1], m[SIGMA[r][3] as usize]);
|
||||
v[2] = add(v[2], m[SIGMA[r][5] as usize]);
|
||||
v[3] = add(v[3], m[SIGMA[r][7] as usize]);
|
||||
v[0] = add(v[0], v[4]);
|
||||
v[1] = add(v[1], v[5]);
|
||||
v[2] = add(v[2], v[6]);
|
||||
v[3] = add(v[3], v[7]);
|
||||
v[12] = xor(v[12], v[0]);
|
||||
v[13] = xor(v[13], v[1]);
|
||||
v[14] = xor(v[14], v[2]);
|
||||
v[15] = xor(v[15], v[3]);
|
||||
v[12] = rot16(v[12]);
|
||||
v[13] = rot16(v[13]);
|
||||
v[14] = rot16(v[14]);
|
||||
v[15] = rot16(v[15]);
|
||||
v[8] = add(v[8], v[12]);
|
||||
v[9] = add(v[9], v[13]);
|
||||
v[10] = add(v[10], v[14]);
|
||||
v[11] = add(v[11], v[15]);
|
||||
v[4] = xor(v[4], v[8]);
|
||||
v[5] = xor(v[5], v[9]);
|
||||
v[6] = xor(v[6], v[10]);
|
||||
v[7] = xor(v[7], v[11]);
|
||||
v[4] = rot63(v[4]);
|
||||
v[5] = rot63(v[5]);
|
||||
v[6] = rot63(v[6]);
|
||||
v[7] = rot63(v[7]);
|
||||
|
||||
v[0] = add(v[0], m[SIGMA[r][8] as usize]);
|
||||
v[1] = add(v[1], m[SIGMA[r][10] as usize]);
|
||||
v[2] = add(v[2], m[SIGMA[r][12] as usize]);
|
||||
v[3] = add(v[3], m[SIGMA[r][14] as usize]);
|
||||
v[0] = add(v[0], v[5]);
|
||||
v[1] = add(v[1], v[6]);
|
||||
v[2] = add(v[2], v[7]);
|
||||
v[3] = add(v[3], v[4]);
|
||||
v[15] = xor(v[15], v[0]);
|
||||
v[12] = xor(v[12], v[1]);
|
||||
v[13] = xor(v[13], v[2]);
|
||||
v[14] = xor(v[14], v[3]);
|
||||
v[15] = rot32(v[15]);
|
||||
v[12] = rot32(v[12]);
|
||||
v[13] = rot32(v[13]);
|
||||
v[14] = rot32(v[14]);
|
||||
v[10] = add(v[10], v[15]);
|
||||
v[11] = add(v[11], v[12]);
|
||||
v[8] = add(v[8], v[13]);
|
||||
v[9] = add(v[9], v[14]);
|
||||
v[5] = xor(v[5], v[10]);
|
||||
v[6] = xor(v[6], v[11]);
|
||||
v[7] = xor(v[7], v[8]);
|
||||
v[4] = xor(v[4], v[9]);
|
||||
v[5] = rot24(v[5]);
|
||||
v[6] = rot24(v[6]);
|
||||
v[7] = rot24(v[7]);
|
||||
v[4] = rot24(v[4]);
|
||||
v[0] = add(v[0], m[SIGMA[r][9] as usize]);
|
||||
v[1] = add(v[1], m[SIGMA[r][11] as usize]);
|
||||
v[2] = add(v[2], m[SIGMA[r][13] as usize]);
|
||||
v[3] = add(v[3], m[SIGMA[r][15] as usize]);
|
||||
v[0] = add(v[0], v[5]);
|
||||
v[1] = add(v[1], v[6]);
|
||||
v[2] = add(v[2], v[7]);
|
||||
v[3] = add(v[3], v[4]);
|
||||
v[15] = xor(v[15], v[0]);
|
||||
v[12] = xor(v[12], v[1]);
|
||||
v[13] = xor(v[13], v[2]);
|
||||
v[14] = xor(v[14], v[3]);
|
||||
v[15] = rot16(v[15]);
|
||||
v[12] = rot16(v[12]);
|
||||
v[13] = rot16(v[13]);
|
||||
v[14] = rot16(v[14]);
|
||||
v[10] = add(v[10], v[15]);
|
||||
v[11] = add(v[11], v[12]);
|
||||
v[8] = add(v[8], v[13]);
|
||||
v[9] = add(v[9], v[14]);
|
||||
v[5] = xor(v[5], v[10]);
|
||||
v[6] = xor(v[6], v[11]);
|
||||
v[7] = xor(v[7], v[8]);
|
||||
v[4] = xor(v[4], v[9]);
|
||||
v[5] = rot63(v[5]);
|
||||
v[6] = rot63(v[6]);
|
||||
v[7] = rot63(v[7]);
|
||||
v[4] = rot63(v[4]);
|
||||
}
|
||||
|
||||
// We'd rather make this a regular function with #[inline(always)], but for
|
||||
// some reason that blows up compile times by about 10 seconds, at least in
|
||||
// some cases (BLAKE2b avx2.rs). This macro seems to get the same performance
|
||||
// result, without the compile time issue.
|
||||
macro_rules! compress2_transposed {
|
||||
(
|
||||
$h_vecs:expr,
|
||||
$msg_vecs:expr,
|
||||
$count_low:expr,
|
||||
$count_high:expr,
|
||||
$lastblock:expr,
|
||||
$lastnode:expr,
|
||||
) => {
|
||||
let h_vecs: &mut [__m128i; 8] = $h_vecs;
|
||||
let msg_vecs: &[__m128i; 16] = $msg_vecs;
|
||||
let count_low: __m128i = $count_low;
|
||||
let count_high: __m128i = $count_high;
|
||||
let lastblock: __m128i = $lastblock;
|
||||
let lastnode: __m128i = $lastnode;
|
||||
let mut v = [
|
||||
h_vecs[0],
|
||||
h_vecs[1],
|
||||
h_vecs[2],
|
||||
h_vecs[3],
|
||||
h_vecs[4],
|
||||
h_vecs[5],
|
||||
h_vecs[6],
|
||||
h_vecs[7],
|
||||
set1(IV[0]),
|
||||
set1(IV[1]),
|
||||
set1(IV[2]),
|
||||
set1(IV[3]),
|
||||
xor(set1(IV[4]), count_low),
|
||||
xor(set1(IV[5]), count_high),
|
||||
xor(set1(IV[6]), lastblock),
|
||||
xor(set1(IV[7]), lastnode),
|
||||
];
|
||||
|
||||
round(&mut v, &msg_vecs, 0);
|
||||
round(&mut v, &msg_vecs, 1);
|
||||
round(&mut v, &msg_vecs, 2);
|
||||
round(&mut v, &msg_vecs, 3);
|
||||
round(&mut v, &msg_vecs, 4);
|
||||
round(&mut v, &msg_vecs, 5);
|
||||
round(&mut v, &msg_vecs, 6);
|
||||
round(&mut v, &msg_vecs, 7);
|
||||
round(&mut v, &msg_vecs, 8);
|
||||
round(&mut v, &msg_vecs, 9);
|
||||
round(&mut v, &msg_vecs, 10);
|
||||
round(&mut v, &msg_vecs, 11);
|
||||
|
||||
h_vecs[0] = xor(xor(h_vecs[0], v[0]), v[8]);
|
||||
h_vecs[1] = xor(xor(h_vecs[1], v[1]), v[9]);
|
||||
h_vecs[2] = xor(xor(h_vecs[2], v[2]), v[10]);
|
||||
h_vecs[3] = xor(xor(h_vecs[3], v[3]), v[11]);
|
||||
h_vecs[4] = xor(xor(h_vecs[4], v[4]), v[12]);
|
||||
h_vecs[5] = xor(xor(h_vecs[5], v[5]), v[13]);
|
||||
h_vecs[6] = xor(xor(h_vecs[6], v[6]), v[14]);
|
||||
h_vecs[7] = xor(xor(h_vecs[7], v[7]), v[15]);
|
||||
};
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn transpose_vecs(a: __m128i, b: __m128i) -> [__m128i; DEGREE] {
|
||||
let a_words: [Word; DEGREE] = mem::transmute(a);
|
||||
let b_words: [Word; DEGREE] = mem::transmute(b);
|
||||
[set2(a_words[0], b_words[0]), set2(a_words[1], b_words[1])]
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn transpose_state_vecs(jobs: &[Job; DEGREE]) -> [__m128i; 8] {
|
||||
// Load all the state words into transposed vectors, where the first vector
|
||||
// has the first word of each state, etc. Transposing once at the beginning
|
||||
// and once at the end is more efficient that repeating it for each block.
|
||||
let words0 = array_refs!(&jobs[0].words, DEGREE, DEGREE, DEGREE, DEGREE);
|
||||
let words1 = array_refs!(&jobs[1].words, DEGREE, DEGREE, DEGREE, DEGREE);
|
||||
let [h0, h1] = transpose_vecs(loadu(words0.0), loadu(words1.0));
|
||||
let [h2, h3] = transpose_vecs(loadu(words0.1), loadu(words1.1));
|
||||
let [h4, h5] = transpose_vecs(loadu(words0.2), loadu(words1.2));
|
||||
let [h6, h7] = transpose_vecs(loadu(words0.3), loadu(words1.3));
|
||||
[h0, h1, h2, h3, h4, h5, h6, h7]
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn untranspose_state_vecs(h_vecs: &[__m128i; 8], jobs: &mut [Job; DEGREE]) {
|
||||
// Un-transpose the updated state vectors back into the caller's arrays.
|
||||
let [job0, job1] = jobs;
|
||||
let words0 = mut_array_refs!(&mut job0.words, DEGREE, DEGREE, DEGREE, DEGREE);
|
||||
let words1 = mut_array_refs!(&mut job1.words, DEGREE, DEGREE, DEGREE, DEGREE);
|
||||
|
||||
let out = transpose_vecs(h_vecs[0], h_vecs[1]);
|
||||
storeu(out[0], words0.0);
|
||||
storeu(out[1], words1.0);
|
||||
let out = transpose_vecs(h_vecs[2], h_vecs[3]);
|
||||
storeu(out[0], words0.1);
|
||||
storeu(out[1], words1.1);
|
||||
let out = transpose_vecs(h_vecs[4], h_vecs[5]);
|
||||
storeu(out[0], words0.2);
|
||||
storeu(out[1], words1.2);
|
||||
let out = transpose_vecs(h_vecs[6], h_vecs[7]);
|
||||
storeu(out[0], words0.3);
|
||||
storeu(out[1], words1.3);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn transpose_msg_vecs(blocks: [*const [u8; BLOCKBYTES]; DEGREE]) -> [__m128i; 16] {
|
||||
// These input arrays have no particular alignment, so we use unaligned
|
||||
// loads to read from them.
|
||||
let block0 = blocks[0] as *const [Word; DEGREE];
|
||||
let block1 = blocks[1] as *const [Word; DEGREE];
|
||||
let [m0, m1] = transpose_vecs(loadu(block0.add(0)), loadu(block1.add(0)));
|
||||
let [m2, m3] = transpose_vecs(loadu(block0.add(1)), loadu(block1.add(1)));
|
||||
let [m4, m5] = transpose_vecs(loadu(block0.add(2)), loadu(block1.add(2)));
|
||||
let [m6, m7] = transpose_vecs(loadu(block0.add(3)), loadu(block1.add(3)));
|
||||
let [m8, m9] = transpose_vecs(loadu(block0.add(4)), loadu(block1.add(4)));
|
||||
let [m10, m11] = transpose_vecs(loadu(block0.add(5)), loadu(block1.add(5)));
|
||||
let [m12, m13] = transpose_vecs(loadu(block0.add(6)), loadu(block1.add(6)));
|
||||
let [m14, m15] = transpose_vecs(loadu(block0.add(7)), loadu(block1.add(7)));
|
||||
[
|
||||
m0, m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11, m12, m13, m14, m15,
|
||||
]
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn load_counts(jobs: &[Job; DEGREE]) -> (__m128i, __m128i) {
|
||||
(
|
||||
set2(count_low(jobs[0].count), count_low(jobs[1].count)),
|
||||
set2(count_high(jobs[0].count), count_high(jobs[1].count)),
|
||||
)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn store_counts(jobs: &mut [Job; DEGREE], low: __m128i, high: __m128i) {
|
||||
let low_ints: [Word; DEGREE] = mem::transmute(low);
|
||||
let high_ints: [Word; DEGREE] = mem::transmute(high);
|
||||
for i in 0..DEGREE {
|
||||
jobs[i].count = assemble_count(low_ints[i], high_ints[i]);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn add_to_counts(lo: &mut __m128i, hi: &mut __m128i, delta: __m128i) {
|
||||
// If the low counts reach zero, that means they wrapped, unless the delta
|
||||
// was also zero.
|
||||
*lo = add(*lo, delta);
|
||||
let lo_reached_zero = eq(*lo, set1(0));
|
||||
let delta_was_zero = eq(delta, set1(0));
|
||||
let hi_inc = and(set1(1), negate_and(delta_was_zero, lo_reached_zero));
|
||||
*hi = add(*hi, hi_inc);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn flags_vec(flags: [bool; DEGREE]) -> __m128i {
|
||||
set2(flag_word(flags[0]), flag_word(flags[1]))
|
||||
}
|
||||
|
||||
#[target_feature(enable = "sse4.1")]
|
||||
pub unsafe fn compress2_loop(jobs: &mut [Job; DEGREE], finalize: Finalize, stride: Stride) {
|
||||
// If we're not finalizing, there can't be a partial block at the end.
|
||||
for job in jobs.iter() {
|
||||
input_debug_asserts(job.input, finalize);
|
||||
}
|
||||
|
||||
let msg_ptrs = [jobs[0].input.as_ptr(), jobs[1].input.as_ptr()];
|
||||
let mut h_vecs = transpose_state_vecs(&jobs);
|
||||
let (mut counts_lo, mut counts_hi) = load_counts(&jobs);
|
||||
|
||||
// Prepare the final blocks (note, which could be empty if the input is
|
||||
// empty). Do all this before entering the main loop.
|
||||
let min_len = jobs.iter().map(|job| job.input.len()).min().unwrap();
|
||||
let mut fin_offset = min_len.saturating_sub(1);
|
||||
fin_offset -= fin_offset % stride.padded_blockbytes();
|
||||
// Performance note, making these buffers mem::uninitialized() seems to
|
||||
// cause problems in the optimizer.
|
||||
let mut buf0: [u8; BLOCKBYTES] = [0; BLOCKBYTES];
|
||||
let mut buf1: [u8; BLOCKBYTES] = [0; BLOCKBYTES];
|
||||
let (block0, len0, finalize0) = final_block(jobs[0].input, fin_offset, &mut buf0, stride);
|
||||
let (block1, len1, finalize1) = final_block(jobs[1].input, fin_offset, &mut buf1, stride);
|
||||
let fin_blocks: [*const [u8; BLOCKBYTES]; DEGREE] = [block0, block1];
|
||||
let fin_counts_delta = set2(len0 as Word, len1 as Word);
|
||||
let fin_last_block;
|
||||
let fin_last_node;
|
||||
if finalize.yes() {
|
||||
fin_last_block = flags_vec([finalize0, finalize1]);
|
||||
fin_last_node = flags_vec([
|
||||
finalize0 && jobs[0].last_node.yes(),
|
||||
finalize1 && jobs[1].last_node.yes(),
|
||||
]);
|
||||
} else {
|
||||
fin_last_block = set1(0);
|
||||
fin_last_node = set1(0);
|
||||
}
|
||||
|
||||
// The main loop.
|
||||
let mut offset = 0;
|
||||
loop {
|
||||
let blocks;
|
||||
let counts_delta;
|
||||
let last_block;
|
||||
let last_node;
|
||||
if offset == fin_offset {
|
||||
blocks = fin_blocks;
|
||||
counts_delta = fin_counts_delta;
|
||||
last_block = fin_last_block;
|
||||
last_node = fin_last_node;
|
||||
} else {
|
||||
blocks = [
|
||||
msg_ptrs[0].add(offset) as *const [u8; BLOCKBYTES],
|
||||
msg_ptrs[1].add(offset) as *const [u8; BLOCKBYTES],
|
||||
];
|
||||
counts_delta = set1(BLOCKBYTES as Word);
|
||||
last_block = set1(0);
|
||||
last_node = set1(0);
|
||||
};
|
||||
|
||||
let m_vecs = transpose_msg_vecs(blocks);
|
||||
add_to_counts(&mut counts_lo, &mut counts_hi, counts_delta);
|
||||
compress2_transposed!(
|
||||
&mut h_vecs,
|
||||
&m_vecs,
|
||||
counts_lo,
|
||||
counts_hi,
|
||||
last_block,
|
||||
last_node,
|
||||
);
|
||||
|
||||
// Check for termination before bumping the offset, to avoid overflow.
|
||||
if offset == fin_offset {
|
||||
break;
|
||||
}
|
||||
|
||||
offset += stride.padded_blockbytes();
|
||||
}
|
||||
|
||||
// Write out the results.
|
||||
untranspose_state_vecs(&h_vecs, &mut *jobs);
|
||||
store_counts(&mut *jobs, counts_lo, counts_hi);
|
||||
let max_consumed = offset.saturating_add(stride.padded_blockbytes());
|
||||
for job in jobs.iter_mut() {
|
||||
let consumed = cmp::min(max_consumed, job.input.len());
|
||||
job.input = &job.input[consumed..];
|
||||
}
|
||||
}
|
201
third_party/rust/blake2b_simd/src/test.rs
vendored
201
third_party/rust/blake2b_simd/src/test.rs
vendored
@ -1,201 +0,0 @@
|
||||
use super::*;
|
||||
|
||||
const EMPTY_HASH: &str = "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419\
|
||||
d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce";
|
||||
const ABC_HASH: &str = "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d1\
|
||||
7d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923";
|
||||
const ONE_BLOCK_HASH: &str = "865939e120e6805438478841afb739ae4250cf372653078a065cdcfffca4caf7\
|
||||
98e6d462b65d658fc165782640eded70963449ae1500fb0f24981d7727e22c41";
|
||||
const THOUSAND_HASH: &str = "1ee4e51ecab5210a518f26150e882627ec839967f19d763e1508b12cfefed148\
|
||||
58f6a1c9d1f969bc224dc9440f5a6955277e755b9c513f9ba4421c5e50c8d787";
|
||||
|
||||
#[test]
|
||||
fn test_update_state() {
|
||||
let io = &[
|
||||
(&b""[..], EMPTY_HASH),
|
||||
(&b"abc"[..], ABC_HASH),
|
||||
(&[0; BLOCKBYTES], ONE_BLOCK_HASH),
|
||||
(&[0; 1000], THOUSAND_HASH),
|
||||
];
|
||||
// Test each input all at once.
|
||||
for &(input, output) in io {
|
||||
let hash = blake2b(input);
|
||||
assert_eq!(&hash.to_hex(), output, "hash mismatch");
|
||||
}
|
||||
// Now in two chunks. This is especially important for the ONE_BLOCK case, because it would be
|
||||
// a mistake for update() to call compress, even though the buffer is full.
|
||||
for &(input, output) in io {
|
||||
let mut state = State::new();
|
||||
let split = input.len() / 2;
|
||||
state.update(&input[..split]);
|
||||
assert_eq!(split as Count, state.count());
|
||||
state.update(&input[split..]);
|
||||
assert_eq!(input.len() as Count, state.count());
|
||||
let hash = state.finalize();
|
||||
assert_eq!(&hash.to_hex(), output, "hash mismatch");
|
||||
}
|
||||
// Now one byte at a time.
|
||||
for &(input, output) in io {
|
||||
let mut state = State::new();
|
||||
let mut count = 0;
|
||||
for &b in input {
|
||||
state.update(&[b]);
|
||||
count += 1;
|
||||
assert_eq!(count, state.count());
|
||||
}
|
||||
let hash = state.finalize();
|
||||
assert_eq!(&hash.to_hex(), output, "hash mismatch");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_multiple_finalizes() {
|
||||
let mut state = State::new();
|
||||
assert_eq!(&state.finalize().to_hex(), EMPTY_HASH, "hash mismatch");
|
||||
assert_eq!(&state.finalize().to_hex(), EMPTY_HASH, "hash mismatch");
|
||||
assert_eq!(&state.finalize().to_hex(), EMPTY_HASH, "hash mismatch");
|
||||
state.update(b"abc");
|
||||
assert_eq!(&state.finalize().to_hex(), ABC_HASH, "hash mismatch");
|
||||
assert_eq!(&state.finalize().to_hex(), ABC_HASH, "hash mismatch");
|
||||
assert_eq!(&state.finalize().to_hex(), ABC_HASH, "hash mismatch");
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
#[test]
|
||||
fn test_write() {
|
||||
use std::io::prelude::*;
|
||||
|
||||
let mut state = State::new();
|
||||
state.write_all(&[0; 1000]).unwrap();
|
||||
let hash = state.finalize();
|
||||
assert_eq!(&hash.to_hex(), THOUSAND_HASH, "hash mismatch");
|
||||
}
|
||||
|
||||
// You can check this case against the equivalent Python:
|
||||
//
|
||||
// import hashlib
|
||||
// hashlib.blake2b(
|
||||
// b'foo',
|
||||
// digest_size=18,
|
||||
// key=b"bar",
|
||||
// salt=b"bazbazbazbazbazb",
|
||||
// person=b"bing bing bing b",
|
||||
// fanout=2,
|
||||
// depth=3,
|
||||
// leaf_size=0x04050607,
|
||||
// node_offset=0x08090a0b0c0d0e0f,
|
||||
// node_depth=16,
|
||||
// inner_size=17,
|
||||
// last_node=True,
|
||||
// ).hexdigest()
|
||||
#[test]
|
||||
fn test_all_parameters() {
|
||||
let mut params = Params::new();
|
||||
params
|
||||
.hash_length(18)
|
||||
// Make sure a shorter key properly overwrites a longer one.
|
||||
.key(b"not the real key")
|
||||
.key(b"bar")
|
||||
.salt(b"bazbazbazbazbazb")
|
||||
.personal(b"bing bing bing b")
|
||||
.fanout(2)
|
||||
.max_depth(3)
|
||||
.max_leaf_length(0x04050607)
|
||||
.node_offset(0x08090a0b0c0d0e0f)
|
||||
.node_depth(16)
|
||||
.inner_hash_length(17)
|
||||
.last_node(true);
|
||||
|
||||
// Check the State API.
|
||||
assert_eq!(
|
||||
"ec0f59cb65f92e7fcca1280ba859a6925ded",
|
||||
¶ms.to_state().update(b"foo").finalize().to_hex()
|
||||
);
|
||||
|
||||
// Check the all-at-once API.
|
||||
assert_eq!(
|
||||
"ec0f59cb65f92e7fcca1280ba859a6925ded",
|
||||
¶ms.hash(b"foo").to_hex()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_all_parameters_blake2bp() {
|
||||
let mut params = blake2bp::Params::new();
|
||||
params
|
||||
.hash_length(18)
|
||||
// Make sure a shorter key properly overwrites a longer one.
|
||||
.key(b"not the real key")
|
||||
.key(b"bar");
|
||||
|
||||
// Check the State API.
|
||||
assert_eq!(
|
||||
"8c54e888a8a01c63da6585c058fe54ea81df",
|
||||
¶ms.to_state().update(b"foo").finalize().to_hex()
|
||||
);
|
||||
|
||||
// Check the all-at-once API.
|
||||
assert_eq!(
|
||||
"8c54e888a8a01c63da6585c058fe54ea81df",
|
||||
¶ms.hash(b"foo").to_hex()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_short_hash_length_panics() {
|
||||
Params::new().hash_length(0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_long_hash_length_panics() {
|
||||
Params::new().hash_length(OUTBYTES + 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_long_key_panics() {
|
||||
Params::new().key(&[0; KEYBYTES + 1]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_long_salt_panics() {
|
||||
Params::new().salt(&[0; SALTBYTES + 1]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_long_personal_panics() {
|
||||
Params::new().personal(&[0; PERSONALBYTES + 1]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zero_max_depth_supported() {
|
||||
Params::new().max_depth(0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_long_inner_hash_length_panics() {
|
||||
Params::new().inner_hash_length(OUTBYTES + 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_blake2bp_short_hash_length_panics() {
|
||||
blake2bp::Params::new().hash_length(0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_blake2bp_long_hash_length_panics() {
|
||||
blake2bp::Params::new().hash_length(OUTBYTES + 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_blake2bp_long_key_panics() {
|
||||
blake2bp::Params::new().key(&[0; KEYBYTES + 1]);
|
||||
}
|
@ -1 +0,0 @@
|
||||
{"files":{"Cargo.toml":"5039cc861ab84d85162dc1b3acf268a98d63d299a99b897ab21d390a9e9fb0f3","LICENSE.txt":"a2010f343487d3f7618affe54f789f5487602331c0a8d03f49e9a7c547cf0499","README":"4f0deec2ec32eeabaa065fef2ddd7816a32550b8395da5c47fc458bd45143bea","benches/bench.rs":"ffc599703d114cc4943db322f433b0819787db0c1ff41d7be3efc5c0940e0001","src/lib.rs":"ab735430ea1eaea0673a9a15d9437d591a718bc061c70f3499e42b65e4eb8ba4"},"package":"245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc"}
|
25
third_party/rust/constant_time_eq/Cargo.toml
vendored
25
third_party/rust/constant_time_eq/Cargo.toml
vendored
@ -1,25 +0,0 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "constant_time_eq"
|
||||
version = "0.1.5"
|
||||
authors = ["Cesar Eduardo Barros <cesarb@cesarb.eti.br>"]
|
||||
description = "Compares two equal-sized byte strings in constant time."
|
||||
documentation = "https://docs.rs/constant_time_eq"
|
||||
readme = "README"
|
||||
keywords = ["constant_time"]
|
||||
categories = ["cryptography", "no-std"]
|
||||
license = "CC0-1.0"
|
||||
repository = "https://github.com/cesarb/constant_time_eq"
|
||||
[badges.travis-ci]
|
||||
repository = "cesarb/constant_time_eq"
|
121
third_party/rust/constant_time_eq/LICENSE.txt
vendored
121
third_party/rust/constant_time_eq/LICENSE.txt
vendored
@ -1,121 +0,0 @@
|
||||
Creative Commons Legal Code
|
||||
|
||||
CC0 1.0 Universal
|
||||
|
||||
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
|
||||
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
|
||||
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
|
||||
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
|
||||
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
||||
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
|
||||
HEREUNDER.
|
||||
|
||||
Statement of Purpose
|
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer
|
||||
exclusive Copyright and Related Rights (defined below) upon the creator
|
||||
and subsequent owner(s) (each and all, an "owner") of an original work of
|
||||
authorship and/or a database (each, a "Work").
|
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for
|
||||
the purpose of contributing to a commons of creative, cultural and
|
||||
scientific works ("Commons") that the public can reliably and without fear
|
||||
of later claims of infringement build upon, modify, incorporate in other
|
||||
works, reuse and redistribute as freely as possible in any form whatsoever
|
||||
and for any purposes, including without limitation commercial purposes.
|
||||
These owners may contribute to the Commons to promote the ideal of a free
|
||||
culture and the further production of creative, cultural and scientific
|
||||
works, or to gain reputation or greater distribution for their Work in
|
||||
part through the use and efforts of others.
|
||||
|
||||
For these and/or other purposes and motivations, and without any
|
||||
expectation of additional consideration or compensation, the person
|
||||
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
|
||||
is an owner of Copyright and Related Rights in the Work, voluntarily
|
||||
elects to apply CC0 to the Work and publicly distribute the Work under its
|
||||
terms, with knowledge of his or her Copyright and Related Rights in the
|
||||
Work and the meaning and intended legal effect of CC0 on those rights.
|
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be
|
||||
protected by copyright and related or neighboring rights ("Copyright and
|
||||
Related Rights"). Copyright and Related Rights include, but are not
|
||||
limited to, the following:
|
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display,
|
||||
communicate, and translate a Work;
|
||||
ii. moral rights retained by the original author(s) and/or performer(s);
|
||||
iii. publicity and privacy rights pertaining to a person's image or
|
||||
likeness depicted in a Work;
|
||||
iv. rights protecting against unfair competition in regards to a Work,
|
||||
subject to the limitations in paragraph 4(a), below;
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data
|
||||
in a Work;
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the
|
||||
European Parliament and of the Council of 11 March 1996 on the legal
|
||||
protection of databases, and under any national implementation
|
||||
thereof, including any amended or successor version of such
|
||||
directive); and
|
||||
vii. other similar, equivalent or corresponding rights throughout the
|
||||
world based on applicable law or treaty, and any national
|
||||
implementations thereof.
|
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention
|
||||
of, applicable law, Affirmer hereby overtly, fully, permanently,
|
||||
irrevocably and unconditionally waives, abandons, and surrenders all of
|
||||
Affirmer's Copyright and Related Rights and associated claims and causes
|
||||
of action, whether now known or unknown (including existing as well as
|
||||
future claims and causes of action), in the Work (i) in all territories
|
||||
worldwide, (ii) for the maximum duration provided by applicable law or
|
||||
treaty (including future time extensions), (iii) in any current or future
|
||||
medium and for any number of copies, and (iv) for any purpose whatsoever,
|
||||
including without limitation commercial, advertising or promotional
|
||||
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
|
||||
member of the public at large and to the detriment of Affirmer's heirs and
|
||||
successors, fully intending that such Waiver shall not be subject to
|
||||
revocation, rescission, cancellation, termination, or any other legal or
|
||||
equitable action to disrupt the quiet enjoyment of the Work by the public
|
||||
as contemplated by Affirmer's express Statement of Purpose.
|
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason
|
||||
be judged legally invalid or ineffective under applicable law, then the
|
||||
Waiver shall be preserved to the maximum extent permitted taking into
|
||||
account Affirmer's express Statement of Purpose. In addition, to the
|
||||
extent the Waiver is so judged Affirmer hereby grants to each affected
|
||||
person a royalty-free, non transferable, non sublicensable, non exclusive,
|
||||
irrevocable and unconditional license to exercise Affirmer's Copyright and
|
||||
Related Rights in the Work (i) in all territories worldwide, (ii) for the
|
||||
maximum duration provided by applicable law or treaty (including future
|
||||
time extensions), (iii) in any current or future medium and for any number
|
||||
of copies, and (iv) for any purpose whatsoever, including without
|
||||
limitation commercial, advertising or promotional purposes (the
|
||||
"License"). The License shall be deemed effective as of the date CC0 was
|
||||
applied by Affirmer to the Work. Should any part of the License for any
|
||||
reason be judged legally invalid or ineffective under applicable law, such
|
||||
partial invalidity or ineffectiveness shall not invalidate the remainder
|
||||
of the License, and in such case Affirmer hereby affirms that he or she
|
||||
will not (i) exercise any of his or her remaining Copyright and Related
|
||||
Rights in the Work or (ii) assert any associated claims and causes of
|
||||
action with respect to the Work, in either case contrary to Affirmer's
|
||||
express Statement of Purpose.
|
||||
|
||||
4. Limitations and Disclaimers.
|
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned,
|
||||
surrendered, licensed or otherwise affected by this document.
|
||||
b. Affirmer offers the Work as-is and makes no representations or
|
||||
warranties of any kind concerning the Work, express, implied,
|
||||
statutory or otherwise, including without limitation warranties of
|
||||
title, merchantability, fitness for a particular purpose, non
|
||||
infringement, or the absence of latent or other defects, accuracy, or
|
||||
the present or absence of errors, whether or not discoverable, all to
|
||||
the greatest extent permissible under applicable law.
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons
|
||||
that may apply to the Work or any use thereof, including without
|
||||
limitation any person's Copyright and Related Rights in the Work.
|
||||
Further, Affirmer disclaims responsibility for obtaining any necessary
|
||||
consents, permissions or other rights required for any use of the
|
||||
Work.
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a
|
||||
party to this document and has no duty or obligation with respect to
|
||||
this CC0 or use of the Work.
|
3
third_party/rust/constant_time_eq/README
vendored
3
third_party/rust/constant_time_eq/README
vendored
@ -1,3 +0,0 @@
|
||||
Compares two equal-sized byte strings in constant time.
|
||||
|
||||
Inspired by the Linux kernel's crypto_memneq.
|
@ -1,29 +0,0 @@
|
||||
#![feature(test)]
|
||||
|
||||
extern crate constant_time_eq;
|
||||
extern crate test;
|
||||
|
||||
use constant_time_eq::constant_time_eq;
|
||||
use test::{Bencher, black_box};
|
||||
|
||||
fn bench(b: &mut Bencher, left: &[u8], right: &[u8]) {
|
||||
b.bytes = (left.len() + right.len()) as u64;
|
||||
b.iter(|| {
|
||||
constant_time_eq(black_box(left), black_box(right))
|
||||
})
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_16(b: &mut Bencher) {
|
||||
bench(b, &[0; 16], &[0; 16])
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_4096(b: &mut Bencher) {
|
||||
bench(b, &[0; 4096], &[0; 4096])
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn bench_65536(b: &mut Bencher) {
|
||||
bench(b, &[0; 65536], &[0; 65536])
|
||||
}
|
105
third_party/rust/constant_time_eq/src/lib.rs
vendored
105
third_party/rust/constant_time_eq/src/lib.rs
vendored
@ -1,105 +0,0 @@
|
||||
#![no_std]
|
||||
|
||||
// This function is non-inline to prevent the optimizer from looking inside it.
|
||||
#[inline(never)]
|
||||
fn constant_time_ne(a: &[u8], b: &[u8]) -> u8 {
|
||||
assert!(a.len() == b.len());
|
||||
|
||||
// These useless slices make the optimizer elide the bounds checks.
|
||||
// See the comment in clone_from_slice() added on Rust commit 6a7bc47.
|
||||
let len = a.len();
|
||||
let a = &a[..len];
|
||||
let b = &b[..len];
|
||||
|
||||
let mut tmp = 0;
|
||||
for i in 0..len {
|
||||
tmp |= a[i] ^ b[i];
|
||||
}
|
||||
tmp // The compare with 0 must happen outside this function.
|
||||
}
|
||||
|
||||
/// Compares two equal-sized byte strings in constant time.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use constant_time_eq::constant_time_eq;
|
||||
///
|
||||
/// assert!(constant_time_eq(b"foo", b"foo"));
|
||||
/// assert!(!constant_time_eq(b"foo", b"bar"));
|
||||
/// assert!(!constant_time_eq(b"bar", b"baz"));
|
||||
/// # assert!(constant_time_eq(b"", b""));
|
||||
///
|
||||
/// // Not equal-sized, so won't take constant time.
|
||||
/// assert!(!constant_time_eq(b"foo", b""));
|
||||
/// assert!(!constant_time_eq(b"foo", b"quux"));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn constant_time_eq(a: &[u8], b: &[u8]) -> bool {
|
||||
a.len() == b.len() && constant_time_ne(a, b) == 0
|
||||
}
|
||||
|
||||
// Fixed-size variants for the most common sizes.
|
||||
|
||||
macro_rules! constant_time_ne_n {
|
||||
($ne:ident, $n:expr) => {
|
||||
// This function is non-inline to prevent the optimizer from looking inside it.
|
||||
#[inline(never)]
|
||||
fn $ne(a: &[u8; $n], b: &[u8; $n]) -> u8 {
|
||||
let mut tmp = 0;
|
||||
for i in 0..$n {
|
||||
tmp |= a[i] ^ b[i];
|
||||
}
|
||||
tmp // The compare with 0 must happen outside this function.
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
constant_time_ne_n!(constant_time_ne_16, 16);
|
||||
constant_time_ne_n!(constant_time_ne_32, 32);
|
||||
constant_time_ne_n!(constant_time_ne_64, 64);
|
||||
|
||||
/// Compares two 128-bit byte strings in constant time.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use constant_time_eq::constant_time_eq_16;
|
||||
///
|
||||
/// assert!(constant_time_eq_16(&[3; 16], &[3; 16]));
|
||||
/// assert!(!constant_time_eq_16(&[3; 16], &[7; 16]));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn constant_time_eq_16(a: &[u8; 16], b: &[u8; 16]) -> bool {
|
||||
constant_time_ne_16(a, b) == 0
|
||||
}
|
||||
|
||||
/// Compares two 256-bit byte strings in constant time.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use constant_time_eq::constant_time_eq_32;
|
||||
///
|
||||
/// assert!(constant_time_eq_32(&[3; 32], &[3; 32]));
|
||||
/// assert!(!constant_time_eq_32(&[3; 32], &[7; 32]));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn constant_time_eq_32(a: &[u8; 32], b: &[u8; 32]) -> bool {
|
||||
constant_time_ne_32(a, b) == 0
|
||||
}
|
||||
|
||||
/// Compares two 512-bit byte strings in constant time.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use constant_time_eq::constant_time_eq_64;
|
||||
///
|
||||
/// assert!(constant_time_eq_64(&[3; 64], &[3; 64]));
|
||||
/// assert!(!constant_time_eq_64(&[3; 64], &[7; 64]));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn constant_time_eq_64(a: &[u8; 64], b: &[u8; 64]) -> bool {
|
||||
constant_time_ne_64(a, b) == 0
|
||||
}
|
@ -1 +0,0 @@
|
||||
{"files":{"Cargo.toml":"1c598c990a0957aa81b038c1ece1d6b0c6d606c3cdd6420eb3ef5845510a4178","LICENSE":"e6a8ae2d796083783efc94b1e66271aa2929dc4dfb231d34239aa9c7db8396db","README.md":"9c3a6fd2a798bd1e105c5ee72f7b475471e3a9abec89b5be2b5263d654085d22","src/lib.rs":"d9d82538b9c6a3467407525e0db2c588981f2491fb40fbe237af925bc13a7551","tests/etc/group":"175d89e8d03e2976d3f37110050372163fcafd07a20c899ade3a9690b2cb4526","tests/etc/passwd":"aee0d4bd2abf55846683cc2e5daaa03641636a262519623d59b1ab8e1eb1db32","tests/etc/shadow":"ca7c1a6f96eaef3bd26da4faeae55e78cad04822c191e3263b539ee687de4d0a"},"package":"de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d"}
|
35
third_party/rust/redox_users/Cargo.toml
vendored
35
third_party/rust/redox_users/Cargo.toml
vendored
@ -1,35 +0,0 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
name = "redox_users"
|
||||
version = "0.3.5"
|
||||
authors = ["Jose Narvaez <goyox86@gmail.com>", "Wesley Hershberger <mggmugginsmc@gmail.com>"]
|
||||
description = "A Rust library to access Redox users and groups functionality"
|
||||
documentation = "https://docs.rs/redox_users"
|
||||
readme = "README.md"
|
||||
keywords = ["redox", "auth"]
|
||||
license = "MIT"
|
||||
repository = "https://gitlab.redox-os.org/redox-os/users"
|
||||
[dependencies.getrandom]
|
||||
version = "0.1"
|
||||
|
||||
[dependencies.redox_syscall]
|
||||
version = "0.1"
|
||||
|
||||
[dependencies.rust-argon2]
|
||||
version = "0.8"
|
||||
optional = true
|
||||
|
||||
[features]
|
||||
auth = ["rust-argon2"]
|
||||
default = ["auth"]
|
22
third_party/rust/redox_users/LICENSE
vendored
22
third_party/rust/redox_users/LICENSE
vendored
@ -1,22 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 Jose Narvaez
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
23
third_party/rust/redox_users/README.md
vendored
23
third_party/rust/redox_users/README.md
vendored
@ -1,23 +0,0 @@
|
||||
# redox_users <a href="https://crates.io/crates/redox_users"><img src="https://img.shields.io/crates/v/redox_users.svg"></a>
|
||||
|
||||
Redox OS APIs for accessing users and groups information. [Documentation](https://docs.rs/redox_users/0.1.0/redox_users/)
|
||||
|
||||
High level APIs for:
|
||||
|
||||
- Getting the current process effective user ID.
|
||||
- Getting the current process user ID.
|
||||
- Getting the current process effective group ID.
|
||||
- Getting the current process group ID.
|
||||
- Manipulating User and Group information (including adding, removing, and modifying groups and users, in addition to other functionality, see docs)
|
||||
|
||||
We recommend to use these APIs instead of directly manipulating the
|
||||
`/etc/group` and `/etc/passwd` as this is an implementation detail and
|
||||
might change in the future.
|
||||
|
||||
Note that redox_users is an API designed only for use on Redox. It compiles on other platforms (for testing), but it will not work and might produce unexpected behavior.
|
||||
|
||||
## Hashing
|
||||
redox_users uses the Argon2 hashing algorithm. The default hashing parameters are as follows:
|
||||
```Rust
|
||||
Argon2::new(10, 1, 4096, Variant::Argon2i)
|
||||
```
|
1357
third_party/rust/redox_users/src/lib.rs
vendored
1357
third_party/rust/redox_users/src/lib.rs
vendored
File diff suppressed because it is too large
Load Diff
4
third_party/rust/redox_users/tests/etc/group
vendored
4
third_party/rust/redox_users/tests/etc/group
vendored
@ -1,4 +0,0 @@
|
||||
root;0;root
|
||||
user;1000;user
|
||||
wheel;1;user,root
|
||||
li;1007;li
|
@ -1,3 +0,0 @@
|
||||
root;0;0;root;file:/root;file:/bin/ion
|
||||
user;1000;1000;user;file:/home/user;file:/bin/ion
|
||||
li;1007;1007;Lorem;file:/home/lorem;file:/bin/ion
|
@ -1,3 +0,0 @@
|
||||
root;$argon2i$m=4096,t=10,p=1$Tnc4UVV0N00$ML9LIOujd3nmAfkAwEcSTMPqakWUF0OUiLWrIy0nGLk
|
||||
user;
|
||||
li;!
|
@ -1 +0,0 @@
|
||||
{"files":{"CHANGELOG.md":"5ec3f32d09a22757e0f36f39dbd57db8bb382e274446364eb0604b84ed9664e7","Cargo.toml":"847d8033f0dec82bee18fb3dc76f685f34431b7b0af813de9a18fd8a36b374d4","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"26b997d1a1496df49cb1ad2cbe024714cd9126543c18e1bc6c7bbca1b3dc42b6","README.md":"2e5715166ab7b99342d7be096db244709d96c3dc2fbe393eb8afe7de198ecd37","src/argon2.rs":"c7ee856d807a6f3eb72efacd0af96d71f1075ae8e754831485f3b80c072caaab","src/block.rs":"08968700128c9d5de01a60b070fbe20fee8c5bf7428979515d3598ddc4268a6f","src/common.rs":"ff3d031e058e65cc03247008c61ba702e08d2d2545536c86aa208bbc05e7e8e2","src/config.rs":"60b2fcfca173d613e78edebb8827aacec4007675f64bdad5a038c7c7f8b1456c","src/context.rs":"3e774b14e97f336c0935b0eacec44e11daeda6d2039eefb93ed3568b4e48ba02","src/core.rs":"273633c52892dae6da3d4e4c9cd116d59f4235ab65c57a6dd0d31042657d27fa","src/decoded.rs":"0e7b4a64a1848809a9e0dd95618eb32851f13a5ac73f95e4547cfbb71d0dfdbb","src/encoding.rs":"532089c7233908b2ce7082f920f4c95b8d568160b9fd0b1a8f4d2a962623a681","src/error.rs":"e8fd91c80830d97af6d132dc8c7e9d0dcaf690ca7c1daf8b661b1ad5cb15443c","src/lib.rs":"22c795c286035f2dd5f5ea668b67cca2f25e46ba7f68a084edae91b65ef197e6","src/memory.rs":"bee7a02c738024c4a0fbfd2f4ae6515fb8ec36cb3922dd2ff0683f7864b3b713","src/result.rs":"54afe0972853b6e16c8a99118ddf4564112b8446ba4592131c4c66afd55822dd","src/thread_mode.rs":"21814ede00af01d43c0b04392bcfa0dc6fa24d0bedcef13248a100b2e9b290a8","src/variant.rs":"8ec67987dded48b1851085df99b1f25aa4c99b749acc60476db77f6d780672e5","src/version.rs":"6cdbb34892e1c09983eb81aec39be93bb5ea09ad001aa9f7c387f631be7feda4","tests/integration_test.rs":"25fbc41a35595223d074091844f934b816c75fbd535153e998470479fb1b7478"},"package":"4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb"}
|
88
third_party/rust/rust-argon2/CHANGELOG.md
vendored
88
third_party/rust/rust-argon2/CHANGELOG.md
vendored
@ -1,88 +0,0 @@
|
||||
ChangeLog for rust-argon2
|
||||
=========================
|
||||
|
||||
This documents all notable changes to
|
||||
[rust-argon2](https://github.com/sru-systems/rust-argon2).
|
||||
|
||||
|
||||
## 0.8.3
|
||||
|
||||
- Replace transmute with to_le_bytes.
|
||||
- Update base64 to version 0.13.
|
||||
- Update crossbeam-utils to version 0.8.
|
||||
- Update hex to version 0.4.
|
||||
- Derive Clone for Error struct.
|
||||
- Add optional serde support for Error struct.
|
||||
|
||||
|
||||
## 0.8.2
|
||||
|
||||
- Change base64 to latest version (0.12).
|
||||
|
||||
|
||||
## 0.8.1
|
||||
|
||||
- Fix issue with verifying multi-lane hashes with parallelism disabled (#27)
|
||||
|
||||
## 0.8.0
|
||||
|
||||
- Make parallelism optional via feature flag.
|
||||
|
||||
|
||||
## 0.7.0
|
||||
|
||||
- Update crossbeam-utils dependency to 0.7.
|
||||
|
||||
|
||||
## 0.6.1
|
||||
|
||||
- Use constant time equals to compare hashes.
|
||||
|
||||
|
||||
## 0.6.0
|
||||
|
||||
- Use 2018 edition or Rust
|
||||
- Use &dyn error::Error instead of &error::Error
|
||||
- Fix clippy lints
|
||||
- Allow callers of encode_string to pass any &[u8]
|
||||
- Update base64 dependency.
|
||||
|
||||
|
||||
## 0.5.1
|
||||
|
||||
- Use crossbeam utils 0.6 instead of crossbeam 0.5
|
||||
|
||||
|
||||
## 0.5.0
|
||||
|
||||
- Replace blake2-rfc with blake2b_simd.
|
||||
|
||||
|
||||
## 0.4.0
|
||||
|
||||
- Replace rustc-serialize dependency with base64 and hex.
|
||||
- Update base64 dependency.
|
||||
- Update crossbeam dependency.
|
||||
- Update hex dependency.
|
||||
- Allow updating to minor versions of blake2-rfc.
|
||||
|
||||
|
||||
## 0.3.0
|
||||
|
||||
- Embed Config struct in Context struct.
|
||||
|
||||
|
||||
## 0.2.0
|
||||
|
||||
- Use ThreadMode enum instead of explicit thread number.
|
||||
- Use a Config struct instead of explicit configuration arguments.
|
||||
- Use references instead of vectors for byte data in the Context struct.
|
||||
- Deprecate the following functions:
|
||||
- hash_encoded_defaults
|
||||
- hash_encoded_old
|
||||
- hash_encoded_std
|
||||
- hash_raw_defaults
|
||||
- hash_raw_old
|
||||
- hash_raw_std
|
||||
- verify_raw_old
|
||||
- verify_raw_std
|
49
third_party/rust/rust-argon2/Cargo.toml
vendored
49
third_party/rust/rust-argon2/Cargo.toml
vendored
@ -1,49 +0,0 @@
|
||||
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
|
||||
#
|
||||
# When uploading crates to the registry Cargo will automatically
|
||||
# "normalize" Cargo.toml files for maximal compatibility
|
||||
# with all versions of Cargo and also rewrite `path` dependencies
|
||||
# to registry (e.g., crates.io) dependencies
|
||||
#
|
||||
# If you believe there's an error in this file please file an
|
||||
# issue against the rust-lang/cargo repository. If you're
|
||||
# editing this file be aware that the upstream Cargo.toml
|
||||
# will likely look very different (and much more reasonable)
|
||||
|
||||
[package]
|
||||
edition = "2018"
|
||||
name = "rust-argon2"
|
||||
version = "0.8.3"
|
||||
authors = ["Martijn Rijkeboer <mrr@sru-systems.com>"]
|
||||
description = "Rust implementation of the Argon2 password hashing function."
|
||||
homepage = "https://github.com/sru-systems/rust-argon2"
|
||||
documentation = "https://docs.sru-systems.com/rust-argon2/0.8.0/argon2/"
|
||||
readme = "README.md"
|
||||
keywords = ["argon2", "argon2d", "argon2i", "hash", "password"]
|
||||
license = "MIT/Apache-2.0"
|
||||
repository = "https://github.com/sru-systems/rust-argon2"
|
||||
|
||||
[lib]
|
||||
name = "argon2"
|
||||
[dependencies.base64]
|
||||
version = "0.13"
|
||||
|
||||
[dependencies.blake2b_simd]
|
||||
version = "0.5"
|
||||
|
||||
[dependencies.constant_time_eq]
|
||||
version = "0.1.4"
|
||||
|
||||
[dependencies.crossbeam-utils]
|
||||
version = "0.8"
|
||||
optional = true
|
||||
|
||||
[dependencies.serde]
|
||||
version = "1.0.116"
|
||||
features = ["derive"]
|
||||
optional = true
|
||||
[dev-dependencies.hex]
|
||||
version = "0.4"
|
||||
|
||||
[features]
|
||||
default = ["crossbeam-utils"]
|
201
third_party/rust/rust-argon2/LICENSE-APACHE
vendored
201
third_party/rust/rust-argon2/LICENSE-APACHE
vendored
@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
22
third_party/rust/rust-argon2/LICENSE-MIT
vendored
22
third_party/rust/rust-argon2/LICENSE-MIT
vendored
@ -1,22 +0,0 @@
|
||||
The MIT license.
|
||||
|
||||
Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
85
third_party/rust/rust-argon2/README.md
vendored
85
third_party/rust/rust-argon2/README.md
vendored
@ -1,85 +0,0 @@
|
||||
# Rust-argon2
|
||||
|
||||
Rust library for hashing passwords using
|
||||
[Argon2](https://github.com/P-H-C/phc-winner-argon2), the password-hashing
|
||||
function that won the
|
||||
[Password Hashing Competition (PHC)](https://password-hashing.net).
|
||||
|
||||
## Usage
|
||||
|
||||
To use `rust-argon2`, add the following to your Cargo.toml:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
rust-argon2 = "0.8"
|
||||
```
|
||||
|
||||
And the following to your crate root:
|
||||
|
||||
```rust
|
||||
extern crate argon2;
|
||||
```
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Create a password hash using the defaults and verify it:
|
||||
|
||||
```rust
|
||||
use argon2::{self, Config};
|
||||
|
||||
let password = b"password";
|
||||
let salt = b"randomsalt";
|
||||
let config = Config::default();
|
||||
let hash = argon2::hash_encoded(password, salt, &config).unwrap();
|
||||
let matches = argon2::verify_encoded(&hash, password).unwrap();
|
||||
assert!(matches);
|
||||
```
|
||||
|
||||
Create a password hash with custom settings and verify it:
|
||||
|
||||
```rust
|
||||
use argon2::{self, Config, ThreadMode, Variant, Version};
|
||||
|
||||
let password = b"password";
|
||||
let salt = b"othersalt";
|
||||
let config = Config {
|
||||
variant: Variant::Argon2i,
|
||||
version: Version::Version13,
|
||||
mem_cost: 65536,
|
||||
time_cost: 10,
|
||||
lanes: 4,
|
||||
thread_mode: ThreadMode::Parallel,
|
||||
secret: &[],
|
||||
ad: &[],
|
||||
hash_length: 32
|
||||
};
|
||||
let hash = argon2::hash_encoded(password, salt, &config).unwrap();
|
||||
let matches = argon2::verify_encoded(&hash, password).unwrap();
|
||||
assert!(matches);
|
||||
```
|
||||
|
||||
|
||||
## Limitations
|
||||
|
||||
This crate has the same limitation as the `blake2-rfc` crate that it uses.
|
||||
It does not attempt to clear potentially sensitive data from its work
|
||||
memory. To do so correctly without a heavy performance penalty would
|
||||
require help from the compiler. It's better to not attempt to do so than to
|
||||
present a false assurance.
|
||||
|
||||
This version uses the standard implementation and does not yet implement
|
||||
optimizations. Therefore, it is not the fastest implementation available.
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Rust-argon2 is dual licensed under the [MIT](LICENSE-MIT) and
|
||||
[Apache 2.0](LICENSE-APACHE) licenses, the same licenses as the Rust compiler.
|
||||
|
||||
|
||||
## Contributions
|
||||
|
||||
Contributions are welcome. By submitting a pull request you are agreeing to
|
||||
make you work available under the license terms of the Rust-argon2 project.
|
||||
|
760
third_party/rust/rust-argon2/src/argon2.rs
vendored
760
third_party/rust/rust-argon2/src/argon2.rs
vendored
@ -1,760 +0,0 @@
|
||||
// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::context::Context;
|
||||
use crate::core;
|
||||
use crate::encoding;
|
||||
use crate::memory::Memory;
|
||||
use crate::result::Result;
|
||||
use crate::thread_mode::ThreadMode;
|
||||
use crate::variant::Variant;
|
||||
use crate::version::Version;
|
||||
|
||||
use constant_time_eq::constant_time_eq;
|
||||
|
||||
/// Returns the length of the encoded string.
|
||||
///
|
||||
/// # Remarks
|
||||
///
|
||||
/// The length is **one** less that the original C version, since no null
|
||||
/// terminator is used.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use argon2::{self, Variant};
|
||||
///
|
||||
/// let variant = Variant::Argon2i;
|
||||
/// let mem = 4096;
|
||||
/// let time = 10;
|
||||
/// let parallelism = 10;
|
||||
/// let salt_len = 8;
|
||||
/// let hash_len = 32;
|
||||
/// let enc_len = argon2::encoded_len(variant, mem, time, parallelism, salt_len, hash_len);
|
||||
/// assert_eq!(enc_len, 86);
|
||||
/// ```
|
||||
#[rustfmt::skip]
|
||||
pub fn encoded_len(
|
||||
variant: Variant,
|
||||
mem_cost: u32,
|
||||
time_cost: u32,
|
||||
parallelism: u32,
|
||||
salt_len: u32,
|
||||
hash_len: u32
|
||||
) -> u32 {
|
||||
("$$v=$m=,t=,p=$$".len() as u32) +
|
||||
(variant.as_lowercase_str().len() as u32) +
|
||||
encoding::num_len(Version::default().as_u32()) +
|
||||
encoding::num_len(mem_cost) +
|
||||
encoding::num_len(time_cost) +
|
||||
encoding::num_len(parallelism) +
|
||||
encoding::base64_len(salt_len) +
|
||||
encoding::base64_len(hash_len)
|
||||
}
|
||||
|
||||
/// Hashes the password and returns the encoded hash.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Create an encoded hash with the default configuration:
|
||||
///
|
||||
/// ```
|
||||
/// use argon2::{self, Config};
|
||||
///
|
||||
/// let pwd = b"password";
|
||||
/// let salt = b"somesalt";
|
||||
/// let config = Config::default();
|
||||
/// let encoded = argon2::hash_encoded(pwd, salt, &config).unwrap();
|
||||
/// ```
|
||||
///
|
||||
///
|
||||
/// Create an Argon2d encoded hash with 4 lanes and parallel execution:
|
||||
///
|
||||
/// ```
|
||||
/// use argon2::{self, Config, ThreadMode, Variant};
|
||||
///
|
||||
/// let pwd = b"password";
|
||||
/// let salt = b"somesalt";
|
||||
/// let mut config = Config::default();
|
||||
/// config.variant = Variant::Argon2d;
|
||||
#[cfg_attr(feature = "crossbeam-utils", doc = "config.lanes = 4;")]
|
||||
#[cfg_attr(
|
||||
feature = "crossbeam-utils",
|
||||
doc = "config.thread_mode = ThreadMode::Parallel;"
|
||||
)]
|
||||
#[cfg_attr(not(feature = "crossbeam-utils"), doc = "config.lanes = 1;")]
|
||||
#[cfg_attr(
|
||||
not(feature = "crossbeam-utils"),
|
||||
doc = "config.thread_mode = ThreadMode::Sequential;"
|
||||
)]
|
||||
/// let encoded = argon2::hash_encoded(pwd, salt, &config).unwrap();
|
||||
/// ```
|
||||
pub fn hash_encoded(pwd: &[u8], salt: &[u8], config: &Config) -> Result<String> {
|
||||
let context = Context::new(config.clone(), pwd, salt)?;
|
||||
let hash = run(&context);
|
||||
let encoded = encoding::encode_string(&context, &hash);
|
||||
Ok(encoded)
|
||||
}
|
||||
|
||||
/// Hashes the password using default settings and returns the encoded hash.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use argon2;
|
||||
///
|
||||
/// let pwd = b"password";
|
||||
/// let salt = b"somesalt";
|
||||
/// let encoded = argon2::hash_encoded_defaults(pwd, salt).unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// The above rewritten using `hash_encoded`:
|
||||
///
|
||||
/// ```
|
||||
/// use argon2::{self, Config};
|
||||
///
|
||||
/// let pwd = b"password";
|
||||
/// let salt = b"somesalt";
|
||||
/// let config = Config::default();
|
||||
/// let encoded = argon2::hash_encoded(pwd, salt, &config).unwrap();
|
||||
/// ```
|
||||
#[deprecated(since = "0.2.0", note = "please use `hash_encoded` instead")]
|
||||
pub fn hash_encoded_defaults(pwd: &[u8], salt: &[u8]) -> Result<String> {
|
||||
hash_encoded(pwd, salt, &Config::default())
|
||||
}
|
||||
|
||||
/// Hashes the password and returns the encoded hash (pre 0.2.0 `hash_encoded`).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// use argon2::{self, Variant, Version};
|
||||
///
|
||||
/// let pwd = b"password";
|
||||
/// let salt = b"somesalt";
|
||||
/// let mem_cost = 4096;
|
||||
/// let time_cost = 10;
|
||||
/// let lanes = 1;
|
||||
/// let threads = 1;
|
||||
/// let secret = b"secret value";
|
||||
/// let ad = b"associated data";
|
||||
/// let hash_len = 32;
|
||||
/// let encoded = argon2::hash_encoded_old(Variant::Argon2i,
|
||||
/// Version::Version13,
|
||||
/// mem_cost,
|
||||
/// time_cost,
|
||||
/// lanes,
|
||||
/// threads,
|
||||
/// pwd,
|
||||
/// salt,
|
||||
/// secret,
|
||||
/// ad,
|
||||
/// hash_len).unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// The above rewritten using the new `hash_encoded`:
|
||||
///
|
||||
/// ```
|
||||
/// use argon2::{self, Config, ThreadMode, Variant, Version};
|
||||
///
|
||||
/// let pwd = b"password";
|
||||
/// let salt = b"somesalt";
|
||||
/// let config = Config {
|
||||
/// variant: Variant::Argon2i,
|
||||
/// version: Version::Version13,
|
||||
/// mem_cost: 4096,
|
||||
/// time_cost: 10,
|
||||
/// lanes: 1,
|
||||
/// thread_mode: ThreadMode::Sequential,
|
||||
/// secret: b"secret value",
|
||||
/// ad: b"associated data",
|
||||
/// hash_length: 32,
|
||||
/// };
|
||||
/// let encoded = argon2::hash_encoded(pwd, salt, &config).unwrap();
|
||||
/// ```
|
||||
#[deprecated(since = "0.2.0", note = "please use new `hash_encoded` instead")]
|
||||
pub fn hash_encoded_old(
|
||||
variant: Variant,
|
||||
version: Version,
|
||||
mem_cost: u32,
|
||||
time_cost: u32,
|
||||
lanes: u32,
|
||||
threads: u32,
|
||||
pwd: &[u8],
|
||||
salt: &[u8],
|
||||
secret: &[u8],
|
||||
ad: &[u8],
|
||||
hash_len: u32,
|
||||
) -> Result<String> {
|
||||
let threads = if cfg!(feature = "crossbeam-utils") { threads } else { 1 };
|
||||
let config = Config {
|
||||
variant,
|
||||
version,
|
||||
mem_cost,
|
||||
time_cost,
|
||||
lanes,
|
||||
thread_mode: ThreadMode::from_threads(threads),
|
||||
secret,
|
||||
ad,
|
||||
hash_length: hash_len,
|
||||
};
|
||||
hash_encoded(pwd, salt, &config)
|
||||
}
|
||||
|
||||
/// Hashes the password and returns the encoded hash (standard).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// use argon2::{self, Variant, Version};
|
||||
///
|
||||
/// let pwd = b"password";
|
||||
/// let salt = b"somesalt";
|
||||
/// let mem_cost = 4096;
|
||||
/// let time_cost = 10;
|
||||
/// let parallelism = 1;
|
||||
/// let hash_len = 32;
|
||||
/// let encoded = argon2::hash_encoded_std(Variant::Argon2i,
|
||||
/// Version::Version13,
|
||||
/// mem_cost,
|
||||
/// time_cost,
|
||||
/// parallelism,
|
||||
/// pwd,
|
||||
/// salt,
|
||||
/// hash_len).unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// The above rewritten using `hash_encoded`:
|
||||
///
|
||||
/// ```
|
||||
/// use argon2::{self, Config, ThreadMode, Variant, Version};
|
||||
///
|
||||
/// let pwd = b"password";
|
||||
/// let salt = b"somesalt";
|
||||
/// let config = Config {
|
||||
/// variant: Variant::Argon2i,
|
||||
/// version: Version::Version13,
|
||||
/// mem_cost: 4096,
|
||||
/// time_cost: 10,
|
||||
/// lanes: 1,
|
||||
/// thread_mode: ThreadMode::Sequential,
|
||||
/// secret: &[],
|
||||
/// ad: &[],
|
||||
/// hash_length: 32,
|
||||
/// };
|
||||
/// let encoded = argon2::hash_encoded(pwd, salt, &config).unwrap();
|
||||
/// ```
|
||||
#[deprecated(since = "0.2.0", note = "please use `hash_encoded` instead")]
|
||||
pub fn hash_encoded_std(
|
||||
variant: Variant,
|
||||
version: Version,
|
||||
mem_cost: u32,
|
||||
time_cost: u32,
|
||||
parallelism: u32,
|
||||
pwd: &[u8],
|
||||
salt: &[u8],
|
||||
hash_len: u32,
|
||||
) -> Result<String> {
|
||||
let threads = if cfg!(feature = "crossbeam-utils") { parallelism } else { 1 };
|
||||
let config = Config {
|
||||
variant,
|
||||
version,
|
||||
mem_cost,
|
||||
time_cost,
|
||||
lanes: parallelism,
|
||||
thread_mode: ThreadMode::from_threads(threads),
|
||||
secret: &[],
|
||||
ad: &[],
|
||||
hash_length: hash_len,
|
||||
};
|
||||
hash_encoded(pwd, salt, &config)
|
||||
}
|
||||
|
||||
/// Hashes the password and returns the hash as a vector.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Create a hash with the default configuration:
|
||||
///
|
||||
/// ```
|
||||
/// use argon2::{self, Config};
|
||||
///
|
||||
/// let pwd = b"password";
|
||||
/// let salt = b"somesalt";
|
||||
/// let config = Config::default();
|
||||
/// let vec = argon2::hash_raw(pwd, salt, &config).unwrap();
|
||||
/// ```
|
||||
///
|
||||
///
|
||||
/// Create an Argon2d hash with 4 lanes and parallel execution:
|
||||
///
|
||||
/// ```
|
||||
/// use argon2::{self, Config, ThreadMode, Variant};
|
||||
///
|
||||
/// let pwd = b"password";
|
||||
/// let salt = b"somesalt";
|
||||
/// let mut config = Config::default();
|
||||
/// config.variant = Variant::Argon2d;
|
||||
#[cfg_attr(feature = "crossbeam-utils", doc = "config.lanes = 4;")]
|
||||
#[cfg_attr(
|
||||
feature = "crossbeam-utils",
|
||||
doc = "config.thread_mode = ThreadMode::Parallel;"
|
||||
)]
|
||||
#[cfg_attr(not(feature = "crossbeam-utils"), doc = "config.lanes = 1;")]
|
||||
#[cfg_attr(
|
||||
not(feature = "crossbeam-utils"),
|
||||
doc = "config.thread_mode = ThreadMode::Sequential;"
|
||||
)]
|
||||
/// let vec = argon2::hash_raw(pwd, salt, &config).unwrap();
|
||||
/// ```
|
||||
pub fn hash_raw(pwd: &[u8], salt: &[u8], config: &Config) -> Result<Vec<u8>> {
|
||||
let context = Context::new(config.clone(), pwd, salt)?;
|
||||
let hash = run(&context);
|
||||
Ok(hash)
|
||||
}
|
||||
|
||||
/// Hashes the password using default settings and returns the hash as a vector.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use argon2;
|
||||
///
|
||||
/// let pwd = b"password";
|
||||
/// let salt = b"somesalt";
|
||||
/// let vec = argon2::hash_raw_defaults(pwd, salt).unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// The above rewritten using `hash_raw`:
|
||||
///
|
||||
/// ```
|
||||
/// use argon2::{self, Config};
|
||||
///
|
||||
/// let pwd = b"password";
|
||||
/// let salt = b"somesalt";
|
||||
/// let config = Config::default();
|
||||
/// let vec = argon2::hash_raw(pwd, salt, &config).unwrap();
|
||||
/// ```
|
||||
#[deprecated(since = "0.2.0", note = "please use `hash_raw` instead")]
|
||||
pub fn hash_raw_defaults(pwd: &[u8], salt: &[u8]) -> Result<Vec<u8>> {
|
||||
hash_raw(pwd, salt, &Config::default())
|
||||
}
|
||||
|
||||
/// Hashes the password and returns the hash as a vector (pre 0.2.0 `hash_raw`).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// use argon2::{self, Variant, Version};
|
||||
///
|
||||
/// let mem_cost = 4096;
|
||||
/// let time_cost = 10;
|
||||
/// let lanes = 1;
|
||||
/// let threads = 1;
|
||||
/// let pwd = b"password";
|
||||
/// let salt = b"somesalt";
|
||||
/// let secret = b"secret value";
|
||||
/// let ad = b"associated data";
|
||||
/// let hash_len = 32;
|
||||
/// let vec = argon2::hash_raw_old(Variant::Argon2i,
|
||||
/// Version::Version13,
|
||||
/// mem_cost,
|
||||
/// time_cost,
|
||||
/// lanes,
|
||||
/// threads,
|
||||
/// pwd,
|
||||
/// salt,
|
||||
/// secret,
|
||||
/// ad,
|
||||
/// hash_len).unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// The above rewritten using the new `hash_raw`:
|
||||
///
|
||||
/// ```
|
||||
/// use argon2::{self, Config, ThreadMode, Variant, Version};
|
||||
///
|
||||
/// let pwd = b"password";
|
||||
/// let salt = b"somesalt";
|
||||
/// let config = Config {
|
||||
/// variant: Variant::Argon2i,
|
||||
/// version: Version::Version13,
|
||||
/// mem_cost: 4096,
|
||||
/// time_cost: 10,
|
||||
/// lanes: 1,
|
||||
/// thread_mode: ThreadMode::Sequential,
|
||||
/// secret: b"secret value",
|
||||
/// ad: b"associated data",
|
||||
/// hash_length: 32,
|
||||
/// };
|
||||
/// let vec = argon2::hash_raw(pwd, salt, &config);
|
||||
/// ```
|
||||
#[deprecated(since = "0.2.0", note = "please use new `hash_raw` instead")]
|
||||
pub fn hash_raw_old(
|
||||
variant: Variant,
|
||||
version: Version,
|
||||
mem_cost: u32,
|
||||
time_cost: u32,
|
||||
lanes: u32,
|
||||
threads: u32,
|
||||
pwd: &[u8],
|
||||
salt: &[u8],
|
||||
secret: &[u8],
|
||||
ad: &[u8],
|
||||
hash_len: u32,
|
||||
) -> Result<Vec<u8>> {
|
||||
let threads = if cfg!(feature = "crossbeam-utils") { threads } else { 1 };
|
||||
let config = Config {
|
||||
variant,
|
||||
version,
|
||||
mem_cost,
|
||||
time_cost,
|
||||
lanes,
|
||||
thread_mode: ThreadMode::from_threads(threads),
|
||||
secret,
|
||||
ad,
|
||||
hash_length: hash_len,
|
||||
};
|
||||
hash_raw(pwd, salt, &config)
|
||||
}
|
||||
|
||||
/// Hashes the password and returns the hash as a vector (standard).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// use argon2::{self, Variant, Version};
|
||||
///
|
||||
/// let pwd = b"password";
|
||||
/// let salt = b"somesalt";
|
||||
/// let mem_cost = 4096;
|
||||
/// let time_cost = 10;
|
||||
/// let parallelism = 1;
|
||||
/// let hash_len = 32;
|
||||
/// let vec = argon2::hash_raw_std(Variant::Argon2i,
|
||||
/// Version::Version13,
|
||||
/// mem_cost,
|
||||
/// time_cost,
|
||||
/// parallelism,
|
||||
/// pwd,
|
||||
/// salt,
|
||||
/// hash_len).unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// The above rewritten using `hash_raw`:
|
||||
///
|
||||
/// ```
|
||||
/// use argon2::{self, Config, ThreadMode, Variant, Version};
|
||||
///
|
||||
/// let pwd = b"password";
|
||||
/// let salt = b"somesalt";
|
||||
/// let config = Config {
|
||||
/// variant: Variant::Argon2i,
|
||||
/// version: Version::Version13,
|
||||
/// mem_cost: 4096,
|
||||
/// time_cost: 10,
|
||||
/// lanes: 1,
|
||||
/// thread_mode: ThreadMode::Sequential,
|
||||
/// secret: &[],
|
||||
/// ad: &[],
|
||||
/// hash_length: 32,
|
||||
/// };
|
||||
/// let vec = argon2::hash_raw(pwd, salt, &config);
|
||||
/// ```
|
||||
#[deprecated(since = "0.2.0", note = "please use `hash_raw` instead")]
|
||||
pub fn hash_raw_std(
|
||||
variant: Variant,
|
||||
version: Version,
|
||||
mem_cost: u32,
|
||||
time_cost: u32,
|
||||
parallelism: u32,
|
||||
pwd: &[u8],
|
||||
salt: &[u8],
|
||||
hash_len: u32,
|
||||
) -> Result<Vec<u8>> {
|
||||
let threads = if cfg!(feature = "crossbeam-utils") { parallelism } else { 1 };
|
||||
let config = Config {
|
||||
variant,
|
||||
version,
|
||||
mem_cost,
|
||||
time_cost,
|
||||
lanes: parallelism,
|
||||
thread_mode: ThreadMode::from_threads(threads),
|
||||
secret: &[],
|
||||
ad: &[],
|
||||
hash_length: hash_len,
|
||||
};
|
||||
hash_raw(pwd, salt, &config)
|
||||
}
|
||||
|
||||
/// Verifies the password with the encoded hash.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use argon2;
|
||||
///
|
||||
/// let enc = "$argon2i$v=19$m=4096,t=3,p=1$c29tZXNhbHQ\
|
||||
/// $iWh06vD8Fy27wf9npn6FXWiCX4K6pW6Ue1Bnzz07Z8A";
|
||||
/// let pwd = b"password";
|
||||
/// let res = argon2::verify_encoded(enc, pwd).unwrap();
|
||||
/// assert!(res);
|
||||
/// ```
|
||||
pub fn verify_encoded(encoded: &str, pwd: &[u8]) -> Result<bool> {
|
||||
verify_encoded_ext(encoded, pwd, &[], &[])
|
||||
}
|
||||
|
||||
/// Verifies the password with the encoded hash, secret and associated data.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use argon2;
|
||||
///
|
||||
/// let enc = "$argon2i$v=19$m=4096,t=3,p=1$c29tZXNhbHQ\
|
||||
/// $OlcSvlN20Lz43sK3jhCJ9K04oejhiY0AmI+ck6nuETo";
|
||||
/// let pwd = b"password";
|
||||
/// let secret = b"secret";
|
||||
/// let ad = b"ad";
|
||||
/// let res = argon2::verify_encoded_ext(enc, pwd, secret, ad).unwrap();
|
||||
/// assert!(res);
|
||||
/// ```
|
||||
pub fn verify_encoded_ext(encoded: &str, pwd: &[u8], secret: &[u8], ad: &[u8]) -> Result<bool> {
|
||||
let decoded = encoding::decode_string(encoded)?;
|
||||
let threads = if cfg!(feature = "crossbeam-utils") { decoded.parallelism } else { 1 };
|
||||
let config = Config {
|
||||
variant: decoded.variant,
|
||||
version: decoded.version,
|
||||
mem_cost: decoded.mem_cost,
|
||||
time_cost: decoded.time_cost,
|
||||
lanes: decoded.parallelism,
|
||||
thread_mode: ThreadMode::from_threads(threads),
|
||||
secret,
|
||||
ad,
|
||||
hash_length: decoded.hash.len() as u32,
|
||||
};
|
||||
verify_raw(pwd, &decoded.salt, &decoded.hash, &config)
|
||||
}
|
||||
|
||||
/// Verifies the password with the supplied configuration.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// use argon2::{self, Config};
|
||||
///
|
||||
/// let pwd = b"password";
|
||||
/// let salt = b"somesalt";
|
||||
/// let hash = &[137, 104, 116, 234, 240, 252, 23, 45, 187, 193, 255, 103, 166,
|
||||
/// 126, 133, 93, 104, 130, 95, 130, 186, 165, 110, 148, 123, 80,
|
||||
/// 103, 207, 61, 59, 103, 192];
|
||||
/// let config = Config::default();
|
||||
/// let res = argon2::verify_raw(pwd, salt, hash, &config).unwrap();
|
||||
/// assert!(res);
|
||||
/// ```
|
||||
pub fn verify_raw(pwd: &[u8], salt: &[u8], hash: &[u8], config: &Config) -> Result<bool> {
|
||||
let config = Config {
|
||||
hash_length: hash.len() as u32,
|
||||
..config.clone()
|
||||
};
|
||||
let context = Context::new(config, pwd, salt)?;
|
||||
let calculated_hash = run(&context);
|
||||
Ok(constant_time_eq(hash, &calculated_hash))
|
||||
}
|
||||
|
||||
/// Verifies the password with the supplied settings (pre 0.2.0 `verify_raw`).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use argon2::{self, Variant, Version};
|
||||
///
|
||||
/// let pwd = b"password";
|
||||
/// let salt = b"somesalt";
|
||||
/// let hash = &[137, 104, 116, 234, 240, 252, 23, 45, 187, 193, 255, 103, 166,
|
||||
/// 126, 133, 93, 104, 130, 95, 130, 186, 165, 110, 148, 123, 80,
|
||||
/// 103, 207, 61, 59, 103, 192];
|
||||
/// let mem_cost = 4096;
|
||||
/// let time_cost = 3;
|
||||
/// let lanes = 1;
|
||||
/// let threads = 1;
|
||||
/// let secret = &[];
|
||||
/// let ad = &[];
|
||||
/// let res = argon2::verify_raw_old(Variant::Argon2i,
|
||||
/// Version::Version13,
|
||||
/// mem_cost,
|
||||
/// time_cost,
|
||||
/// lanes,
|
||||
/// threads,
|
||||
/// pwd,
|
||||
/// salt,
|
||||
/// secret,
|
||||
/// ad,
|
||||
/// hash).unwrap();
|
||||
/// assert!(res);
|
||||
/// ```
|
||||
///
|
||||
/// The above rewritten using the new `verify_raw`:
|
||||
///
|
||||
/// ```
|
||||
/// use argon2::{self, Config, ThreadMode, Variant, Version};
|
||||
///
|
||||
/// let pwd = b"password";
|
||||
/// let salt = b"somesalt";
|
||||
/// let hash = &[137, 104, 116, 234, 240, 252, 23, 45, 187, 193, 255, 103, 166,
|
||||
/// 126, 133, 93, 104, 130, 95, 130, 186, 165, 110, 148, 123, 80,
|
||||
/// 103, 207, 61, 59, 103, 192];
|
||||
/// let config = Config {
|
||||
/// variant: Variant::Argon2i,
|
||||
/// version: Version::Version13,
|
||||
/// mem_cost: 4096,
|
||||
/// time_cost: 3,
|
||||
/// lanes: 1,
|
||||
/// thread_mode: ThreadMode::Sequential,
|
||||
/// secret: &[],
|
||||
/// ad: &[],
|
||||
/// hash_length: hash.len() as u32,
|
||||
/// };
|
||||
/// let res = argon2::verify_raw(pwd, salt, hash, &config).unwrap();
|
||||
/// assert!(res);
|
||||
/// ```
|
||||
#[deprecated(since = "0.2.0", note = "please use new `verify_raw` instead")]
|
||||
pub fn verify_raw_old(
|
||||
variant: Variant,
|
||||
version: Version,
|
||||
mem_cost: u32,
|
||||
time_cost: u32,
|
||||
lanes: u32,
|
||||
threads: u32,
|
||||
pwd: &[u8],
|
||||
salt: &[u8],
|
||||
secret: &[u8],
|
||||
ad: &[u8],
|
||||
hash: &[u8],
|
||||
) -> Result<bool> {
|
||||
let threads = if cfg!(feature = "crossbeam-utils") { threads } else { 1 };
|
||||
let config = Config {
|
||||
variant,
|
||||
version,
|
||||
mem_cost,
|
||||
time_cost,
|
||||
lanes,
|
||||
thread_mode: ThreadMode::from_threads(threads),
|
||||
secret,
|
||||
ad,
|
||||
hash_length: hash.len() as u32,
|
||||
};
|
||||
verify_raw(pwd, salt, hash, &config)
|
||||
}
|
||||
|
||||
/// Verifies the password with the supplied settings (standard).
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
///
|
||||
/// ```
|
||||
/// use argon2::{self, Variant, Version};
|
||||
///
|
||||
/// let pwd = b"password";
|
||||
/// let salt = b"somesalt";
|
||||
/// let hash = &[137, 104, 116, 234, 240, 252, 23, 45, 187, 193, 255, 103, 166,
|
||||
/// 126, 133, 93, 104, 130, 95, 130, 186, 165, 110, 148, 123, 80,
|
||||
/// 103, 207, 61, 59, 103, 192];
|
||||
/// let mem_cost = 4096;
|
||||
/// let time_cost = 3;
|
||||
/// let parallelism = 1;
|
||||
/// let res = argon2::verify_raw_std(Variant::Argon2i,
|
||||
/// Version::Version13,
|
||||
/// mem_cost,
|
||||
/// time_cost,
|
||||
/// parallelism,
|
||||
/// pwd,
|
||||
/// salt,
|
||||
/// hash).unwrap();
|
||||
/// assert!(res);
|
||||
/// ```
|
||||
///
|
||||
/// The above rewritten using `verify_raw`:
|
||||
///
|
||||
/// ```
|
||||
/// use argon2::{self, Config, ThreadMode, Variant, Version};
|
||||
///
|
||||
/// let pwd = b"password";
|
||||
/// let salt = b"somesalt";
|
||||
/// let hash = &[137, 104, 116, 234, 240, 252, 23, 45, 187, 193, 255, 103, 166,
|
||||
/// 126, 133, 93, 104, 130, 95, 130, 186, 165, 110, 148, 123, 80,
|
||||
/// 103, 207, 61, 59, 103, 192];
|
||||
/// let config = Config {
|
||||
/// variant: Variant::Argon2i,
|
||||
/// version: Version::Version13,
|
||||
/// mem_cost: 4096,
|
||||
/// time_cost: 3,
|
||||
/// lanes: 1,
|
||||
/// thread_mode: ThreadMode::Sequential,
|
||||
/// secret: &[],
|
||||
/// ad: &[],
|
||||
/// hash_length: hash.len() as u32,
|
||||
/// };
|
||||
/// let res = argon2::verify_raw(pwd, salt, hash, &config).unwrap();
|
||||
/// assert!(res);
|
||||
/// ```
|
||||
#[deprecated(since = "0.2.0", note = "please use `verify_raw` instead")]
|
||||
pub fn verify_raw_std(
|
||||
variant: Variant,
|
||||
version: Version,
|
||||
mem_cost: u32,
|
||||
time_cost: u32,
|
||||
parallelism: u32,
|
||||
pwd: &[u8],
|
||||
salt: &[u8],
|
||||
hash: &[u8],
|
||||
) -> Result<bool> {
|
||||
let threads = if cfg!(feature = "crossbeam-utils") { parallelism } else { 1 };
|
||||
let config = Config {
|
||||
variant,
|
||||
version,
|
||||
mem_cost,
|
||||
time_cost,
|
||||
lanes: parallelism,
|
||||
thread_mode: ThreadMode::from_threads(threads),
|
||||
secret: &[],
|
||||
ad: &[],
|
||||
hash_length: hash.len() as u32,
|
||||
};
|
||||
verify_raw(pwd, salt, hash, &config)
|
||||
}
|
||||
|
||||
fn run(context: &Context) -> Vec<u8> {
|
||||
let mut memory = Memory::new(context.config.lanes, context.lane_length);
|
||||
core::initialize(context, &mut memory);
|
||||
core::fill_memory_blocks(context, &mut memory);
|
||||
core::finalize(context, &memory)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn single_thread_verification_multi_lane_hash() {
|
||||
/*
|
||||
let hash = hash_encoded(b"foo", b"abcdefghijklmnopqrstuvwxyz", &Config {
|
||||
lanes: 4, thread_mode: ThreadMode::Parallel,
|
||||
..Config::default()
|
||||
});
|
||||
*/
|
||||
let hash = "$argon2i$v=19$m=4096,t=3,p=4$YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo$BvBk2OaSofBHfbrUW61nHrWB/43xgfs/QJJ5DkMAd8I";
|
||||
verify_encoded(hash, b"foo").unwrap();
|
||||
}
|
||||
}
|
146
third_party/rust/rust-argon2/src/block.rs
vendored
146
third_party/rust/rust-argon2/src/block.rs
vendored
@ -1,146 +0,0 @@
|
||||
// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use crate::common;
|
||||
use std::fmt;
|
||||
use std::fmt::Debug;
|
||||
use std::ops::{BitXorAssign, Index, IndexMut};
|
||||
|
||||
/// Structure for the (1KB) memory block implemented as 128 64-bit words.
|
||||
pub struct Block([u64; common::QWORDS_IN_BLOCK]);
|
||||
|
||||
impl Block {
|
||||
/// Gets the byte slice representation of the block.
|
||||
pub fn as_u8(&self) -> &[u8] {
|
||||
let bytes: &[u8; common::BLOCK_SIZE] = unsafe {
|
||||
&*(&self.0 as *const [u64; common::QWORDS_IN_BLOCK] as *const [u8; common::BLOCK_SIZE])
|
||||
};
|
||||
bytes
|
||||
}
|
||||
|
||||
/// Gets the mutable byte slice representation of the block.
|
||||
pub fn as_u8_mut(&mut self) -> &mut [u8] {
|
||||
let bytes: &mut [u8; common::BLOCK_SIZE] = unsafe {
|
||||
&mut *(&mut self.0 as *mut [u64; common::QWORDS_IN_BLOCK]
|
||||
as *mut [u8; common::BLOCK_SIZE])
|
||||
};
|
||||
bytes
|
||||
}
|
||||
|
||||
/// Copies self to destination.
|
||||
pub fn copy_to(&self, dst: &mut Block) {
|
||||
for (d, s) in dst.0.iter_mut().zip(self.0.iter()) {
|
||||
*d = *s
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates a new block filled with zeros.
|
||||
pub fn zero() -> Block {
|
||||
Block([0u64; common::QWORDS_IN_BLOCK])
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> BitXorAssign<&'a Block> for Block {
|
||||
fn bitxor_assign(&mut self, rhs: &Block) {
|
||||
for (s, r) in self.0.iter_mut().zip(rhs.0.iter()) {
|
||||
*s ^= *r
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for Block {
|
||||
fn clone(&self) -> Block {
|
||||
Block(self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Block {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
fmt.debug_list().entries(self.0.iter()).finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Block {}
|
||||
|
||||
impl Index<usize> for Block {
|
||||
type Output = u64;
|
||||
fn index(&self, index: usize) -> &u64 {
|
||||
&self.0[index]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<usize> for Block {
|
||||
fn index_mut(&mut self, index: usize) -> &mut u64 {
|
||||
&mut self.0[index]
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for Block {
|
||||
fn eq(&self, other: &Block) -> bool {
|
||||
let mut equal = true;
|
||||
for (s, o) in self.0.iter().zip(other.0.iter()) {
|
||||
if s != o {
|
||||
equal = false;
|
||||
}
|
||||
}
|
||||
equal
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::block::Block;
|
||||
use crate::common;
|
||||
|
||||
#[test]
|
||||
fn as_u8_returns_correct_slice() {
|
||||
let block = Block::zero();
|
||||
let expected = vec![0u8; 1024];
|
||||
let actual = block.as_u8();
|
||||
assert_eq!(actual, expected.as_slice());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn as_u8_mut_returns_correct_slice() {
|
||||
let mut block = Block::zero();
|
||||
let mut expected = vec![0u8; 1024];
|
||||
let actual = block.as_u8_mut();
|
||||
assert_eq!(actual, expected.as_mut_slice());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bitxor_assign_updates_lhs() {
|
||||
let mut lhs = Block([0u64; common::QWORDS_IN_BLOCK]);
|
||||
let rhs = Block([1u64; common::QWORDS_IN_BLOCK]);
|
||||
lhs ^= &rhs;
|
||||
assert_eq!(lhs, rhs);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copy_to_copies_block() {
|
||||
let src = Block([1u64; common::QWORDS_IN_BLOCK]);
|
||||
let mut dst = Block([0u64; common::QWORDS_IN_BLOCK]);
|
||||
src.copy_to(&mut dst);
|
||||
assert_eq!(dst, src);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn clone_clones_block() {
|
||||
let orig = Block([1u64; common::QWORDS_IN_BLOCK]);
|
||||
let copy = orig.clone();
|
||||
assert_eq!(copy, orig);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_creates_block_will_all_zeros() {
|
||||
let expected = Block([0u64; common::QWORDS_IN_BLOCK]);
|
||||
let actual = Block::zero();
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
}
|
92
third_party/rust/rust-argon2/src/common.rs
vendored
92
third_party/rust/rust-argon2/src/common.rs
vendored
@ -1,92 +0,0 @@
|
||||
// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/// Default number of lanes (degree of parallelism).
|
||||
pub const DEF_LANES: u32 = 1;
|
||||
|
||||
/// Minimum number of lanes (degree of parallelism).
|
||||
pub const MIN_LANES: u32 = 1;
|
||||
|
||||
/// Maximum number of lanes (degree of parallelism).
|
||||
pub const MAX_LANES: u32 = 0x00FF_FFFF;
|
||||
|
||||
/// Number of synchronization points between lanes per pass.
|
||||
pub const SYNC_POINTS: u32 = 4;
|
||||
|
||||
/// Default digest size in bytes.
|
||||
pub const DEF_HASH_LENGTH: u32 = 32;
|
||||
|
||||
/// Minimum digest size in bytes.
|
||||
pub const MIN_HASH_LENGTH: u32 = 4;
|
||||
|
||||
/// Maximum digest size in bytes.
|
||||
pub const MAX_HASH_LENGTH: u32 = 0xFFFF_FFFF;
|
||||
|
||||
/// Default number of memory blocks (2^12).
|
||||
pub const DEF_MEMORY: u32 = 4096;
|
||||
|
||||
/// Minimum number of memory blocks (each of BLOCK_SIZE bytes).
|
||||
pub const MIN_MEMORY: u32 = 2 * SYNC_POINTS;
|
||||
|
||||
/// Maximum number of memory blocks (each of BLOCK_SIZE bytes).
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
pub const MAX_MEMORY: u32 = 0x200000;
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
pub const MAX_MEMORY: u32 = 0xFFFF_FFFF;
|
||||
|
||||
/// Default number of passes.
|
||||
pub const DEF_TIME: u32 = 3;
|
||||
|
||||
/// Minimum number of passes
|
||||
pub const MIN_TIME: u32 = 1;
|
||||
|
||||
/// Maximum number of passes.
|
||||
pub const MAX_TIME: u32 = 0xFFFF_FFFF;
|
||||
|
||||
/// Minimum password length in bytes.
|
||||
pub const MIN_PWD_LENGTH: u32 = 0;
|
||||
|
||||
/// Maximum password length in bytes.
|
||||
pub const MAX_PWD_LENGTH: u32 = 0xFFFF_FFFF;
|
||||
|
||||
/// Minimum associated data length in bytes.
|
||||
pub const MIN_AD_LENGTH: u32 = 0;
|
||||
|
||||
/// Maximum associated data length in bytes.
|
||||
pub const MAX_AD_LENGTH: u32 = 0xFFFF_FFFF;
|
||||
|
||||
/// Minimum salt length in bytes.
|
||||
pub const MIN_SALT_LENGTH: u32 = 8;
|
||||
|
||||
/// Maximum salt length in bytes.
|
||||
pub const MAX_SALT_LENGTH: u32 = 0xFFFF_FFFF;
|
||||
|
||||
/// Minimum key length in bytes.
|
||||
pub const MIN_SECRET_LENGTH: u32 = 0;
|
||||
|
||||
/// Maximum key length in bytes.
|
||||
pub const MAX_SECRET_LENGTH: u32 = 0xFFFF_FFFF;
|
||||
|
||||
/// Memory block size in bytes.
|
||||
pub const BLOCK_SIZE: usize = 1024;
|
||||
|
||||
/// Number of quad words in a block.
|
||||
pub const QWORDS_IN_BLOCK: usize = BLOCK_SIZE / 8;
|
||||
|
||||
/// Number of pseudo-random values generated by one call to Blake in Argon2i
|
||||
/// to generate reference block positions.
|
||||
pub const ADDRESSES_IN_BLOCK: u32 = 128;
|
||||
|
||||
/// Pre-hashing digest length.
|
||||
pub const PREHASH_DIGEST_LENGTH: usize = 64;
|
||||
|
||||
/// Pre-hashing digest length with extension.
|
||||
pub const PREHASH_SEED_LENGTH: usize = 72;
|
||||
|
||||
/// Blake2b output length in bytes.
|
||||
pub const BLAKE2B_OUT_LENGTH: usize = 64;
|
105
third_party/rust/rust-argon2/src/config.rs
vendored
105
third_party/rust/rust-argon2/src/config.rs
vendored
@ -1,105 +0,0 @@
|
||||
// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use crate::common;
|
||||
use crate::thread_mode::ThreadMode;
|
||||
use crate::variant::Variant;
|
||||
use crate::version::Version;
|
||||
|
||||
/// Structure containing configuration settings.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use argon2::{Config, ThreadMode, Variant, Version};
|
||||
///
|
||||
/// let config = Config::default();
|
||||
/// assert_eq!(config.ad, &[]);
|
||||
/// assert_eq!(config.hash_length, 32);
|
||||
/// assert_eq!(config.lanes, 1);
|
||||
/// assert_eq!(config.mem_cost, 4096);
|
||||
/// assert_eq!(config.secret, &[]);
|
||||
/// assert_eq!(config.thread_mode, ThreadMode::Sequential);
|
||||
/// assert_eq!(config.time_cost, 3);
|
||||
/// assert_eq!(config.variant, Variant::Argon2i);
|
||||
/// assert_eq!(config.version, Version::Version13);
|
||||
/// ```
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Config<'a> {
|
||||
/// The associated data.
|
||||
pub ad: &'a [u8],
|
||||
|
||||
/// The length of the resulting hash.
|
||||
pub hash_length: u32,
|
||||
|
||||
/// The number of lanes.
|
||||
pub lanes: u32,
|
||||
|
||||
/// The amount of memory requested (KB).
|
||||
pub mem_cost: u32,
|
||||
|
||||
/// The key.
|
||||
pub secret: &'a [u8],
|
||||
|
||||
/// The thread mode.
|
||||
pub thread_mode: ThreadMode,
|
||||
|
||||
/// The number of passes.
|
||||
pub time_cost: u32,
|
||||
|
||||
/// The variant.
|
||||
pub variant: Variant,
|
||||
|
||||
/// The version number.
|
||||
pub version: Version,
|
||||
}
|
||||
|
||||
impl<'a> Config<'a> {
|
||||
pub fn uses_sequential(&self) -> bool {
|
||||
self.thread_mode == ThreadMode::Sequential || self.lanes == 1
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Default for Config<'a> {
|
||||
fn default() -> Config<'a> {
|
||||
Config {
|
||||
ad: &[],
|
||||
hash_length: common::DEF_HASH_LENGTH,
|
||||
lanes: common::DEF_LANES,
|
||||
mem_cost: common::DEF_MEMORY,
|
||||
secret: &[],
|
||||
thread_mode: ThreadMode::default(),
|
||||
time_cost: common::DEF_TIME,
|
||||
variant: Variant::default(),
|
||||
version: Version::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::thread_mode::ThreadMode;
|
||||
use crate::variant::Variant;
|
||||
use crate::version::Version;
|
||||
|
||||
#[test]
|
||||
fn default_returns_correct_instance() {
|
||||
let config = Config::default();
|
||||
assert_eq!(config.ad, &[]);
|
||||
assert_eq!(config.hash_length, 32);
|
||||
assert_eq!(config.lanes, 1);
|
||||
assert_eq!(config.mem_cost, 4096);
|
||||
assert_eq!(config.secret, &[]);
|
||||
assert_eq!(config.thread_mode, ThreadMode::Sequential);
|
||||
assert_eq!(config.time_cost, 3);
|
||||
assert_eq!(config.variant, Variant::Argon2i);
|
||||
assert_eq!(config.version, Version::Version13);
|
||||
}
|
||||
}
|
234
third_party/rust/rust-argon2/src/context.rs
vendored
234
third_party/rust/rust-argon2/src/context.rs
vendored
@ -1,234 +0,0 @@
|
||||
// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use crate::common;
|
||||
use crate::config::Config;
|
||||
use crate::error::Error;
|
||||
use crate::result::Result;
|
||||
|
||||
/// Structure containing settings for the Argon2 algorithm. A combination of
|
||||
/// the original argon2_context and argon2_instance_t.
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub struct Context<'a> {
|
||||
/// The config for this context.
|
||||
pub config: Config<'a>,
|
||||
|
||||
/// The length of a lane.
|
||||
pub lane_length: u32,
|
||||
|
||||
/// The number of memory blocks.
|
||||
pub memory_blocks: u32,
|
||||
|
||||
/// The password.
|
||||
pub pwd: &'a [u8],
|
||||
|
||||
/// The salt.
|
||||
pub salt: &'a [u8],
|
||||
|
||||
/// The length of a segment.
|
||||
pub segment_length: u32,
|
||||
}
|
||||
|
||||
impl<'a> Context<'a> {
|
||||
/// Attempts to create a new context.
|
||||
pub fn new(config: Config<'a>, pwd: &'a [u8], salt: &'a [u8]) -> Result<Context<'a>> {
|
||||
if config.lanes < common::MIN_LANES {
|
||||
return Err(Error::LanesTooFew);
|
||||
} else if config.lanes > common::MAX_LANES {
|
||||
return Err(Error::LanesTooMany);
|
||||
}
|
||||
|
||||
let lanes = config.lanes;
|
||||
if config.mem_cost < common::MIN_MEMORY {
|
||||
return Err(Error::MemoryTooLittle);
|
||||
} else if config.mem_cost > common::MAX_MEMORY {
|
||||
return Err(Error::MemoryTooMuch);
|
||||
} else if config.mem_cost < 8 * lanes {
|
||||
return Err(Error::MemoryTooLittle);
|
||||
}
|
||||
|
||||
if config.time_cost < common::MIN_TIME {
|
||||
return Err(Error::TimeTooSmall);
|
||||
} else if config.time_cost > common::MAX_TIME {
|
||||
return Err(Error::TimeTooLarge);
|
||||
}
|
||||
|
||||
let pwd_len = pwd.len();
|
||||
if pwd_len < common::MIN_PWD_LENGTH as usize {
|
||||
return Err(Error::PwdTooShort);
|
||||
} else if pwd_len > common::MAX_PWD_LENGTH as usize {
|
||||
return Err(Error::PwdTooLong);
|
||||
}
|
||||
|
||||
let salt_len = salt.len();
|
||||
if salt_len < common::MIN_SALT_LENGTH as usize {
|
||||
return Err(Error::SaltTooShort);
|
||||
} else if salt_len > common::MAX_SALT_LENGTH as usize {
|
||||
return Err(Error::SaltTooLong);
|
||||
}
|
||||
|
||||
let secret_len = config.secret.len();
|
||||
if secret_len < common::MIN_SECRET_LENGTH as usize {
|
||||
return Err(Error::SecretTooShort);
|
||||
} else if secret_len > common::MAX_SECRET_LENGTH as usize {
|
||||
return Err(Error::SecretTooLong);
|
||||
}
|
||||
|
||||
let ad_len = config.ad.len();
|
||||
if ad_len < common::MIN_AD_LENGTH as usize {
|
||||
return Err(Error::AdTooShort);
|
||||
} else if ad_len > common::MAX_AD_LENGTH as usize {
|
||||
return Err(Error::AdTooLong);
|
||||
}
|
||||
|
||||
if config.hash_length < common::MIN_HASH_LENGTH {
|
||||
return Err(Error::OutputTooShort);
|
||||
} else if config.hash_length > common::MAX_HASH_LENGTH {
|
||||
return Err(Error::OutputTooLong);
|
||||
}
|
||||
|
||||
let mut memory_blocks = config.mem_cost;
|
||||
if memory_blocks < 2 * common::SYNC_POINTS * lanes {
|
||||
memory_blocks = 2 * common::SYNC_POINTS * lanes;
|
||||
}
|
||||
|
||||
let segment_length = memory_blocks / (lanes * common::SYNC_POINTS);
|
||||
let memory_blocks = segment_length * (lanes * common::SYNC_POINTS);
|
||||
let lane_length = segment_length * common::SYNC_POINTS;
|
||||
|
||||
Ok(Context {
|
||||
config,
|
||||
lane_length,
|
||||
memory_blocks,
|
||||
pwd,
|
||||
salt,
|
||||
segment_length,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::context::Context;
|
||||
use crate::error::Error;
|
||||
use crate::thread_mode::ThreadMode;
|
||||
use crate::variant::Variant;
|
||||
use crate::version::Version;
|
||||
|
||||
#[test]
|
||||
fn new_returns_correct_instance() {
|
||||
let config = Config {
|
||||
ad: b"additionaldata",
|
||||
hash_length: 32,
|
||||
lanes: 4,
|
||||
mem_cost: 4096,
|
||||
secret: b"secret",
|
||||
thread_mode: ThreadMode::Sequential,
|
||||
time_cost: 3,
|
||||
variant: Variant::Argon2i,
|
||||
version: Version::Version13,
|
||||
};
|
||||
let pwd = b"password";
|
||||
let salt = b"somesalt";
|
||||
let result = Context::new(config.clone(), pwd, salt);
|
||||
assert!(result.is_ok());
|
||||
|
||||
let context = result.unwrap();
|
||||
assert_eq!(context.config, config);
|
||||
assert_eq!(context.pwd, pwd);
|
||||
assert_eq!(context.salt, salt);
|
||||
assert_eq!(context.memory_blocks, 4096);
|
||||
assert_eq!(context.segment_length, 256);
|
||||
assert_eq!(context.lane_length, 1024);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_with_too_little_mem_cost_returns_correct_error() {
|
||||
let config = Config {
|
||||
mem_cost: 7,
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(
|
||||
Context::new(config, &[0u8; 8], &[0u8; 8]),
|
||||
Err(Error::MemoryTooLittle)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_with_less_than_8_x_lanes_mem_cost_returns_correct_error() {
|
||||
let config = Config {
|
||||
lanes: 4,
|
||||
mem_cost: 31,
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(
|
||||
Context::new(config, &[0u8; 8], &[0u8; 8]),
|
||||
Err(Error::MemoryTooLittle)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_with_too_small_time_cost_returns_correct_error() {
|
||||
let config = Config {
|
||||
time_cost: 0,
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(
|
||||
Context::new(config, &[0u8; 8], &[0u8; 8]),
|
||||
Err(Error::TimeTooSmall)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_with_too_few_lanes_returns_correct_error() {
|
||||
let config = Config {
|
||||
lanes: 0,
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(
|
||||
Context::new(config, &[0u8; 8], &[0u8; 8]),
|
||||
Err(Error::LanesTooFew)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_with_too_many_lanes_returns_correct_error() {
|
||||
let config = Config {
|
||||
lanes: 1 << 24,
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(
|
||||
Context::new(config, &[0u8; 8], &[0u8; 8]),
|
||||
Err(Error::LanesTooMany)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_with_too_short_salt_returns_correct_error() {
|
||||
let config = Default::default();
|
||||
let salt = [0u8; 7];
|
||||
assert_eq!(
|
||||
Context::new(config, &[0u8; 8], &salt),
|
||||
Err(Error::SaltTooShort)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_with_too_short_hash_length_returns_correct_error() {
|
||||
let config = Config {
|
||||
hash_length: 3,
|
||||
..Default::default()
|
||||
};
|
||||
assert_eq!(
|
||||
Context::new(config, &[0u8; 8], &[0u8; 8]),
|
||||
Err(Error::OutputTooShort)
|
||||
);
|
||||
}
|
||||
}
|
467
third_party/rust/rust-argon2/src/core.rs
vendored
467
third_party/rust/rust-argon2/src/core.rs
vendored
@ -1,467 +0,0 @@
|
||||
// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use crate::block::Block;
|
||||
use crate::common;
|
||||
use crate::context::Context;
|
||||
use crate::memory::Memory;
|
||||
use crate::variant::Variant;
|
||||
use crate::version::Version;
|
||||
use blake2b_simd::Params;
|
||||
#[cfg(feature = "crossbeam-utils")]
|
||||
use crossbeam_utils::thread::scope;
|
||||
|
||||
/// Position of the block currently being operated on.
|
||||
#[derive(Clone, Debug)]
|
||||
struct Position {
|
||||
pass: u32,
|
||||
lane: u32,
|
||||
slice: u32,
|
||||
index: u32,
|
||||
}
|
||||
|
||||
/// Initializes the memory.
|
||||
pub fn initialize(context: &Context, memory: &mut Memory) {
|
||||
fill_first_blocks(context, memory, &mut h0(context));
|
||||
}
|
||||
|
||||
/// Fills all the memory blocks.
|
||||
pub fn fill_memory_blocks(context: &Context, memory: &mut Memory) {
|
||||
if context.config.uses_sequential() {
|
||||
fill_memory_blocks_st(context, memory);
|
||||
} else {
|
||||
fill_memory_blocks_mt(context, memory);
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates the final hash and returns it.
|
||||
pub fn finalize(context: &Context, memory: &Memory) -> Vec<u8> {
|
||||
let mut blockhash = memory[context.lane_length - 1].clone();
|
||||
for l in 1..context.config.lanes {
|
||||
let last_block_in_lane = l * context.lane_length + (context.lane_length - 1);
|
||||
blockhash ^= &memory[last_block_in_lane];
|
||||
}
|
||||
|
||||
let mut hash = vec![0u8; context.config.hash_length as usize];
|
||||
hprime(hash.as_mut_slice(), blockhash.as_u8());
|
||||
hash
|
||||
}
|
||||
|
||||
fn blake2b(out: &mut [u8], input: &[&[u8]]) {
|
||||
let mut blake = Params::new().hash_length(out.len()).to_state();
|
||||
for slice in input {
|
||||
blake.update(slice);
|
||||
}
|
||||
out.copy_from_slice(blake.finalize().as_bytes());
|
||||
}
|
||||
|
||||
fn f_bla_mka(x: u64, y: u64) -> u64 {
|
||||
let m = 0xFFFF_FFFFu64;
|
||||
let xy = (x & m) * (y & m);
|
||||
x.wrapping_add(y.wrapping_add(xy.wrapping_add(xy)))
|
||||
}
|
||||
|
||||
fn fill_block(prev_block: &Block, ref_block: &Block, next_block: &mut Block, with_xor: bool) {
|
||||
let mut block_r = ref_block.clone();
|
||||
block_r ^= prev_block;
|
||||
let mut block_tmp = block_r.clone();
|
||||
|
||||
// Now block_r = ref_block + prev_block and block_tmp = ref_block + prev_block
|
||||
if with_xor {
|
||||
// Saving the next block contents for XOR over
|
||||
block_tmp ^= next_block;
|
||||
// Now block_r = ref_block + prev_block and
|
||||
// block_tmp = ref_block + prev_block + next_block
|
||||
}
|
||||
|
||||
// Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then
|
||||
// (16,17,..31)... finally (112,113,...127)
|
||||
for i in 0..8 {
|
||||
let mut v0 = block_r[16 * i];
|
||||
let mut v1 = block_r[16 * i + 1];
|
||||
let mut v2 = block_r[16 * i + 2];
|
||||
let mut v3 = block_r[16 * i + 3];
|
||||
let mut v4 = block_r[16 * i + 4];
|
||||
let mut v5 = block_r[16 * i + 5];
|
||||
let mut v6 = block_r[16 * i + 6];
|
||||
let mut v7 = block_r[16 * i + 7];
|
||||
let mut v8 = block_r[16 * i + 8];
|
||||
let mut v9 = block_r[16 * i + 9];
|
||||
let mut v10 = block_r[16 * i + 10];
|
||||
let mut v11 = block_r[16 * i + 11];
|
||||
let mut v12 = block_r[16 * i + 12];
|
||||
let mut v13 = block_r[16 * i + 13];
|
||||
let mut v14 = block_r[16 * i + 14];
|
||||
let mut v15 = block_r[16 * i + 15];
|
||||
|
||||
p(
|
||||
&mut v0, &mut v1, &mut v2, &mut v3, &mut v4, &mut v5, &mut v6, &mut v7, &mut v8,
|
||||
&mut v9, &mut v10, &mut v11, &mut v12, &mut v13, &mut v14, &mut v15,
|
||||
);
|
||||
|
||||
block_r[16 * i] = v0;
|
||||
block_r[16 * i + 1] = v1;
|
||||
block_r[16 * i + 2] = v2;
|
||||
block_r[16 * i + 3] = v3;
|
||||
block_r[16 * i + 4] = v4;
|
||||
block_r[16 * i + 5] = v5;
|
||||
block_r[16 * i + 6] = v6;
|
||||
block_r[16 * i + 7] = v7;
|
||||
block_r[16 * i + 8] = v8;
|
||||
block_r[16 * i + 9] = v9;
|
||||
block_r[16 * i + 10] = v10;
|
||||
block_r[16 * i + 11] = v11;
|
||||
block_r[16 * i + 12] = v12;
|
||||
block_r[16 * i + 13] = v13;
|
||||
block_r[16 * i + 14] = v14;
|
||||
block_r[16 * i + 15] = v15;
|
||||
}
|
||||
|
||||
// Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then
|
||||
// (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127)
|
||||
for i in 0..8 {
|
||||
let mut v0 = block_r[2 * i];
|
||||
let mut v1 = block_r[2 * i + 1];
|
||||
let mut v2 = block_r[2 * i + 16];
|
||||
let mut v3 = block_r[2 * i + 17];
|
||||
let mut v4 = block_r[2 * i + 32];
|
||||
let mut v5 = block_r[2 * i + 33];
|
||||
let mut v6 = block_r[2 * i + 48];
|
||||
let mut v7 = block_r[2 * i + 49];
|
||||
let mut v8 = block_r[2 * i + 64];
|
||||
let mut v9 = block_r[2 * i + 65];
|
||||
let mut v10 = block_r[2 * i + 80];
|
||||
let mut v11 = block_r[2 * i + 81];
|
||||
let mut v12 = block_r[2 * i + 96];
|
||||
let mut v13 = block_r[2 * i + 97];
|
||||
let mut v14 = block_r[2 * i + 112];
|
||||
let mut v15 = block_r[2 * i + 113];
|
||||
|
||||
p(
|
||||
&mut v0, &mut v1, &mut v2, &mut v3, &mut v4, &mut v5, &mut v6, &mut v7, &mut v8,
|
||||
&mut v9, &mut v10, &mut v11, &mut v12, &mut v13, &mut v14, &mut v15,
|
||||
);
|
||||
|
||||
block_r[2 * i] = v0;
|
||||
block_r[2 * i + 1] = v1;
|
||||
block_r[2 * i + 16] = v2;
|
||||
block_r[2 * i + 17] = v3;
|
||||
block_r[2 * i + 32] = v4;
|
||||
block_r[2 * i + 33] = v5;
|
||||
block_r[2 * i + 48] = v6;
|
||||
block_r[2 * i + 49] = v7;
|
||||
block_r[2 * i + 64] = v8;
|
||||
block_r[2 * i + 65] = v9;
|
||||
block_r[2 * i + 80] = v10;
|
||||
block_r[2 * i + 81] = v11;
|
||||
block_r[2 * i + 96] = v12;
|
||||
block_r[2 * i + 97] = v13;
|
||||
block_r[2 * i + 112] = v14;
|
||||
block_r[2 * i + 113] = v15;
|
||||
}
|
||||
|
||||
block_tmp.copy_to(next_block);
|
||||
*next_block ^= &block_r;
|
||||
}
|
||||
|
||||
fn fill_first_blocks(context: &Context, memory: &mut Memory, h0: &mut [u8]) {
|
||||
for lane in 0..context.config.lanes {
|
||||
let start = common::PREHASH_DIGEST_LENGTH;
|
||||
// H'(H0||0||i)
|
||||
h0[start..(start + 4)].clone_from_slice(&u32::to_le_bytes(0));
|
||||
h0[(start + 4)..(start + 8)].clone_from_slice(&u32::to_le_bytes(lane));
|
||||
hprime(memory[(lane, 0)].as_u8_mut(), &h0);
|
||||
|
||||
// H'(H0||1||i)
|
||||
h0[start..(start + 4)].clone_from_slice(&u32::to_le_bytes(1));
|
||||
hprime(memory[(lane, 1)].as_u8_mut(), &h0);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "crossbeam-utils")]
|
||||
fn fill_memory_blocks_mt(context: &Context, memory: &mut Memory) {
|
||||
for p in 0..context.config.time_cost {
|
||||
for s in 0..common::SYNC_POINTS {
|
||||
let _ = scope(|scoped| {
|
||||
for (l, mem) in (0..context.config.lanes).zip(memory.as_lanes_mut()) {
|
||||
let position = Position {
|
||||
pass: p,
|
||||
lane: l,
|
||||
slice: s,
|
||||
index: 0,
|
||||
};
|
||||
scoped.spawn(move |_| {
|
||||
fill_segment(context, &position, mem);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "crossbeam-utils"))]
|
||||
fn fill_memory_blocks_mt(_: &Context, _: &mut Memory) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn fill_memory_blocks_st(context: &Context, memory: &mut Memory) {
|
||||
for p in 0..context.config.time_cost {
|
||||
for s in 0..common::SYNC_POINTS {
|
||||
for l in 0..context.config.lanes {
|
||||
let position = Position {
|
||||
pass: p,
|
||||
lane: l,
|
||||
slice: s,
|
||||
index: 0,
|
||||
};
|
||||
fill_segment(context, &position, memory);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_segment(context: &Context, position: &Position, memory: &mut Memory) {
|
||||
let mut position = position.clone();
|
||||
let data_independent_addressing = (context.config.variant == Variant::Argon2i)
|
||||
|| (context.config.variant == Variant::Argon2id && position.pass == 0)
|
||||
&& (position.slice < (common::SYNC_POINTS / 2));
|
||||
let zero_block = Block::zero();
|
||||
let mut input_block = Block::zero();
|
||||
let mut address_block = Block::zero();
|
||||
|
||||
if data_independent_addressing {
|
||||
input_block[0] = position.pass as u64;
|
||||
input_block[1] = position.lane as u64;
|
||||
input_block[2] = position.slice as u64;
|
||||
input_block[3] = context.memory_blocks as u64;
|
||||
input_block[4] = context.config.time_cost as u64;
|
||||
input_block[5] = context.config.variant.as_u64();
|
||||
}
|
||||
|
||||
let mut starting_index = 0u32;
|
||||
|
||||
if position.pass == 0 && position.slice == 0 {
|
||||
starting_index = 2;
|
||||
|
||||
// Don't forget to generate the first block of addresses:
|
||||
if data_independent_addressing {
|
||||
next_addresses(&mut address_block, &mut input_block, &zero_block);
|
||||
}
|
||||
}
|
||||
|
||||
let mut curr_offset = (position.lane * context.lane_length)
|
||||
+ (position.slice * context.segment_length)
|
||||
+ starting_index;
|
||||
|
||||
let mut prev_offset = if curr_offset % context.lane_length == 0 {
|
||||
// Last block in this lane
|
||||
curr_offset + context.lane_length - 1
|
||||
} else {
|
||||
curr_offset - 1
|
||||
};
|
||||
|
||||
let mut pseudo_rand;
|
||||
for i in starting_index..context.segment_length {
|
||||
// 1.1 Rotating prev_offset if needed
|
||||
if curr_offset % context.lane_length == 1 {
|
||||
prev_offset = curr_offset - 1;
|
||||
}
|
||||
|
||||
// 1.2 Computing the index of the reference block
|
||||
// 1.2.1 Taking pseudo-random value from the previous block
|
||||
if data_independent_addressing {
|
||||
if i % common::ADDRESSES_IN_BLOCK == 0 {
|
||||
next_addresses(&mut address_block, &mut input_block, &zero_block);
|
||||
}
|
||||
pseudo_rand = address_block[(i % common::ADDRESSES_IN_BLOCK) as usize];
|
||||
} else {
|
||||
pseudo_rand = memory[(prev_offset)][0];
|
||||
}
|
||||
|
||||
// 1.2.2 Computing the lane of the reference block
|
||||
// If (position.pass == 0) && (position.slice == 0): can not reference other lanes yet
|
||||
let ref_lane = if (position.pass == 0) && (position.slice == 0) {
|
||||
position.lane as u64
|
||||
} else {
|
||||
(pseudo_rand >> 32) % context.config.lanes as u64
|
||||
};
|
||||
|
||||
// 1.2.3 Computing the number of possible reference block within the lane.
|
||||
position.index = i;
|
||||
let pseudo_rand_u32 = (pseudo_rand & 0xFFFF_FFFF) as u32;
|
||||
let same_lane = ref_lane == (position.lane as u64);
|
||||
let ref_index = index_alpha(context, &position, pseudo_rand_u32, same_lane);
|
||||
|
||||
// 2 Creating a new block
|
||||
let index = context.lane_length as u64 * ref_lane + ref_index as u64;
|
||||
let mut curr_block = memory[curr_offset].clone();
|
||||
{
|
||||
let prev_block = &memory[prev_offset];
|
||||
let ref_block = &memory[index];
|
||||
if context.config.version == Version::Version10 || position.pass == 0 {
|
||||
fill_block(prev_block, ref_block, &mut curr_block, false);
|
||||
} else {
|
||||
fill_block(prev_block, ref_block, &mut curr_block, true);
|
||||
}
|
||||
}
|
||||
|
||||
memory[curr_offset] = curr_block;
|
||||
curr_offset += 1;
|
||||
prev_offset += 1;
|
||||
}
|
||||
}
|
||||
|
||||
fn g(a: &mut u64, b: &mut u64, c: &mut u64, d: &mut u64) {
|
||||
*a = f_bla_mka(*a, *b);
|
||||
*d = rotr64(*d ^ *a, 32);
|
||||
*c = f_bla_mka(*c, *d);
|
||||
*b = rotr64(*b ^ *c, 24);
|
||||
*a = f_bla_mka(*a, *b);
|
||||
*d = rotr64(*d ^ *a, 16);
|
||||
*c = f_bla_mka(*c, *d);
|
||||
*b = rotr64(*b ^ *c, 63);
|
||||
}
|
||||
|
||||
fn h0(context: &Context) -> [u8; common::PREHASH_SEED_LENGTH] {
|
||||
let input = [
|
||||
&u32::to_le_bytes(context.config.lanes),
|
||||
&u32::to_le_bytes(context.config.hash_length),
|
||||
&u32::to_le_bytes(context.config.mem_cost),
|
||||
&u32::to_le_bytes(context.config.time_cost),
|
||||
&u32::to_le_bytes(context.config.version.as_u32()),
|
||||
&u32::to_le_bytes(context.config.variant.as_u32()),
|
||||
&len_as_32le(context.pwd),
|
||||
context.pwd,
|
||||
&len_as_32le(context.salt),
|
||||
context.salt,
|
||||
&len_as_32le(context.config.secret),
|
||||
context.config.secret,
|
||||
&len_as_32le(context.config.ad),
|
||||
context.config.ad,
|
||||
];
|
||||
let mut out = [0u8; common::PREHASH_SEED_LENGTH];
|
||||
blake2b(&mut out[0..common::PREHASH_DIGEST_LENGTH], &input);
|
||||
out
|
||||
}
|
||||
|
||||
fn hprime(out: &mut [u8], input: &[u8]) {
|
||||
let out_len = out.len();
|
||||
if out_len <= common::BLAKE2B_OUT_LENGTH {
|
||||
blake2b(out, &[&u32::to_le_bytes(out_len as u32), input]);
|
||||
} else {
|
||||
let ai_len = 32;
|
||||
let mut out_buffer = [0u8; common::BLAKE2B_OUT_LENGTH];
|
||||
let mut in_buffer = [0u8; common::BLAKE2B_OUT_LENGTH];
|
||||
blake2b(&mut out_buffer, &[&u32::to_le_bytes(out_len as u32), input]);
|
||||
out[0..ai_len].clone_from_slice(&out_buffer[0..ai_len]);
|
||||
let mut out_pos = ai_len;
|
||||
let mut to_produce = out_len - ai_len;
|
||||
|
||||
while to_produce > common::BLAKE2B_OUT_LENGTH {
|
||||
in_buffer.clone_from_slice(&out_buffer);
|
||||
blake2b(&mut out_buffer, &[&in_buffer]);
|
||||
out[out_pos..out_pos + ai_len].clone_from_slice(&out_buffer[0..ai_len]);
|
||||
out_pos += ai_len;
|
||||
to_produce -= ai_len;
|
||||
}
|
||||
blake2b(&mut out[out_pos..out_len], &[&out_buffer]);
|
||||
}
|
||||
}
|
||||
|
||||
fn index_alpha(context: &Context, position: &Position, pseudo_rand: u32, same_lane: bool) -> u32 {
|
||||
// Pass 0:
|
||||
// - This lane: all already finished segments plus already constructed blocks in this segment
|
||||
// - Other lanes: all already finished segments
|
||||
// Pass 1+:
|
||||
// - This lane: (SYNC_POINTS - 1) last segments plus already constructed blocks in this segment
|
||||
// - Other lanes : (SYNC_POINTS - 1) last segments
|
||||
let reference_area_size: u32 = if position.pass == 0 {
|
||||
// First pass
|
||||
if position.slice == 0 {
|
||||
// First slice
|
||||
position.index - 1
|
||||
} else if same_lane {
|
||||
// The same lane => add current segment
|
||||
position.slice * context.segment_length + position.index - 1
|
||||
} else if position.index == 0 {
|
||||
position.slice * context.segment_length - 1
|
||||
} else {
|
||||
position.slice * context.segment_length
|
||||
}
|
||||
} else {
|
||||
// Second pass
|
||||
if same_lane {
|
||||
context.lane_length - context.segment_length + position.index - 1
|
||||
} else if position.index == 0 {
|
||||
context.lane_length - context.segment_length - 1
|
||||
} else {
|
||||
context.lane_length - context.segment_length
|
||||
}
|
||||
};
|
||||
let reference_area_size = reference_area_size as u64;
|
||||
let mut relative_position = pseudo_rand as u64;
|
||||
relative_position = (relative_position * relative_position) >> 32;
|
||||
relative_position = reference_area_size - 1 - ((reference_area_size * relative_position) >> 32);
|
||||
|
||||
// 1.2.5 Computing starting position
|
||||
let start_position: u32 = if position.pass != 0 {
|
||||
if position.slice == common::SYNC_POINTS - 1 {
|
||||
0u32
|
||||
} else {
|
||||
(position.slice + 1) * context.segment_length
|
||||
}
|
||||
} else {
|
||||
0u32
|
||||
};
|
||||
let start_position = start_position as u64;
|
||||
|
||||
// 1.2.6. Computing absolute position
|
||||
((start_position + relative_position) % context.lane_length as u64) as u32
|
||||
}
|
||||
|
||||
fn len_as_32le(slice: &[u8]) -> [u8; 4] {
|
||||
u32::to_le_bytes(slice.len() as u32)
|
||||
}
|
||||
|
||||
fn next_addresses(address_block: &mut Block, input_block: &mut Block, zero_block: &Block) {
|
||||
input_block[6] += 1;
|
||||
fill_block(zero_block, input_block, address_block, false);
|
||||
fill_block(zero_block, &address_block.clone(), address_block, false);
|
||||
}
|
||||
|
||||
fn p(
|
||||
v0: &mut u64,
|
||||
v1: &mut u64,
|
||||
v2: &mut u64,
|
||||
v3: &mut u64,
|
||||
v4: &mut u64,
|
||||
v5: &mut u64,
|
||||
v6: &mut u64,
|
||||
v7: &mut u64,
|
||||
v8: &mut u64,
|
||||
v9: &mut u64,
|
||||
v10: &mut u64,
|
||||
v11: &mut u64,
|
||||
v12: &mut u64,
|
||||
v13: &mut u64,
|
||||
v14: &mut u64,
|
||||
v15: &mut u64,
|
||||
) {
|
||||
g(v0, v4, v8, v12);
|
||||
g(v1, v5, v9, v13);
|
||||
g(v2, v6, v10, v14);
|
||||
g(v3, v7, v11, v15);
|
||||
g(v0, v5, v10, v15);
|
||||
g(v1, v6, v11, v12);
|
||||
g(v2, v7, v8, v13);
|
||||
g(v3, v4, v9, v14);
|
||||
}
|
||||
|
||||
fn rotr64(w: u64, c: u32) -> u64 {
|
||||
(w >> c) | (w << (64 - c))
|
||||
}
|
35
third_party/rust/rust-argon2/src/decoded.rs
vendored
35
third_party/rust/rust-argon2/src/decoded.rs
vendored
@ -1,35 +0,0 @@
|
||||
// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use crate::variant::Variant;
|
||||
use crate::version::Version;
|
||||
|
||||
/// Structure that contains the decoded data.
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct Decoded {
|
||||
/// The variant.
|
||||
pub variant: Variant,
|
||||
|
||||
/// The version.
|
||||
pub version: Version,
|
||||
|
||||
/// The amount of memory requested (KiB).
|
||||
pub mem_cost: u32,
|
||||
|
||||
/// The number of passes.
|
||||
pub time_cost: u32,
|
||||
|
||||
/// The parallelism.
|
||||
pub parallelism: u32,
|
||||
|
||||
/// The salt.
|
||||
pub salt: Vec<u8>,
|
||||
|
||||
/// The hash.
|
||||
pub hash: Vec<u8>,
|
||||
}
|
405
third_party/rust/rust-argon2/src/encoding.rs
vendored
405
third_party/rust/rust-argon2/src/encoding.rs
vendored
@ -1,405 +0,0 @@
|
||||
// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::decoded::Decoded;
|
||||
use crate::error::Error;
|
||||
use crate::result::Result;
|
||||
use crate::variant::Variant;
|
||||
use crate::version::Version;
|
||||
use base64;
|
||||
|
||||
/// Structure containing the options.
|
||||
struct Options {
|
||||
mem_cost: u32,
|
||||
time_cost: u32,
|
||||
parallelism: u32,
|
||||
}
|
||||
|
||||
/// Gets the base64 encoded length of a byte slice with the specified length.
|
||||
pub fn base64_len(length: u32) -> u32 {
|
||||
let olen = (length / 3) << 2;
|
||||
match length % 3 {
|
||||
2 => olen + 3,
|
||||
1 => olen + 2,
|
||||
_ => olen,
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to decode the encoded string slice.
|
||||
pub fn decode_string(encoded: &str) -> Result<Decoded> {
|
||||
let items: Vec<&str> = encoded.split('$').collect();
|
||||
if items.len() == 6 {
|
||||
decode_empty(items[0])?;
|
||||
let variant = decode_variant(items[1])?;
|
||||
let version = decode_version(items[2])?;
|
||||
let options = decode_options(items[3])?;
|
||||
let salt = base64::decode(items[4])?;
|
||||
let hash = base64::decode(items[5])?;
|
||||
|
||||
Ok(Decoded {
|
||||
variant,
|
||||
version,
|
||||
mem_cost: options.mem_cost,
|
||||
time_cost: options.time_cost,
|
||||
parallelism: options.parallelism,
|
||||
salt,
|
||||
hash,
|
||||
})
|
||||
} else if items.len() == 5 {
|
||||
decode_empty(items[0])?;
|
||||
let variant = decode_variant(items[1])?;
|
||||
let options = decode_options(items[2])?;
|
||||
let salt = base64::decode(items[3])?;
|
||||
let hash = base64::decode(items[4])?;
|
||||
|
||||
Ok(Decoded {
|
||||
variant,
|
||||
version: Version::Version10,
|
||||
mem_cost: options.mem_cost,
|
||||
time_cost: options.time_cost,
|
||||
parallelism: options.parallelism,
|
||||
salt,
|
||||
hash,
|
||||
})
|
||||
} else {
|
||||
Err(Error::DecodingFail)
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_empty(str: &str) -> Result<()> {
|
||||
if str == "" {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::DecodingFail)
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_options(str: &str) -> Result<Options> {
|
||||
let items: Vec<&str> = str.split(',').collect();
|
||||
if items.len() == 3 {
|
||||
Ok(Options {
|
||||
mem_cost: decode_option(items[0], "m")?,
|
||||
time_cost: decode_option(items[1], "t")?,
|
||||
parallelism: decode_option(items[2], "p")?,
|
||||
})
|
||||
} else {
|
||||
Err(Error::DecodingFail)
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_option(str: &str, name: &str) -> Result<u32> {
|
||||
let items: Vec<&str> = str.split('=').collect();
|
||||
if items.len() == 2 {
|
||||
if items[0] == name {
|
||||
decode_u32(items[1])
|
||||
} else {
|
||||
Err(Error::DecodingFail)
|
||||
}
|
||||
} else {
|
||||
Err(Error::DecodingFail)
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_u32(str: &str) -> Result<u32> {
|
||||
match str.parse() {
|
||||
Ok(i) => Ok(i),
|
||||
Err(_) => Err(Error::DecodingFail),
|
||||
}
|
||||
}
|
||||
|
||||
fn decode_variant(str: &str) -> Result<Variant> {
|
||||
Variant::from_str(str)
|
||||
}
|
||||
|
||||
fn decode_version(str: &str) -> Result<Version> {
|
||||
let items: Vec<&str> = str.split('=').collect();
|
||||
if items.len() == 2 {
|
||||
if items[0] == "v" {
|
||||
Version::from_str(items[1])
|
||||
} else {
|
||||
Err(Error::DecodingFail)
|
||||
}
|
||||
} else {
|
||||
Err(Error::DecodingFail)
|
||||
}
|
||||
}
|
||||
|
||||
/// Encodes the hash and context.
|
||||
pub fn encode_string(context: &Context, hash: &[u8]) -> String {
|
||||
format!(
|
||||
"${}$v={}$m={},t={},p={}${}${}",
|
||||
context.config.variant,
|
||||
context.config.version,
|
||||
context.config.mem_cost,
|
||||
context.config.time_cost,
|
||||
context.config.lanes,
|
||||
base64::encode_config(context.salt, base64::STANDARD_NO_PAD),
|
||||
base64::encode_config(hash, base64::STANDARD_NO_PAD),
|
||||
)
|
||||
}
|
||||
|
||||
/// Gets the string length of the specified number.
|
||||
pub fn num_len(number: u32) -> u32 {
|
||||
let mut len = 1;
|
||||
let mut num = number;
|
||||
while num >= 10 {
|
||||
len += 1;
|
||||
num /= 10;
|
||||
}
|
||||
len
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
#[cfg(feature = "crossbeam-utils")]
|
||||
use crate::config::Config;
|
||||
#[cfg(feature = "crossbeam-utils")]
|
||||
use crate::context::Context;
|
||||
use crate::decoded::Decoded;
|
||||
#[cfg(feature = "crossbeam-utils")]
|
||||
use crate::encoding::encode_string;
|
||||
use crate::encoding::{base64_len, decode_string, num_len};
|
||||
use crate::error::Error;
|
||||
#[cfg(feature = "crossbeam-utils")]
|
||||
use crate::thread_mode::ThreadMode;
|
||||
use crate::variant::Variant;
|
||||
use crate::version::Version;
|
||||
|
||||
#[test]
|
||||
fn base64_len_returns_correct_length() {
|
||||
let tests = vec![
|
||||
(1, 2),
|
||||
(2, 3),
|
||||
(3, 4),
|
||||
(4, 6),
|
||||
(5, 7),
|
||||
(6, 8),
|
||||
(7, 10),
|
||||
(8, 11),
|
||||
(9, 12),
|
||||
(10, 14),
|
||||
];
|
||||
for (len, expected) in tests {
|
||||
let actual = base64_len(len);
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_string_with_version10_returns_correct_result() {
|
||||
let encoded = "$argon2i$v=16$m=4096,t=3,p=1\
|
||||
$c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=";
|
||||
let expected = Decoded {
|
||||
variant: Variant::Argon2i,
|
||||
version: Version::Version10,
|
||||
mem_cost: 4096,
|
||||
time_cost: 3,
|
||||
parallelism: 1,
|
||||
salt: b"salt1234".to_vec(),
|
||||
hash: b"12345678901234567890123456789012".to_vec(),
|
||||
};
|
||||
let actual = decode_string(encoded).unwrap();
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_string_with_version13_returns_correct_result() {
|
||||
let encoded = "$argon2i$v=19$m=4096,t=3,p=1\
|
||||
$c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=";
|
||||
let expected = Decoded {
|
||||
variant: Variant::Argon2i,
|
||||
version: Version::Version13,
|
||||
mem_cost: 4096,
|
||||
time_cost: 3,
|
||||
parallelism: 1,
|
||||
salt: b"salt1234".to_vec(),
|
||||
hash: b"12345678901234567890123456789012".to_vec(),
|
||||
};
|
||||
let actual = decode_string(encoded).unwrap();
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_string_without_version_returns_correct_result() {
|
||||
let encoded = "$argon2i$m=4096,t=3,p=1\
|
||||
$c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=";
|
||||
let expected = Decoded {
|
||||
variant: Variant::Argon2i,
|
||||
version: Version::Version10,
|
||||
mem_cost: 4096,
|
||||
time_cost: 3,
|
||||
parallelism: 1,
|
||||
salt: b"salt1234".to_vec(),
|
||||
hash: b"12345678901234567890123456789012".to_vec(),
|
||||
};
|
||||
let actual = decode_string(encoded).unwrap();
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_string_without_variant_returns_error_result() {
|
||||
let encoded = "$m=4096,t=3,p=1\
|
||||
$c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=";
|
||||
let result = decode_string(encoded);
|
||||
assert_eq!(result, Err(Error::DecodingFail));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_string_with_empty_variant_returns_error_result() {
|
||||
let encoded = "$$m=4096,t=3,p=1\
|
||||
$c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=";
|
||||
let result = decode_string(encoded);
|
||||
assert_eq!(result, Err(Error::DecodingFail));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_string_with_invalid_variant_returns_error_result() {
|
||||
let encoded = "$argon$m=4096,t=3,p=1\
|
||||
$c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=";
|
||||
let result = decode_string(encoded);
|
||||
assert_eq!(result, Err(Error::DecodingFail));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_string_without_mem_cost_returns_error_result() {
|
||||
let encoded = "$argon2i$t=3,p=1\
|
||||
$c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=";
|
||||
let result = decode_string(encoded);
|
||||
assert_eq!(result, Err(Error::DecodingFail));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_string_with_empty_mem_cost_returns_error_result() {
|
||||
let encoded = "$argon2i$m=,t=3,p=1\
|
||||
$c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=";
|
||||
let result = decode_string(encoded);
|
||||
assert_eq!(result, Err(Error::DecodingFail));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_string_with_non_numeric_mem_cost_returns_error_result() {
|
||||
let encoded = "$argon2i$m=a,t=3,p=1\
|
||||
$c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=";
|
||||
let result = decode_string(encoded);
|
||||
assert_eq!(result, Err(Error::DecodingFail));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_string_without_time_cost_returns_error_result() {
|
||||
let encoded = "$argon2i$m=4096,p=1\
|
||||
$c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=";
|
||||
let result = decode_string(encoded);
|
||||
assert_eq!(result, Err(Error::DecodingFail));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_string_with_empty_time_cost_returns_error_result() {
|
||||
let encoded = "$argon2i$m=4096,t=,p=1\
|
||||
$c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=";
|
||||
let result = decode_string(encoded);
|
||||
assert_eq!(result, Err(Error::DecodingFail));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_string_with_non_numeric_time_cost_returns_error_result() {
|
||||
let encoded = "$argon2i$m=4096,t=a,p=1\
|
||||
$c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=";
|
||||
let result = decode_string(encoded);
|
||||
assert_eq!(result, Err(Error::DecodingFail));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_string_without_parallelism_returns_error_result() {
|
||||
let encoded = "$argon2i$m=4096,t=3\
|
||||
$c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=";
|
||||
let result = decode_string(encoded);
|
||||
assert_eq!(result, Err(Error::DecodingFail));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_string_with_empty_parallelism_returns_error_result() {
|
||||
let encoded = "$argon2i$m=4096,t=3,p=\
|
||||
$c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=";
|
||||
let result = decode_string(encoded);
|
||||
assert_eq!(result, Err(Error::DecodingFail));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_string_with_non_numeric_parallelism_returns_error_result() {
|
||||
let encoded = "$argon2i$m=4096,t=3,p=a\
|
||||
$c2FsdDEyMzQ=$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=";
|
||||
let result = decode_string(encoded);
|
||||
assert_eq!(result, Err(Error::DecodingFail));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_string_without_salt_returns_error_result() {
|
||||
let encoded = "$argon2i$m=4096,t=3,p=1\
|
||||
$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI=";
|
||||
let result = decode_string(encoded);
|
||||
assert_eq!(result, Err(Error::DecodingFail));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_string_without_hash_returns_error_result() {
|
||||
let encoded = "$argon2i$m=4096,t=3,p=a\
|
||||
$c2FsdDEyMzQ=";
|
||||
let result = decode_string(encoded);
|
||||
assert_eq!(result, Err(Error::DecodingFail));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn decode_string_with_empty_hash_returns_error_result() {
|
||||
let encoded = "$argon2i$m=4096,t=3,p=a\
|
||||
$c2FsdDEyMzQ=$";
|
||||
let result = decode_string(encoded);
|
||||
assert_eq!(result, Err(Error::DecodingFail));
|
||||
}
|
||||
|
||||
#[cfg(feature = "crossbeam-utils")]
|
||||
#[test]
|
||||
fn encode_string_returns_correct_string() {
|
||||
let hash = b"12345678901234567890123456789012".to_vec();
|
||||
let config = Config {
|
||||
ad: &[],
|
||||
hash_length: hash.len() as u32,
|
||||
lanes: 1,
|
||||
mem_cost: 4096,
|
||||
secret: &[],
|
||||
thread_mode: ThreadMode::Parallel,
|
||||
time_cost: 3,
|
||||
variant: Variant::Argon2i,
|
||||
version: Version::Version13,
|
||||
};
|
||||
let pwd = b"password".to_vec();
|
||||
let salt = b"salt1234".to_vec();
|
||||
let context = Context::new(config, &pwd, &salt).unwrap();
|
||||
let expected = "$argon2i$v=19$m=4096,t=3,p=1\
|
||||
$c2FsdDEyMzQ$MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTI";
|
||||
let actual = encode_string(&context, &hash);
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn num_len_returns_correct_length() {
|
||||
let tests = vec![
|
||||
(1, 1),
|
||||
(10, 2),
|
||||
(110, 3),
|
||||
(1230, 4),
|
||||
(12340, 5),
|
||||
(123457, 6),
|
||||
];
|
||||
for (num, expected) in tests {
|
||||
let actual = num_len(num);
|
||||
assert_eq!(actual, expected);
|
||||
}
|
||||
}
|
||||
}
|
123
third_party/rust/rust-argon2/src/error.rs
vendored
123
third_party/rust/rust-argon2/src/error.rs
vendored
@ -1,123 +0,0 @@
|
||||
// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::{error, fmt};
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Error type for Argon2 errors.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
#[cfg_attr(feature = "serde", serde(rename_all = "snake_case"))]
|
||||
pub enum Error {
|
||||
/// The output (hash) is too short (minimum is 4).
|
||||
OutputTooShort,
|
||||
|
||||
/// The output (hash) is too long (maximum is 2^32 - 1).
|
||||
OutputTooLong,
|
||||
|
||||
/// The password is too short (minimum is 0).
|
||||
PwdTooShort,
|
||||
|
||||
/// The password is too long (maximum is 2^32 - 1).
|
||||
PwdTooLong,
|
||||
|
||||
/// The salt is too short (minimum is 8).
|
||||
SaltTooShort,
|
||||
|
||||
/// The salt is too long (maximum is 2^32 - 1).
|
||||
SaltTooLong,
|
||||
|
||||
/// The associated data is too short (minimum is 0).
|
||||
AdTooShort,
|
||||
|
||||
/// The associated data is too long (maximum is 2^32 - 1).
|
||||
AdTooLong,
|
||||
|
||||
/// The secret value is too short (minimum is 0).
|
||||
SecretTooShort,
|
||||
|
||||
/// The secret value is too long (maximum is 2^32 - 1).
|
||||
SecretTooLong,
|
||||
|
||||
/// The time cost (passes) is too small (minimum is 1).
|
||||
TimeTooSmall,
|
||||
|
||||
/// The time cost (passes) is too large (maximum is 2^32 - 1).
|
||||
TimeTooLarge,
|
||||
|
||||
/// The memory cost is too small (minimum is 8 x parallelism).
|
||||
MemoryTooLittle,
|
||||
|
||||
/// The memory cost is too large (maximum 2GiB on 32-bit or 4TiB on 64-bit).
|
||||
MemoryTooMuch,
|
||||
|
||||
/// The number of lanes (parallelism) is too small (minimum is 1).
|
||||
LanesTooFew,
|
||||
|
||||
/// The number of lanes (parallelism) is too large (maximum is 2^24 - 1).
|
||||
LanesTooMany,
|
||||
|
||||
/// Incorrect Argon2 variant.
|
||||
IncorrectType,
|
||||
|
||||
/// Incorrect Argon2 version.
|
||||
IncorrectVersion,
|
||||
|
||||
/// The decoding of the encoded data has failed.
|
||||
DecodingFail,
|
||||
}
|
||||
|
||||
impl Error {
|
||||
fn msg(&self) -> &str {
|
||||
match *self {
|
||||
Error::OutputTooShort => "Output is too short",
|
||||
Error::OutputTooLong => "Output is too long",
|
||||
Error::PwdTooShort => "Password is too short",
|
||||
Error::PwdTooLong => "Password is too long",
|
||||
Error::SaltTooShort => "Salt is too short",
|
||||
Error::SaltTooLong => "Salt is too long",
|
||||
Error::AdTooShort => "Associated data is too short",
|
||||
Error::AdTooLong => "Associated data is too long",
|
||||
Error::SecretTooShort => "Secret is too short",
|
||||
Error::SecretTooLong => "Secret is too long",
|
||||
Error::TimeTooSmall => "Time cost is too small",
|
||||
Error::TimeTooLarge => "Time cost is too large",
|
||||
Error::MemoryTooLittle => "Memory cost is too small",
|
||||
Error::MemoryTooMuch => "Memory cost is too large",
|
||||
Error::LanesTooFew => "Too few lanes",
|
||||
Error::LanesTooMany => "Too many lanes",
|
||||
Error::IncorrectType => "There is no such type of Argon2",
|
||||
Error::IncorrectVersion => "There is no such version of Argon2",
|
||||
Error::DecodingFail => "Decoding failed",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.msg())
|
||||
}
|
||||
}
|
||||
|
||||
impl error::Error for Error {
|
||||
fn description(&self) -> &str {
|
||||
self.msg()
|
||||
}
|
||||
|
||||
fn cause(&self) -> Option<&dyn error::Error> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl From<base64::DecodeError> for Error {
|
||||
fn from(_: base64::DecodeError) -> Self {
|
||||
Error::DecodingFail
|
||||
}
|
||||
}
|
107
third_party/rust/rust-argon2/src/lib.rs
vendored
107
third_party/rust/rust-argon2/src/lib.rs
vendored
@ -1,107 +0,0 @@
|
||||
// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Library for hashing passwords using
|
||||
//! [Argon2](https://github.com/P-H-C/phc-winner-argon2), the password-hashing
|
||||
//! function that won the
|
||||
//! [Password Hashing Competition (PHC)](https://password-hashing.net).
|
||||
//!
|
||||
//! # Usage
|
||||
//!
|
||||
//! To use this crate, add the following to your Cargo.toml:
|
||||
//!
|
||||
//! ```toml
|
||||
//! [dependencies]
|
||||
//! rust-argon2 = "0.8"
|
||||
//! ```
|
||||
//!
|
||||
//! And the following to your crate root:
|
||||
//!
|
||||
//! ```rust
|
||||
//! extern crate argon2;
|
||||
//! ```
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Create a password hash using the defaults and verify it:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use argon2::{self, Config};
|
||||
//!
|
||||
//! let password = b"password";
|
||||
//! let salt = b"randomsalt";
|
||||
//! let config = Config::default();
|
||||
//! let hash = argon2::hash_encoded(password, salt, &config).unwrap();
|
||||
//! let matches = argon2::verify_encoded(&hash, password).unwrap();
|
||||
//! assert!(matches);
|
||||
//! ```
|
||||
//!
|
||||
//! Create a password hash with custom settings and verify it:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use argon2::{self, Config, ThreadMode, Variant, Version};
|
||||
//!
|
||||
//! let password = b"password";
|
||||
//! let salt = b"othersalt";
|
||||
//! let config = Config {
|
||||
//! variant: Variant::Argon2i,
|
||||
//! version: Version::Version13,
|
||||
//! mem_cost: 65536,
|
||||
//! time_cost: 10,
|
||||
#![cfg_attr(feature = "crossbeam-utils", doc = " lanes: 4,")]
|
||||
#![cfg_attr(
|
||||
feature = "crossbeam-utils",
|
||||
doc = " thread_mode: ThreadMode::Parallel,"
|
||||
)]
|
||||
#![cfg_attr(not(feature = "crossbeam-utils"), doc = " lanes: 1,")]
|
||||
#![cfg_attr(
|
||||
not(feature = "crossbeam-utils"),
|
||||
doc = " thread_mode: ThreadMode::Sequential,"
|
||||
)]
|
||||
//! secret: &[],
|
||||
//! ad: &[],
|
||||
//! hash_length: 32
|
||||
//! };
|
||||
//! let hash = argon2::hash_encoded(password, salt, &config).unwrap();
|
||||
//! let matches = argon2::verify_encoded(&hash, password).unwrap();
|
||||
//! assert!(matches);
|
||||
//! ```
|
||||
//!
|
||||
//! # Limitations
|
||||
//!
|
||||
//! This crate has the same limitation as the `blake2-rfc` crate that it uses.
|
||||
//! It does not attempt to clear potentially sensitive data from its work
|
||||
//! memory. To do so correctly without a heavy performance penalty would
|
||||
//! require help from the compiler. It's better to not attempt to do so than to
|
||||
//! present a false assurance.
|
||||
//!
|
||||
//! This version uses the standard implementation and does not yet implement
|
||||
//! optimizations. Therefore, it is not the fastest implementation available.
|
||||
|
||||
mod argon2;
|
||||
mod block;
|
||||
mod common;
|
||||
mod config;
|
||||
mod context;
|
||||
mod core;
|
||||
mod decoded;
|
||||
mod encoding;
|
||||
mod error;
|
||||
mod memory;
|
||||
mod result;
|
||||
mod thread_mode;
|
||||
mod variant;
|
||||
mod version;
|
||||
|
||||
pub use crate::argon2::*;
|
||||
pub use crate::config::Config;
|
||||
pub use crate::error::Error;
|
||||
pub use crate::result::Result;
|
||||
pub use crate::thread_mode::ThreadMode;
|
||||
pub use crate::variant::Variant;
|
||||
pub use crate::version::Version;
|
117
third_party/rust/rust-argon2/src/memory.rs
vendored
117
third_party/rust/rust-argon2/src/memory.rs
vendored
@ -1,117 +0,0 @@
|
||||
// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use crate::block::Block;
|
||||
use std::fmt;
|
||||
use std::fmt::Debug;
|
||||
use std::ops::{Index, IndexMut};
|
||||
|
||||
/// Structure representing the memory matrix.
|
||||
pub struct Memory {
|
||||
/// The number of rows.
|
||||
rows: usize,
|
||||
|
||||
/// The number of columns.
|
||||
cols: usize,
|
||||
|
||||
/// The flat array of blocks representing the memory matrix.
|
||||
blocks: Box<[Block]>,
|
||||
}
|
||||
|
||||
impl Memory {
|
||||
/// Creates a new memory matrix.
|
||||
pub fn new(lanes: u32, lane_length: u32) -> Memory {
|
||||
let rows = lanes as usize;
|
||||
let cols = lane_length as usize;
|
||||
let total = rows * cols;
|
||||
let blocks = vec![Block::zero(); total].into_boxed_slice();
|
||||
Memory { rows, cols, blocks }
|
||||
}
|
||||
|
||||
#[cfg(feature = "crossbeam-utils")]
|
||||
/// Gets the mutable lanes representation of the memory matrix.
|
||||
pub fn as_lanes_mut(&mut self) -> Vec<&mut Memory> {
|
||||
let ptr: *mut Memory = self;
|
||||
let mut vec = Vec::with_capacity(self.rows);
|
||||
for _ in 0..self.rows {
|
||||
vec.push(unsafe { &mut (*ptr) });
|
||||
}
|
||||
vec
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for Memory {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "Memory {{ rows: {}, cols: {} }}", self.rows, self.cols)
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<u32> for Memory {
|
||||
type Output = Block;
|
||||
fn index(&self, index: u32) -> &Block {
|
||||
&self.blocks[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<u64> for Memory {
|
||||
type Output = Block;
|
||||
fn index(&self, index: u64) -> &Block {
|
||||
&self.blocks[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<(u32, u32)> for Memory {
|
||||
type Output = Block;
|
||||
fn index(&self, index: (u32, u32)) -> &Block {
|
||||
let pos = ((index.0 as usize) * self.cols) + (index.1 as usize);
|
||||
&self.blocks[pos]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<u32> for Memory {
|
||||
fn index_mut(&mut self, index: u32) -> &mut Block {
|
||||
&mut self.blocks[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<u64> for Memory {
|
||||
fn index_mut(&mut self, index: u64) -> &mut Block {
|
||||
&mut self.blocks[index as usize]
|
||||
}
|
||||
}
|
||||
|
||||
impl IndexMut<(u32, u32)> for Memory {
|
||||
fn index_mut(&mut self, index: (u32, u32)) -> &mut Block {
|
||||
let pos = ((index.0 as usize) * self.cols) + (index.1 as usize);
|
||||
&mut self.blocks[pos]
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::memory::Memory;
|
||||
|
||||
#[test]
|
||||
fn new_returns_correct_instance() {
|
||||
let lanes = 4;
|
||||
let lane_length = 128;
|
||||
let memory = Memory::new(lanes, lane_length);
|
||||
assert_eq!(memory.rows, lanes as usize);
|
||||
assert_eq!(memory.cols, lane_length as usize);
|
||||
assert_eq!(memory.blocks.len(), 512);
|
||||
}
|
||||
|
||||
#[cfg(feature = "crossbeam-utils")]
|
||||
#[test]
|
||||
fn as_lanes_mut_returns_correct_vec() {
|
||||
let mut memory = Memory::new(4, 128);
|
||||
let lanes = memory.as_lanes_mut();
|
||||
assert_eq!(lanes.len(), 4);
|
||||
}
|
||||
}
|
13
third_party/rust/rust-argon2/src/result.rs
vendored
13
third_party/rust/rust-argon2/src/result.rs
vendored
@ -1,13 +0,0 @@
|
||||
// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use crate::error::Error;
|
||||
use std::result;
|
||||
|
||||
/// A specialized result type for Argon2 operations.
|
||||
pub type Result<T> = result::Result<T, Error>;
|
64
third_party/rust/rust-argon2/src/thread_mode.rs
vendored
64
third_party/rust/rust-argon2/src/thread_mode.rs
vendored
@ -1,64 +0,0 @@
|
||||
// Copyright (c) 2017 Xidorn Quan <me@upsuper.org>
|
||||
// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/// The thread mode used to perform the hashing.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub enum ThreadMode {
|
||||
/// Run in one thread.
|
||||
Sequential,
|
||||
|
||||
#[cfg(feature = "crossbeam-utils")]
|
||||
/// Run in the same number of threads as the number of lanes.
|
||||
Parallel,
|
||||
}
|
||||
|
||||
impl ThreadMode {
|
||||
#[cfg(feature = "crossbeam-utils")]
|
||||
/// Create a thread mode from the threads count.
|
||||
pub fn from_threads(threads: u32) -> ThreadMode {
|
||||
if threads > 1 {
|
||||
ThreadMode::Parallel
|
||||
} else {
|
||||
ThreadMode::Sequential
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "crossbeam-utils"))]
|
||||
pub fn from_threads(threads: u32) -> ThreadMode {
|
||||
assert_eq!(threads, 1);
|
||||
Self::default()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ThreadMode {
|
||||
fn default() -> ThreadMode {
|
||||
ThreadMode::Sequential
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::thread_mode::ThreadMode;
|
||||
|
||||
#[test]
|
||||
fn default_returns_correct_thread_mode() {
|
||||
assert_eq!(ThreadMode::default(), ThreadMode::Sequential);
|
||||
}
|
||||
|
||||
#[cfg(feature = "crossbeam-utils")]
|
||||
#[test]
|
||||
fn from_threads_returns_correct_thread_mode() {
|
||||
assert_eq!(ThreadMode::from_threads(0), ThreadMode::Sequential);
|
||||
assert_eq!(ThreadMode::from_threads(1), ThreadMode::Sequential);
|
||||
assert_eq!(ThreadMode::from_threads(2), ThreadMode::Parallel);
|
||||
assert_eq!(ThreadMode::from_threads(10), ThreadMode::Parallel);
|
||||
assert_eq!(ThreadMode::from_threads(100), ThreadMode::Parallel);
|
||||
}
|
||||
}
|
158
third_party/rust/rust-argon2/src/variant.rs
vendored
158
third_party/rust/rust-argon2/src/variant.rs
vendored
@ -1,158 +0,0 @@
|
||||
// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::result::Result;
|
||||
use std::fmt;
|
||||
|
||||
/// The Argon2 variant.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum Variant {
|
||||
/// Argon2 using data-dependent memory access to thwart tradeoff attacks.
|
||||
/// Recommended for cryptocurrencies and backend servers.
|
||||
Argon2d = 0,
|
||||
|
||||
/// Argon2 using data-independent memory access to thwart side-channel
|
||||
/// attacks. Recommended for password hashing and password-based key
|
||||
/// derivation.
|
||||
Argon2i = 1,
|
||||
|
||||
/// Argon2 using hybrid construction.
|
||||
Argon2id = 2,
|
||||
}
|
||||
|
||||
impl Variant {
|
||||
/// Gets the lowercase string slice representation of the variant.
|
||||
pub fn as_lowercase_str(&self) -> &'static str {
|
||||
match *self {
|
||||
Variant::Argon2d => "argon2d",
|
||||
Variant::Argon2i => "argon2i",
|
||||
Variant::Argon2id => "argon2id",
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the u32 representation of the variant.
|
||||
pub fn as_u32(&self) -> u32 {
|
||||
*self as u32
|
||||
}
|
||||
|
||||
/// Gets the u64 representation of the variant.
|
||||
pub fn as_u64(&self) -> u64 {
|
||||
*self as u64
|
||||
}
|
||||
|
||||
/// Gets the uppercase string slice representation of the variant.
|
||||
pub fn as_uppercase_str(&self) -> &'static str {
|
||||
match *self {
|
||||
Variant::Argon2d => "Argon2d",
|
||||
Variant::Argon2i => "Argon2i",
|
||||
Variant::Argon2id => "Argon2id",
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to create a variant from a string slice.
|
||||
pub fn from_str(str: &str) -> Result<Variant> {
|
||||
match str {
|
||||
"Argon2d" => Ok(Variant::Argon2d),
|
||||
"Argon2i" => Ok(Variant::Argon2i),
|
||||
"Argon2id" => Ok(Variant::Argon2id),
|
||||
"argon2d" => Ok(Variant::Argon2d),
|
||||
"argon2i" => Ok(Variant::Argon2i),
|
||||
"argon2id" => Ok(Variant::Argon2id),
|
||||
_ => Err(Error::DecodingFail),
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to create a variant from an u32.
|
||||
pub fn from_u32(val: u32) -> Result<Variant> {
|
||||
match val {
|
||||
0 => Ok(Variant::Argon2d),
|
||||
1 => Ok(Variant::Argon2i),
|
||||
2 => Ok(Variant::Argon2id),
|
||||
_ => Err(Error::IncorrectType),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Variant {
|
||||
fn default() -> Variant {
|
||||
Variant::Argon2i
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Variant {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.as_lowercase_str())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::variant::Variant;
|
||||
|
||||
#[test]
|
||||
fn as_lowercase_str_returns_correct_str() {
|
||||
assert_eq!(Variant::Argon2d.as_lowercase_str(), "argon2d");
|
||||
assert_eq!(Variant::Argon2i.as_lowercase_str(), "argon2i");
|
||||
assert_eq!(Variant::Argon2id.as_lowercase_str(), "argon2id");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn as_u32_returns_correct_u32() {
|
||||
assert_eq!(Variant::Argon2d.as_u32(), 0);
|
||||
assert_eq!(Variant::Argon2i.as_u32(), 1);
|
||||
assert_eq!(Variant::Argon2id.as_u32(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn as_u64_returns_correct_u64() {
|
||||
assert_eq!(Variant::Argon2d.as_u64(), 0);
|
||||
assert_eq!(Variant::Argon2i.as_u64(), 1);
|
||||
assert_eq!(Variant::Argon2id.as_u64(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn as_uppercase_str_returns_correct_str() {
|
||||
assert_eq!(Variant::Argon2d.as_uppercase_str(), "Argon2d");
|
||||
assert_eq!(Variant::Argon2i.as_uppercase_str(), "Argon2i");
|
||||
assert_eq!(Variant::Argon2id.as_uppercase_str(), "Argon2id");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_returns_correct_variant() {
|
||||
assert_eq!(Variant::default(), Variant::Argon2i);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn display_returns_correct_string() {
|
||||
assert_eq!(format!("{}", Variant::Argon2d), "argon2d");
|
||||
assert_eq!(format!("{}", Variant::Argon2i), "argon2i");
|
||||
assert_eq!(format!("{}", Variant::Argon2id), "argon2id");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str_returns_correct_result() {
|
||||
assert_eq!(Variant::from_str("Argon2d"), Ok(Variant::Argon2d));
|
||||
assert_eq!(Variant::from_str("Argon2i"), Ok(Variant::Argon2i));
|
||||
assert_eq!(Variant::from_str("Argon2id"), Ok(Variant::Argon2id));
|
||||
assert_eq!(Variant::from_str("argon2d"), Ok(Variant::Argon2d));
|
||||
assert_eq!(Variant::from_str("argon2i"), Ok(Variant::Argon2i));
|
||||
assert_eq!(Variant::from_str("argon2id"), Ok(Variant::Argon2id));
|
||||
assert_eq!(Variant::from_str("foobar"), Err(Error::DecodingFail));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_u32_returns_correct_result() {
|
||||
assert_eq!(Variant::from_u32(0), Ok(Variant::Argon2d));
|
||||
assert_eq!(Variant::from_u32(1), Ok(Variant::Argon2i));
|
||||
assert_eq!(Variant::from_u32(2), Ok(Variant::Argon2id));
|
||||
assert_eq!(Variant::from_u32(3), Err(Error::IncorrectType));
|
||||
}
|
||||
}
|
96
third_party/rust/rust-argon2/src/version.rs
vendored
96
third_party/rust/rust-argon2/src/version.rs
vendored
@ -1,96 +0,0 @@
|
||||
// Copyright (c) 2017 Martijn Rijkeboer <mrr@sru-systems.com>
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::result::Result;
|
||||
use std::fmt;
|
||||
|
||||
/// The Argon2 version.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord)]
|
||||
pub enum Version {
|
||||
/// Version 0x10.
|
||||
Version10 = 0x10,
|
||||
|
||||
/// Version 0x13 (Recommended).
|
||||
Version13 = 0x13,
|
||||
}
|
||||
|
||||
impl Version {
|
||||
/// Gets the u32 representation of the version.
|
||||
pub fn as_u32(&self) -> u32 {
|
||||
*self as u32
|
||||
}
|
||||
|
||||
/// Attempts to create a version from a string slice.
|
||||
pub fn from_str(str: &str) -> Result<Version> {
|
||||
match str {
|
||||
"16" => Ok(Version::Version10),
|
||||
"19" => Ok(Version::Version13),
|
||||
_ => Err(Error::DecodingFail),
|
||||
}
|
||||
}
|
||||
|
||||
/// Attempts to create a version from an u32.
|
||||
pub fn from_u32(val: u32) -> Result<Version> {
|
||||
match val {
|
||||
0x10 => Ok(Version::Version10),
|
||||
0x13 => Ok(Version::Version13),
|
||||
_ => Err(Error::IncorrectVersion),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Version {
|
||||
fn default() -> Version {
|
||||
Version::Version13
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Version {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.as_u32())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::error::Error;
|
||||
use crate::version::Version;
|
||||
|
||||
#[test]
|
||||
fn as_u32_returns_correct_u32() {
|
||||
assert_eq!(Version::Version10.as_u32(), 0x10);
|
||||
assert_eq!(Version::Version13.as_u32(), 0x13);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn default_returns_correct_version() {
|
||||
assert_eq!(Version::default(), Version::Version13);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn display_returns_correct_string() {
|
||||
assert_eq!(format!("{}", Version::Version10), "16");
|
||||
assert_eq!(format!("{}", Version::Version13), "19");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str_returns_correct_result() {
|
||||
assert_eq!(Version::from_str("16"), Ok(Version::Version10));
|
||||
assert_eq!(Version::from_str("19"), Ok(Version::Version13));
|
||||
assert_eq!(Version::from_str("11"), Err(Error::DecodingFail));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_u32_returns_correct_result() {
|
||||
assert_eq!(Version::from_u32(0x10), Ok(Version::Version10));
|
||||
assert_eq!(Version::from_u32(0x13), Ok(Version::Version13));
|
||||
assert_eq!(Version::from_u32(0), Err(Error::IncorrectVersion));
|
||||
}
|
||||
}
|
1078
third_party/rust/rust-argon2/tests/integration_test.rs
vendored
1078
third_party/rust/rust-argon2/tests/integration_test.rs
vendored
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user