mirror of
https://github.com/RustCrypto/hashes.git
synced 2026-01-24 20:08:40 +00:00
update crates to digest v0.10 (#217)
This commit is contained in:
2
.github/workflows/blake2.yml
vendored
2
.github/workflows/blake2.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- run: cargo build --no-default-features --release --target ${{ matrix.target }}
|
||||
- run: cargo build --no-default-features --target ${{ matrix.target }}
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
7
.github/workflows/fsb.yml
vendored
7
.github/workflows/fsb.yml
vendored
@@ -22,7 +22,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
rust:
|
||||
- 1.47.0 # MSRV
|
||||
- 1.41.0 # MSRV
|
||||
- stable
|
||||
target:
|
||||
- thumbv7em-none-eabi
|
||||
@@ -35,14 +35,14 @@ jobs:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- run: cargo build --no-default-features --release --target ${{ matrix.target }}
|
||||
- run: cargo build --no-default-features --target ${{ matrix.target }}
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
rust:
|
||||
- 1.47.0 # MSRV
|
||||
- 1.41.0 # MSRV
|
||||
- stable
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
@@ -54,5 +54,4 @@ jobs:
|
||||
- run: cargo check --all-features
|
||||
- run: cargo test --no-default-features
|
||||
- run: cargo test
|
||||
- run: cargo test --features asm
|
||||
- run: cargo test --all-features
|
||||
|
||||
3
.github/workflows/gost94.yml
vendored
3
.github/workflows/gost94.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- run: cargo build --no-default-features --release --target ${{ matrix.target }}
|
||||
- run: cargo build --no-default-features --target ${{ matrix.target }}
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -55,4 +55,3 @@ jobs:
|
||||
- run: cargo test --no-default-features
|
||||
- run: cargo test
|
||||
- run: cargo test --all-features
|
||||
|
||||
|
||||
2
.github/workflows/groestl.yml
vendored
2
.github/workflows/groestl.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- run: cargo build --no-default-features --release --target ${{ matrix.target }}
|
||||
- run: cargo build --no-default-features --target ${{ matrix.target }}
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
3
.github/workflows/k12.yml
vendored
3
.github/workflows/k12.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- run: cargo build --no-default-features --release --target ${{ matrix.target }}
|
||||
- run: cargo build --no-default-features --target ${{ matrix.target }}
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -55,4 +55,3 @@ jobs:
|
||||
- run: cargo test --no-default-features
|
||||
- run: cargo test
|
||||
- run: cargo test --all-features
|
||||
|
||||
|
||||
3
.github/workflows/md2.yml
vendored
3
.github/workflows/md2.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- run: cargo build --no-default-features --release --target ${{ matrix.target }}
|
||||
- run: cargo build --no-default-features --target ${{ matrix.target }}
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -55,4 +55,3 @@ jobs:
|
||||
- run: cargo test --no-default-features
|
||||
- run: cargo test
|
||||
- run: cargo test --all-features
|
||||
|
||||
|
||||
3
.github/workflows/md4.yml
vendored
3
.github/workflows/md4.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- run: cargo build --no-default-features --release --target ${{ matrix.target }}
|
||||
- run: cargo build --no-default-features --target ${{ matrix.target }}
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -55,4 +55,3 @@ jobs:
|
||||
- run: cargo test --no-default-features
|
||||
- run: cargo test
|
||||
- run: cargo test --all-features
|
||||
|
||||
|
||||
2
.github/workflows/md5.yml
vendored
2
.github/workflows/md5.yml
vendored
@@ -38,7 +38,7 @@ jobs:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- run: cargo build --no-default-features --release --target ${{ matrix.target }}
|
||||
- run: cargo build --no-default-features --target ${{ matrix.target }}
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
name: ripemd320
|
||||
name: ripemd
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "ripemd320/**"
|
||||
- "ripemd/**"
|
||||
- "Cargo.*"
|
||||
push:
|
||||
branches: master
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ripemd320
|
||||
working-directory: ripemd
|
||||
|
||||
env:
|
||||
CARGO_INCREMENTAL: 0
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- run: cargo build --no-default-features --release --target ${{ matrix.target }}
|
||||
- run: cargo build --no-default-features --target ${{ matrix.target }}
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
58
.github/workflows/ripemd160.yml
vendored
58
.github/workflows/ripemd160.yml
vendored
@@ -1,58 +0,0 @@
|
||||
name: ripemd160
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "ripemd160/**"
|
||||
- "Cargo.*"
|
||||
push:
|
||||
branches: master
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ripemd160
|
||||
|
||||
env:
|
||||
CARGO_INCREMENTAL: 0
|
||||
RUSTFLAGS: "-Dwarnings"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
rust:
|
||||
- 1.41.0 # MSRV
|
||||
- stable
|
||||
target:
|
||||
- thumbv7em-none-eabi
|
||||
- wasm32-unknown-unknown
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- run: cargo build --no-default-features --release --target ${{ matrix.target }}
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
rust:
|
||||
- 1.41.0 # MSRV
|
||||
- stable
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ matrix.rust }}
|
||||
override: true
|
||||
- run: cargo check --all-features
|
||||
- run: cargo test --no-default-features
|
||||
- run: cargo test
|
||||
- run: cargo test --all-features
|
||||
|
||||
58
.github/workflows/ripemd256.yml
vendored
58
.github/workflows/ripemd256.yml
vendored
@@ -1,58 +0,0 @@
|
||||
name: ripemd256
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "ripemd256/**"
|
||||
- "Cargo.*"
|
||||
push:
|
||||
branches: master
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ripemd256
|
||||
|
||||
env:
|
||||
CARGO_INCREMENTAL: 0
|
||||
RUSTFLAGS: "-Dwarnings"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
rust:
|
||||
- 1.41.0 # MSRV
|
||||
- stable
|
||||
target:
|
||||
- thumbv7em-none-eabi
|
||||
- wasm32-unknown-unknown
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- run: cargo build --no-default-features --release --target ${{ matrix.target }}
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
rust:
|
||||
- 1.41.0 # MSRV
|
||||
- stable
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
profile: minimal
|
||||
toolchain: ${{ matrix.rust }}
|
||||
override: true
|
||||
- run: cargo check --all-features
|
||||
- run: cargo test --no-default-features
|
||||
- run: cargo test
|
||||
- run: cargo test --all-features
|
||||
|
||||
24
.github/workflows/sha1.yml
vendored
24
.github/workflows/sha1.yml
vendored
@@ -36,7 +36,7 @@ jobs:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- run: cargo build --no-default-features --release --target ${{ matrix.target }}
|
||||
- run: cargo build --no-default-features --target ${{ matrix.target }}
|
||||
|
||||
# Linux tests
|
||||
linux:
|
||||
@@ -69,10 +69,10 @@ jobs:
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- run: ${{ matrix.deps }}
|
||||
- run: cargo test --target ${{ matrix.target }} --release --no-default-features
|
||||
- run: cargo test --target ${{ matrix.target }} --release
|
||||
- run: cargo test --target ${{ matrix.target }} --release --features asm
|
||||
- run: cargo test --target ${{ matrix.target }} --release --all-features
|
||||
- run: cargo test --target ${{ matrix.target }} --no-default-features
|
||||
- run: cargo test --target ${{ matrix.target }}
|
||||
- run: cargo test --target ${{ matrix.target }} --features asm
|
||||
- run: cargo test --target ${{ matrix.target }} --all-features
|
||||
|
||||
# macOS tests
|
||||
macos:
|
||||
@@ -91,10 +91,10 @@ jobs:
|
||||
toolchain: ${{ matrix.toolchain }}
|
||||
target: x86_64-apple-darwin
|
||||
override: true
|
||||
- run: cargo test --release --no-default-features
|
||||
- run: cargo test --release
|
||||
- run: cargo test --release --features asm
|
||||
- run: cargo test --release --all-features
|
||||
- run: cargo test --no-default-features
|
||||
- run: cargo test
|
||||
- run: cargo test --features asm
|
||||
- run: cargo test --all-features
|
||||
|
||||
# Windows tests
|
||||
windows:
|
||||
@@ -118,7 +118,7 @@ jobs:
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- uses: msys2/setup-msys2@v2
|
||||
- run: cargo test --target ${{ matrix.target }} --release
|
||||
- run: cargo test --target ${{ matrix.target }}
|
||||
|
||||
# Cross-compiled tests
|
||||
# *** NOTE: Currently broken with `asm` feature enabled! See:
|
||||
@@ -144,5 +144,5 @@ jobs:
|
||||
# target: ${{ matrix.target }}
|
||||
# override: true
|
||||
# - run: cargo install cross
|
||||
# - run: cross test --target ${{ matrix.target }} --release
|
||||
# - run: cross test --target ${{ matrix.target }} --release --features asm
|
||||
# - run: cross test --target ${{ matrix.target }}
|
||||
# - run: cross test --target ${{ matrix.target }} --features asm
|
||||
|
||||
33
.github/workflows/sha2.yml
vendored
33
.github/workflows/sha2.yml
vendored
@@ -36,7 +36,7 @@ jobs:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- run: cargo build --no-default-features --release --target ${{ matrix.target }}
|
||||
- run: cargo build --no-default-features --target ${{ matrix.target }}
|
||||
|
||||
# Linux tests
|
||||
linux:
|
||||
@@ -67,10 +67,10 @@ jobs:
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- run: ${{ matrix.deps }}
|
||||
- run: cargo test --target ${{ matrix.target }} --release --no-default-features
|
||||
- run: cargo test --target ${{ matrix.target }} --release
|
||||
- run: cargo test --target ${{ matrix.target }} --release --features asm
|
||||
- run: cargo test --target ${{ matrix.target }} --release --all-features
|
||||
- run: cargo test --target ${{ matrix.target }} --no-default-features
|
||||
- run: cargo test --target ${{ matrix.target }}
|
||||
- run: cargo test --target ${{ matrix.target }} --features asm
|
||||
- run: cargo test --target ${{ matrix.target }} --all-features
|
||||
|
||||
# macOS tests
|
||||
macos:
|
||||
@@ -89,9 +89,9 @@ jobs:
|
||||
toolchain: ${{ matrix.toolchain }}
|
||||
target: x86_64-apple-darwin
|
||||
override: true
|
||||
- run: cargo test --release --no-default-features
|
||||
- run: cargo test --release
|
||||
- run: cargo test --release --features asm
|
||||
- run: cargo test --no-default-features
|
||||
- run: cargo test
|
||||
- run: cargo test --features asm
|
||||
|
||||
# Windows tests
|
||||
windows:
|
||||
@@ -115,7 +115,7 @@ jobs:
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- uses: msys2/setup-msys2@v2
|
||||
- run: cargo test --target ${{ matrix.target }} --release
|
||||
- run: cargo test --target ${{ matrix.target }}
|
||||
|
||||
# Cross-compiled tests
|
||||
cross:
|
||||
@@ -129,6 +129,10 @@ jobs:
|
||||
rust: stable
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
# Cross mounts only current package, i.e. by default it ignores workspace's Cargo.toml
|
||||
working-directory: .
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions-rs/toolchain@v1
|
||||
@@ -137,6 +141,11 @@ jobs:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- run: cargo install cross
|
||||
- run: cross test --target ${{ matrix.target }} --release
|
||||
- run: cross test --target ${{ matrix.target }} --release --features asm
|
||||
- name: Install precompiled cross
|
||||
run: |
|
||||
export URL=$(curl -s https://api.github.com/repos/rust-embedded/cross/releases/latest | jq -r '.assets[] | select(.name | contains("x86_64-unknown-linux-gnu.tar.gz")) | .browser_download_url')
|
||||
wget -O /tmp/binaries.tar.gz $URL
|
||||
tar -C /tmp -xzf /tmp/binaries.tar.gz
|
||||
mv /tmp/cross ~/.cargo/bin
|
||||
- run: cross test --package sha2 --target ${{ matrix.target }}
|
||||
- run: cross test --package sha2 --target ${{ matrix.target }} --features asm
|
||||
|
||||
2
.github/workflows/sha3.yml
vendored
2
.github/workflows/sha3.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- run: cargo build --no-default-features --release --target ${{ matrix.target }}
|
||||
- run: cargo build --no-default-features --target ${{ matrix.target }}
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
2
.github/workflows/shabal.yml
vendored
2
.github/workflows/shabal.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- run: cargo build --no-default-features --release --target ${{ matrix.target }}
|
||||
- run: cargo build --no-default-features --target ${{ matrix.target }}
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
3
.github/workflows/sm3.yml
vendored
3
.github/workflows/sm3.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- run: cargo build --no-default-features --release --target ${{ matrix.target }}
|
||||
- run: cargo build --no-default-features --target ${{ matrix.target }}
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -55,4 +55,3 @@ jobs:
|
||||
- run: cargo test --no-default-features
|
||||
- run: cargo test
|
||||
- run: cargo test --all-features
|
||||
|
||||
|
||||
3
.github/workflows/streebog.yml
vendored
3
.github/workflows/streebog.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- run: cargo build --no-default-features --release --target ${{ matrix.target }}
|
||||
- run: cargo build --no-default-features --target ${{ matrix.target }}
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -55,4 +55,3 @@ jobs:
|
||||
- run: cargo test --no-default-features
|
||||
- run: cargo test
|
||||
- run: cargo test --all-features
|
||||
|
||||
|
||||
2
.github/workflows/tiger.yml
vendored
2
.github/workflows/tiger.yml
vendored
@@ -38,7 +38,7 @@ jobs:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- run: cargo build --no-default-features --release --target ${{ matrix.target }}
|
||||
- run: cargo build --no-default-features --target ${{ matrix.target }}
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
2
.github/workflows/whirlpool.yml
vendored
2
.github/workflows/whirlpool.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
toolchain: ${{ matrix.rust }}
|
||||
target: ${{ matrix.target }}
|
||||
override: true
|
||||
- run: cargo build --no-default-features --release --target ${{ matrix.target }}
|
||||
- run: cargo build --no-default-features --target ${{ matrix.target }}
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
163
Cargo.lock
generated
163
Cargo.lock
generated
@@ -4,50 +4,32 @@ version = 3
|
||||
|
||||
[[package]]
|
||||
name = "blake2"
|
||||
version = "0.9.2"
|
||||
version = "0.10.0"
|
||||
dependencies = [
|
||||
"crypto-mac",
|
||||
"digest",
|
||||
"hex-literal",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "blobby"
|
||||
version = "0.1.2"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fe5f8c2940b65859ece4b3b2ba02d2b12c87cab455fd42dee2556a187bb2cf6"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
]
|
||||
checksum = "847495c209977a90e8aad588b959d0ca9f5dc228096d29a6bd3defd53f35eaec"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
version = "0.9.0"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
|
||||
checksum = "f1d36a02058e76b040de25a4464ba1c80935655595b661505c8b39b664828b95"
|
||||
dependencies = [
|
||||
"block-padding",
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "block-padding"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.69"
|
||||
version = "1.0.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2"
|
||||
checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@@ -65,34 +47,33 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crypto-mac"
|
||||
version = "0.8.0"
|
||||
name = "crypto-common"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab"
|
||||
checksum = "567569e659735adb39ff2d4c20600f7cd78be5471f8c58ab162bce3c03fdbc5f"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8549e6bfdecd113b7e221fe60b433087f6957387a20f8118ebca9b12af19143d"
|
||||
dependencies = [
|
||||
"blobby",
|
||||
"block-buffer",
|
||||
"crypto-common",
|
||||
"generic-array",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
|
||||
dependencies = [
|
||||
"blobby",
|
||||
"generic-array",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fsb"
|
||||
version = "0.0.2"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"digest",
|
||||
"hex-literal",
|
||||
"opaque-debug",
|
||||
"whirlpool",
|
||||
]
|
||||
|
||||
@@ -108,22 +89,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "gost94"
|
||||
version = "0.9.1"
|
||||
version = "0.10.0"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"digest",
|
||||
"hex-literal",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "groestl"
|
||||
version = "0.9.0"
|
||||
version = "0.10.0"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"digest",
|
||||
"hex-literal",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -147,7 +124,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "k12"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"digest",
|
||||
"hex-literal",
|
||||
@@ -161,56 +138,44 @@ checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.101"
|
||||
version = "0.2.109"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3cb00336871be5ed2c8ed44b60ae9959dc5b9f08539422ed43f09e34ecaeba21"
|
||||
checksum = "f98a04dce437184842841303488f70d0188c5f51437d2a834dc097eafa909a01"
|
||||
|
||||
[[package]]
|
||||
name = "md-5"
|
||||
version = "0.9.1"
|
||||
version = "0.10.0"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"digest",
|
||||
"hex-literal",
|
||||
"md5-asm",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "md2"
|
||||
version = "0.9.0"
|
||||
version = "0.10.0"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"digest",
|
||||
"hex-literal",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "md4"
|
||||
version = "0.9.0"
|
||||
version = "0.10.0"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"digest",
|
||||
"hex-literal",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "md5-asm"
|
||||
version = "0.4.3"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3b47e5a1261ecd6ba951d1ad392534743310e513ef1e2609023368798829f33e"
|
||||
checksum = "73b9a6f25ec11ea27e22d7fc8beafda909da44ece95f63e94f1eeb23d19bb5c7"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opaque-debug"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.19"
|
||||
@@ -218,45 +183,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
|
||||
|
||||
[[package]]
|
||||
name = "ripemd160"
|
||||
version = "0.9.1"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"digest",
|
||||
"hex-literal",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ripemd256"
|
||||
name = "ripemd"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"digest",
|
||||
"hex-literal",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ripemd320"
|
||||
version = "0.9.0"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"digest",
|
||||
"hex-literal",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sha-1"
|
||||
version = "0.9.8"
|
||||
version = "0.10.0"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
"hex-literal",
|
||||
"opaque-debug",
|
||||
"sha1-asm",
|
||||
]
|
||||
|
||||
@@ -271,14 +212,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sha2"
|
||||
version = "0.9.8"
|
||||
version = "0.10.0"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"cfg-if",
|
||||
"cpufeatures",
|
||||
"digest",
|
||||
"hex-literal",
|
||||
"opaque-debug",
|
||||
"sha2-asm",
|
||||
]
|
||||
|
||||
@@ -293,43 +232,35 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sha3"
|
||||
version = "0.9.1"
|
||||
version = "0.10.0"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"digest",
|
||||
"hex-literal",
|
||||
"keccak",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shabal"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"digest",
|
||||
"hex-literal",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sm3"
|
||||
version = "0.3.0"
|
||||
version = "0.4.0"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"digest",
|
||||
"hex-literal",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "streebog"
|
||||
version = "0.9.2"
|
||||
version = "0.10.0"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"digest",
|
||||
"hex-literal",
|
||||
"opaque-debug",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -340,19 +271,17 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
|
||||
|
||||
[[package]]
|
||||
name = "tiger"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"byteorder",
|
||||
"digest",
|
||||
"hex-literal",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.13.0"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06"
|
||||
checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
@@ -362,20 +291,18 @@ checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
||||
|
||||
[[package]]
|
||||
name = "whirlpool"
|
||||
version = "0.9.0"
|
||||
version = "0.10.0"
|
||||
dependencies = [
|
||||
"block-buffer",
|
||||
"digest",
|
||||
"hex-literal",
|
||||
"opaque-debug",
|
||||
"whirlpool-asm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "whirlpool-asm"
|
||||
version = "0.5.2"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cbb23be8b0dec6fafef14563c42ec98bbfc33f2a97ed5bc99cd8b50ea5c68097"
|
||||
checksum = "4b0930846e800a97c78fd09a494b25d1f0780be9face03b7a05151e3104a8284"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"fsb",
|
||||
"blake2",
|
||||
"fsb",
|
||||
"gost94",
|
||||
"groestl",
|
||||
"k12",
|
||||
"md2",
|
||||
"md4",
|
||||
"md5",
|
||||
"ripemd160",
|
||||
"ripemd256",
|
||||
"ripemd320",
|
||||
"ripemd",
|
||||
"sha1",
|
||||
"sha2",
|
||||
"sha3",
|
||||
|
||||
227
README.md
227
README.md
@@ -1,99 +1,91 @@
|
||||
# RustCrypto: hashes [![Project Chat][chat-image]][chat-link] [![dependency status][deps-image]][deps-link]
|
||||
# RustCrypto: Hashes
|
||||
|
||||
[![Project Chat][chat-image]][chat-link] [![dependency status][deps-image]][deps-link] ![Apache2/MIT licensed][license-image]
|
||||
|
||||
Collection of [cryptographic hash functions][1] written in pure Rust.
|
||||
|
||||
All algorithms reside in the separate crates and implemented using traits from
|
||||
[`digest`](https://docs.rs/digest/) crate. Additionally all crates do not
|
||||
require the standard library (i.e. `no_std` capable) and can be easily used for
|
||||
bare-metal or WebAssembly programming.
|
||||
All algorithms reside in the separate crates and implemented using traits from [`digest`] crate.
|
||||
Additionally all crates do not require the standard library (i.e. `no_std` capable) and can be easily used for bare-metal or WebAssembly programming.
|
||||
|
||||
## Supported algorithms
|
||||
**Note:** For new applications, or where compatibility with other existing
|
||||
standards is not a primary concern, we strongly recommend to use either
|
||||
BLAKE2, SHA-2 or SHA-3.
|
||||
## Supported Algorithms
|
||||
|
||||
| Name | Algorithm | Crates.io | Documentation | Build Status | [Security] |
|
||||
|-------------|------------|-----------|---------------|--------------|------------|
|
||||
| `blake2` | [BLAKE2] | [](https://crates.io/crates/blake2) | [](https://docs.rs/blake2) | [](https://github.com/RustCrypto/hashes/actions?query=workflow:blake2+branch:master) | :green_heart: |
|
||||
| `fsb` | [FSB] | [](https://crates.io/crates/fsb) | [](https://docs.rs/fsb) | [](https://github.com/RustCrypto/fsb/actions?query=workflow:fsb+branch:master) | :green_heart: |
|
||||
| `gost94` | [GOST94] (GOST R 34.11-94) | [](https://crates.io/crates/gost94) | [](https://docs.rs/gost94) | [](https://github.com/RustCrypto/hashes/actions?query=workflow:gost94+branch:master) | :yellow_heart: |
|
||||
| `groestl` | [Grøstl] (Groestl) | [](https://crates.io/crates/groestl) | [](https://docs.rs/groestl) | [](https://github.com/RustCrypto/hashes/actions?query=workflow:groestl+branch:master) | :green_heart: |
|
||||
| `k12` | [KangarooTwelve] | [](https://crates.io/crates/k12) | [](https://docs.rs/k12) | [](https://github.com/RustCrypto/hashes/actions?query=workflow:k12+branch:master) | :green_heart: |
|
||||
| `md2` | [MD2] | [](https://crates.io/crates/md2) | [](https://docs.rs/md2) | [](https://github.com/RustCrypto/hashes/actions?query=workflow:md2+branch:master) | :broken_heart: |
|
||||
| `md4` | [MD4] | [](https://crates.io/crates/md4) | [](https://docs.rs/md4) | [](https://github.com/RustCrypto/hashes/actions?query=workflow:md4+branch:master) | :broken_heart: |
|
||||
| `md-5` [:exclamation:] | [MD5] | [](https://crates.io/crates/md-5) | [](https://docs.rs/md-5) | [](https://github.com/RustCrypto/hashes/actions?query=workflow:md5+branch:master) | :broken_heart: |
|
||||
| `ripemd160` | [RIPEMD-160] | [](https://crates.io/crates/ripemd160) | [](https://docs.rs/ripemd160) | [](https://github.com/RustCrypto/hashes/actions?query=workflow:ripemd160+branch:master) | :green_heart: |
|
||||
| `ripemd256` | [RIPEMD-256] | [](https://crates.io/crates/ripemd256) | [](https://docs.rs/ripemd256) | [](https://github.com/RustCrypto/hashes/actions?query=workflow:ripemd256+branch:master) | :green_heart:* |
|
||||
| `ripemd320` | [RIPEMD-320] | [](https://crates.io/crates/ripemd320) | [](https://docs.rs/ripemd320) | [](https://github.com/RustCrypto/hashes/actions?query=workflow:ripemd320+branch:master) | :green_heart:* |
|
||||
| `sha-1` [:exclamation:] | [SHA-1] | [](https://crates.io/crates/sha-1) | [](https://docs.rs/sha-1) | [](https://github.com/RustCrypto/hashes/actions?query=workflow:sha1+branch:master) | :broken_heart: |
|
||||
| `sha2` | [SHA-2] | [](https://crates.io/crates/sha2) | [](https://docs.rs/sha2) | [](https://github.com/RustCrypto/hashes/actions?query=workflow:sha2+branch:master) | :green_heart: |
|
||||
| `sha3` | [SHA-3] (Keccak) | [](https://crates.io/crates/sha3) | [](https://docs.rs/sha3) | [](https://github.com/RustCrypto/hashes/actions?query=workflow:sha3+branch:master) | :green_heart: |
|
||||
| `shabal` | [SHABAL] | [](https://crates.io/crates/shabal) | [](https://docs.rs/shabal) | [](https://github.com/RustCrypto/hashes/actions?query=workflow:shabal+branch:master) | :green_heart: |
|
||||
| `sm3` | [SM3 (OSCCA GM/T 0004-2012)][SM3] | [](https://crates.io/crates/sm3) | [](https://docs.rs/sm3) | [](https://github.com/RustCrypto/hashes/actions?query=workflow:sm3+branch:master) | :green_heart: |
|
||||
| `streebog` | [Streebog] (GOST R 34.11-2012) | [](https://crates.io/crates/streebog) | [](https://docs.rs/streebog) | [](https://github.com/RustCrypto/hashes/actions?query=workflow:streebog+branch:master) | :yellow_heart: |
|
||||
| `tiger` | [Tiger] | [](https://crates.io/crates/tiger) | [](https://docs.rs/tiger) | [](https://github.com/RustCrypto/hashes/actions?query=workflow:tiger+branch:master) | :green_heart: |
|
||||
| `whirlpool` | [Whirlpool] | [](https://crates.io/crates/whirlpool) | [](https://docs.rs/whirlpool) | [](https://github.com/RustCrypto/hashes/actions?query=workflow:whirlpool+branch:master) | :green_heart: |
|
||||
**Note:** For new applications, or where compatibility with other existing standards is not a primary concern, we strongly recommend to use either BLAKE2, SHA-2 or SHA-3.
|
||||
|
||||
NOTE: the [BLAKE3 crate](https://github.com/BLAKE3-team/BLAKE3) implements the `digest` (and `crypto-mac`) traits used by the rest of the hashes in this repository, but is maintained by the BLAKE3 team.
|
||||
| Algorithm | Crate | Crates.io | Documentation | MSRV | [Security] |
|
||||
|-----------|-------|:---------:|:-------------:|:----:|:----------:|
|
||||
| [BLAKE2] | [`blake2`] | [](https://crates.io/crates/blake2) | [](https://docs.rs/blake2) | ![MSRV 1.41][msrv-1.41] | :green_heart: |
|
||||
| [FSB] | [`fsb`] | [](https://crates.io/crates/fsb) | [](https://docs.rs/fsb) | ![MSRV 1.41][msrv-1.41] | :green_heart: |
|
||||
| [GOST R 34.11-94][GOST94] | [`gost94`] | [](https://crates.io/crates/gost94) | [](https://docs.rs/gost94) | ![MSRV 1.41][msrv-1.41] | :yellow_heart: |
|
||||
| [Grøstl] (Groestl) | [`groestl`] | [](https://crates.io/crates/groestl) | [](https://docs.rs/groestl) | ![MSRV 1.41][msrv-1.41] | :green_heart: |
|
||||
| [KangarooTwelve] | [`k12`] | [](https://crates.io/crates/k12) | [](https://docs.rs/k12) | ![MSRV 1.41][msrv-1.41] | :green_heart: |
|
||||
| [MD2] | [`md2`] | [](https://crates.io/crates/md2) | [](https://docs.rs/md2) | ![MSRV 1.41][msrv-1.41] | :broken_heart: |
|
||||
| [MD4] | [`md4`] | [](https://crates.io/crates/md4) | [](https://docs.rs/md4) | ![MSRV 1.41][msrv-1.41] | :broken_heart: |
|
||||
| [MD5] | [`md-5`] [:exclamation:] | [](https://crates.io/crates/md-5) | [](https://docs.rs/md-5) | ![MSRV 1.41][msrv-1.41] | :broken_heart: |
|
||||
| [RIPEMD] | [`ripemd`] | [](https://crates.io/crates/ripemd) | [](https://docs.rs/ripemd) | ![MSRV 1.41][msrv-1.41] | :green_heart: |
|
||||
| [SHA-1] | [`sha-1`] [:exclamation:] | [](https://crates.io/crates/sha-1) | [](https://docs.rs/sha-1) | ![MSRV 1.41][msrv-1.41] | :broken_heart: |
|
||||
| [SHA-2] | [`sha2`] | [](https://crates.io/crates/sha2) | [](https://docs.rs/sha2) | ![MSRV 1.41][msrv-1.41] | :green_heart: |
|
||||
| [SHA-3] (Keccak) | [`sha3`] | [](https://crates.io/crates/sha3) | [](https://docs.rs/sha3) | ![MSRV 1.41][msrv-1.41] | :green_heart: |
|
||||
| [SHABAL] | [`shabal`] | [](https://crates.io/crates/shabal) | [](https://docs.rs/shabal) | ![MSRV 1.41][msrv-1.41] | :green_heart: |
|
||||
| [SM3] (OSCCA GM/T 0004-2012) | [`sm3`] | [](https://crates.io/crates/sm3) | [](https://docs.rs/sm3) | ![MSRV 1.41][msrv-1.41] | :green_heart: |
|
||||
| [Streebog] (GOST R 34.11-2012) | [`streebog`] | [](https://crates.io/crates/streebog) | [](https://docs.rs/streebog) | ![MSRV 1.41][msrv-1.41] | :yellow_heart: |
|
||||
| [Tiger] | [`tiger`] | [](https://crates.io/crates/tiger) | [](https://docs.rs/tiger) | ![MSRV 1.41][msrv-1.41] | :green_heart: |
|
||||
| [Whirlpool] | [`whirlpool`] | [](https://crates.io/crates/whirlpool) | [](https://docs.rs/whirlpool) | ![MSRV 1.41][msrv-1.41] | :green_heart: |
|
||||
|
||||
\* RIPEMD-256 provides only the same security as RIPEMD-128, and RIPEMD-320 provides only the same security as RIPEMD-160
|
||||
NOTE: the [BLAKE3 crate](https://github.com/BLAKE3-team/BLAKE3) implements the `digest` traits used by the rest of the hashes in this repository, but is maintained by the BLAKE3 team.
|
||||
|
||||
[Security]: https://en.wikipedia.org/wiki/Hash_function_security_summary
|
||||
[:exclamation:]: #crate-names
|
||||
|
||||
### Crate names
|
||||
Whenever possible crates are published under the the same name as the crate
|
||||
folder. Owners of `md5` and `sha1` crates declined
|
||||
([1](https://github.com/stainless-steel/md5/pull/2),
|
||||
[2](https://github.com/mitsuhiko/rust-sha1/issues/17)) to participate in this
|
||||
project. This is why crates marked by :exclamation: are published under
|
||||
`md-5` and `sha-1` names respectively.
|
||||
### Crate Names
|
||||
|
||||
Whenever possible crates are published under the the same name as the crate folder.
|
||||
Owners of `md5` and `sha1` declined ([1](https://github.com/stainless-steel/md5/pull/2), [2](https://github.com/mitsuhiko/rust-sha1/issues/17)) to participate in this project.
|
||||
Those crates do not implement the [`digest`] traits, so they are not interoperable with the RustCrypto ecosystem.
|
||||
This is why crates marked by :exclamation: are published under `md-5` and `sha-1` names, but the libraries themselves are named as `md5` and `sha1`, i.e. inside `use` statements you should use `sha1`/`md5`, not `sha_1`/`md_5`.
|
||||
|
||||
### Security Level Legend
|
||||
The following describes the security level ratings associated with each
|
||||
hash function (i.e. algorithms, not the specific implementation):
|
||||
|
||||
The following describes the security level ratings associated with each hash function (i.e. algorithms, not the specific implementation):
|
||||
|
||||
| Heart | Description |
|
||||
|----------------|-------------|
|
||||
|:--------------:|-------------|
|
||||
| :green_heart: | No known successful attacks |
|
||||
| :yellow_heart: | Theoretical break: security lower than claimed |
|
||||
| :broken_heart: | Attack demonstrated in practice: avoid if at all possible |
|
||||
|
||||
See the [Security] page on Wikipedia for more information.
|
||||
|
||||
### Minimum Supported Rust Version (MSRV)
|
||||
All crates in this repository support Rust 1.21 or higher. In future
|
||||
minimally supported version of Rust can be changed, but it will be done with
|
||||
a minor version bump.
|
||||
### Minimum Supported Rust Version (MSRV) Policy
|
||||
|
||||
MSRV bumps are considered breaking changes and will be performed only with minor version bump.
|
||||
|
||||
## Usage
|
||||
Let us demonstrate how to use crates in this repository using BLAKE2b as an
|
||||
example.
|
||||
|
||||
First add `blake2` crate to your `Cargo.toml`:
|
||||
Let us demonstrate how to use crates in this repository using SHA-2 as an example.
|
||||
|
||||
First add [`sha2`](https://docs.rs/sha2) crate to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
blake2 = "0.9"
|
||||
sha2 = "0.10"
|
||||
```
|
||||
|
||||
Note that crates in this repository have an enabled by default `std` feature.
|
||||
Note that all crates in this repository have an enabled by default `std` feature.
|
||||
So if you plan to use the crate in `no_std` environments, don't forget to disable it:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
blake2 = { version="0.9", default-features = false }
|
||||
sha2 = { version = "0.10", default-features = false }
|
||||
```
|
||||
|
||||
`blake2` and other crates re-export `digest` crate and `Digest` trait for
|
||||
convenience, so you don't have to add `digest` crate as an explicit dependency.
|
||||
[`sha2`](https://docs.rs/sha2) and the other hash implementation crates re-export the [`digest`] crate and the [`Digest`] trait for convenience, so you don't have to include it in your `Cargo.toml` it as an explicit dependency.
|
||||
|
||||
Now you can write the following code:
|
||||
|
||||
```Rust
|
||||
use blake2::{Blake2b, Digest};
|
||||
```rust
|
||||
use sha2::{Sha256, Digest};
|
||||
|
||||
let mut hasher = Blake2b::new();
|
||||
let mut hasher = Sha256::new();
|
||||
let data = b"Hello world!";
|
||||
hasher.update(data);
|
||||
// `update` can be called repeatedly and is generic over `AsRef<[u8]>`
|
||||
@@ -103,64 +95,56 @@ let hash = hasher.finalize();
|
||||
println!("Result: {:x}", hash);
|
||||
```
|
||||
|
||||
In this example `hash` has type [`GenericArray<u8, U64>`][2], which is a generic
|
||||
alternative to `[u8; 64]`.
|
||||
In this example `hash` has type `GenericArray<u8, U32>`, which is a generic alternative to `[u8; 32]` defined in the [`generic-array`] crate.
|
||||
|
||||
Alternatively you can use chained approach, which is equivalent to the previous
|
||||
example:
|
||||
Alternatively, you can use chained approach, which is equivalent to the previous example:
|
||||
|
||||
```Rust
|
||||
use blake2::{Blake2b, Digest};
|
||||
```rust
|
||||
use sha2::{Sha256, Digest};
|
||||
|
||||
let hash = Blake2b::new()
|
||||
let hash = Sha256::new()
|
||||
.chain(b"Hello world!")
|
||||
.chain("String data")
|
||||
.finalize();
|
||||
println!("Result: {:x}", hash);
|
||||
```
|
||||
|
||||
If the whole message is available you also can use convenience `digest` method:
|
||||
If a complete message is available, then you also can use the convenience [`Digest::digest`] method:
|
||||
|
||||
```Rust
|
||||
use blake2::{Blake2b, Digest};
|
||||
```rust
|
||||
use sha2::{Sha256, Digest};
|
||||
|
||||
let hash = Blake2b::digest(b"my message");
|
||||
let hash = Sha256::digest(b"my message");
|
||||
println!("Result: {:x}", hash);
|
||||
```
|
||||
|
||||
### Hashing `Read`able objects
|
||||
### Hashing `Read`able Objects
|
||||
|
||||
If you want to hash data from [`Read`][3] trait (e.g. from file) you can rely on
|
||||
implementation of [`Write`][4] trait (requires an enabled-by-default `std` feature):
|
||||
If you want to hash data from a type which imlements the [`Read`] trait, you can rely on implementation of the [`Write`] trait (requires enabled-by-default `std` feature):
|
||||
|
||||
```Rust
|
||||
use blake2::{Blake2b, Digest};
|
||||
```rust
|
||||
use sha2::{Sha256, Digest};
|
||||
use std::{fs, io};
|
||||
|
||||
let mut file = fs::File::open(&path)?;
|
||||
let mut hasher = Blake2b::new();
|
||||
let mut hasher = Sha256::new();
|
||||
let n = io::copy(&mut file, &mut hasher)?;
|
||||
let hash = hasher.finalize();
|
||||
println!("Path: {}", path);
|
||||
|
||||
println!("Bytes processed: {}", n);
|
||||
println!("Hash value: {:x}", hash);
|
||||
```
|
||||
|
||||
### Hash-based Message Authentication Code (HMAC)
|
||||
|
||||
If you want to calculate [Hash-based Message Authentication Code][5] (HMAC),
|
||||
you can use generic implementation from [`hmac`](https://docs.rs/hmac) crate,
|
||||
which is a part of the [RustCrypto/MACs][6] repository.
|
||||
If you want to calculate [Hash-based Message Authentication Code][HMAC] (HMAC), you can use the generic implementation from [`hmac`] crate, which is a part of the [RustCrypto/MACs] repository.
|
||||
|
||||
### Generic code
|
||||
### Generic Code
|
||||
|
||||
You can write generic code over `Digest` (or other traits from `digest` crate)
|
||||
trait which will work over different hash functions:
|
||||
You can write generic code over the [`Digest`] trait (or other traits from the [`digest`] crate) which will work over different hash functions:
|
||||
|
||||
```Rust
|
||||
use digest::Digest;
|
||||
use blake2::Blake2b;
|
||||
use sha2::Sha256;
|
||||
```rust
|
||||
use sha2::{Sha256, Sha512, Digest};
|
||||
|
||||
// Toy example, do not use it in practice!
|
||||
// Instead use crates from: https://github.com/RustCrypto/password-hashing
|
||||
@@ -172,15 +156,31 @@ fn hash_password<D: Digest>(password: &str, salt: &str, output: &mut [u8]) {
|
||||
output.copy_from_slice(&hasher.finalize())
|
||||
}
|
||||
|
||||
let mut buf1 = [0u8; 64];
|
||||
hash_password::<Blake2b>("my_password", "abcd", &mut buf1);
|
||||
let mut buf1 = [0u8; 32];
|
||||
hash_password::<Sha256>("my_password", "abcd", &mut buf1);
|
||||
|
||||
let mut buf2 = [0u8; 32];
|
||||
hash_password::<Sha256>("my_password", "abcd", &mut buf2);
|
||||
let mut buf2 = [0u8; 64];
|
||||
hash_password::<Sha512>("my_password", "abcd", &mut buf2);
|
||||
```
|
||||
|
||||
If you want to use hash functions with trait objects, use `digest::DynDigest`
|
||||
trait.
|
||||
If you want to use hash functions with trait objects, you can use the [`DynDigest`] trait:
|
||||
|
||||
```rust
|
||||
use sha2::{Sha256, Sha512, digest::DynDigest};
|
||||
|
||||
fn dyn_hash(hasher: &mut dyn DynDigest, data: &[u8]) -> Box<[u8]> {
|
||||
hasher.update(data);
|
||||
hasher.finalize_reset()
|
||||
}
|
||||
|
||||
let mut sha256_hasher = Sha256::default();
|
||||
let mut sha512_hasher = Sha512::default();
|
||||
|
||||
let res1 = dyn_hash(&mut sha256_hasher, b"foo");
|
||||
let res2 = dyn_hash(&mut sha256_hasher, b"bar");
|
||||
let res3 = dyn_hash(&mut sha512_hasher, b"foo");
|
||||
let res4 = dyn_hash(&mut sha512_hasher, b"bar");
|
||||
```
|
||||
|
||||
## License
|
||||
|
||||
@@ -193,25 +193,50 @@ at your option.
|
||||
|
||||
### Contribution
|
||||
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted
|
||||
for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
|
||||
dual licensed as above, without any additional terms or conditions.
|
||||
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
|
||||
|
||||
[//]: # (badges)
|
||||
|
||||
[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg
|
||||
[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260041-hashes
|
||||
[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg
|
||||
[deps-image]: https://deps.rs/repo/github/RustCrypto/hashes/status.svg
|
||||
[deps-link]: https://deps.rs/repo/github/RustCrypto/hashes
|
||||
[msrv-1.41]: https://img.shields.io/badge/rustc-1.41.0+-blue.svg
|
||||
|
||||
[//]: # (crates)
|
||||
|
||||
[`blake2`]: ./blake2
|
||||
[`fsb`]: ./fsb
|
||||
[`gost94`]: ./gost94
|
||||
[`groestl`]: ./groestl
|
||||
[`k12`]: ./k12
|
||||
[`md2`]: ./md2
|
||||
[`md4`]: ./md4
|
||||
[`md-5`]: ./md-5
|
||||
[`ripemd`]: ./ripemd
|
||||
[`sha-1`]: ./sha1
|
||||
[`sha2`]: ./sha2
|
||||
[`sha3`]: ./sha3
|
||||
[`shabal`]: ./shabal
|
||||
[`sm3`]: ./sm3
|
||||
[`streebog`]: ./streebog
|
||||
[`tiger`]: ./tiger
|
||||
[`whirlpool`]: ./whirlpool
|
||||
|
||||
[//]: # (footnotes)
|
||||
|
||||
[1]: https://en.wikipedia.org/wiki/Cryptographic_hash_function
|
||||
[2]: https://docs.rs/generic-array
|
||||
[3]: https://doc.rust-lang.org/std/io/trait.Read.html
|
||||
[4]: https://doc.rust-lang.org/std/io/trait.Write.html
|
||||
[5]: https://en.wikipedia.org/wiki/Hash-based_message_authentication_code
|
||||
[6]: https://github.com/RustCrypto/MACs
|
||||
[`digest`]: https://docs.rs/digest
|
||||
[`Digest`]: https://docs.rs/digest/0.10.0/digest/trait.Digest.html
|
||||
[`Digest::digest`]: https://docs.rs/digest/0.10.0/digest/trait.Digest.html#tymethod.digest
|
||||
[`DynDigest`]: https://docs.rs/digest/0.10.0/digest/trait.DynDigest.html
|
||||
[`generic-array`]: https://docs.rs/generic-array
|
||||
[HMAC]: https://en.wikipedia.org/wiki/Hash-based_message_authentication_code
|
||||
[`Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
|
||||
[`Write`]: https://doc.rust-lang.org/std/io/trait.Write.html
|
||||
[`hmac`]: https://docs.rs/hmac
|
||||
[RustCrypto/MACs]: https://github.com/RustCrypto/MACs
|
||||
|
||||
[//]: # (algorithms)
|
||||
|
||||
@@ -223,9 +248,7 @@ dual licensed as above, without any additional terms or conditions.
|
||||
[MD2]: https://en.wikipedia.org/wiki/MD2_(cryptography)
|
||||
[MD4]: https://en.wikipedia.org/wiki/MD4
|
||||
[MD5]: https://en.wikipedia.org/wiki/MD5
|
||||
[RIPEMD-160]: https://en.wikipedia.org/wiki/RIPEMD
|
||||
[RIPEMD-256]: https://en.wikipedia.org/wiki/RIPEMD
|
||||
[RIPEMD-320]: https://en.wikipedia.org/wiki/RIPEMD
|
||||
[RIPEMD]: https://en.wikipedia.org/wiki/RIPEMD
|
||||
[SHA-1]: https://en.wikipedia.org/wiki/SHA-1
|
||||
[SHA-2]: https://en.wikipedia.org/wiki/SHA-2
|
||||
[SHA-3]: https://en.wikipedia.org/wiki/SHA-3
|
||||
|
||||
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.10.0 (2021-12-07)
|
||||
### Changed
|
||||
- Update to `digest` v0.10 and remove dependency on `crypto-mac` ([#217])
|
||||
|
||||
[#217]: https://github.com/RustCrypto/hashes/pull/217
|
||||
|
||||
## 0.9.2 (2021-08-25)
|
||||
### Fixed
|
||||
- Building with `simd_opt` on recent nightlies ([#301])
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "blake2"
|
||||
version = "0.9.2"
|
||||
name = "blake2" # Also update html_root_url in lib.rs when bumping this
|
||||
version = "0.10.0" # Also update html_root_url in lib.rs when bumping this
|
||||
description = "BLAKE2 hash functions"
|
||||
authors = ["RustCrypto Developers"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
@@ -12,18 +12,16 @@ keywords = ["crypto", "blake2", "hash", "digest"]
|
||||
categories = ["cryptography", "no-std"]
|
||||
|
||||
[dependencies]
|
||||
digest = "0.9"
|
||||
crypto-mac = "0.8"
|
||||
opaque-debug = "0.3"
|
||||
digest = { version = "0.10", features = ["mac"] }
|
||||
|
||||
[dev-dependencies]
|
||||
digest = { version = "0.9", features = ["dev"] }
|
||||
crypto-mac = { version = "0.8", features = ["dev"] }
|
||||
digest = { version = "0.10", features = ["dev"] }
|
||||
hex-literal = "0.2"
|
||||
|
||||
[features]
|
||||
default = ["std"]
|
||||
std = ["digest/std", "crypto-mac/std"]
|
||||
std = ["digest/std"]
|
||||
reset = [] # Enable reset functionality
|
||||
simd = []
|
||||
simd_opt = ["simd"]
|
||||
simd_asm = ["simd_opt"]
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
#![no_std]
|
||||
#![feature(test)]
|
||||
|
||||
digest::bench!(blake2::Blake2b);
|
||||
@@ -1,4 +0,0 @@
|
||||
#![no_std]
|
||||
#![feature(test)]
|
||||
|
||||
digest::bench!(blake2::Blake2s);
|
||||
22
blake2/benches/mod.rs
Normal file
22
blake2/benches/mod.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
#![feature(test)]
|
||||
extern crate test;
|
||||
|
||||
use blake2::{Blake2b512, Blake2s256};
|
||||
use digest::bench_update;
|
||||
use test::Bencher;
|
||||
|
||||
bench_update!(
|
||||
Blake2b512::default();
|
||||
blake2b512_10 10;
|
||||
blake2b512_100 100;
|
||||
blake2b512_1000 1000;
|
||||
blake2b512_10000 10000;
|
||||
);
|
||||
|
||||
bench_update!(
|
||||
Blake2s256::default();
|
||||
blake2s256_10 10;
|
||||
blake2s256_100 100;
|
||||
blake2s256_1000 1000;
|
||||
blake2s256_10000 10000;
|
||||
);
|
||||
@@ -1,47 +0,0 @@
|
||||
use blake2::{Blake2b, Digest};
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::io::{self, Read};
|
||||
|
||||
const BUFFER_SIZE: usize = 1024;
|
||||
|
||||
/// Print digest result as hex string and name pair
|
||||
fn print_result(sum: &[u8], name: &str) {
|
||||
for byte in sum {
|
||||
print!("{:02x}", byte);
|
||||
}
|
||||
println!("\t{}", name);
|
||||
}
|
||||
|
||||
/// Compute digest value for given `Reader` and print it
|
||||
/// On any error simply return without doing anything
|
||||
fn process<D: Digest + Default, R: Read>(reader: &mut R, name: &str) {
|
||||
let mut sh = D::default();
|
||||
let mut buffer = [0u8; BUFFER_SIZE];
|
||||
loop {
|
||||
let n = match reader.read(&mut buffer) {
|
||||
Ok(n) => n,
|
||||
Err(_) => return,
|
||||
};
|
||||
sh.update(&buffer[..n]);
|
||||
if n == 0 || n < BUFFER_SIZE {
|
||||
break;
|
||||
}
|
||||
}
|
||||
print_result(&sh.finalize(), name);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = env::args();
|
||||
// Process files listed in command line arguments one by one
|
||||
// If no files provided process input from stdin
|
||||
if args.len() > 1 {
|
||||
for path in args.skip(1) {
|
||||
if let Ok(mut file) = fs::File::open(&path) {
|
||||
process::<Blake2b, _>(&mut file, &path);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
process::<Blake2b, _>(&mut io::stdin(), "-");
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
use blake2::{Blake2s, Digest};
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::io::{self, Read};
|
||||
|
||||
const BUFFER_SIZE: usize = 1024;
|
||||
|
||||
/// Print digest result as hex string and name pair
|
||||
fn print_result(sum: &[u8], name: &str) {
|
||||
for byte in sum {
|
||||
print!("{:02x}", byte);
|
||||
}
|
||||
println!("\t{}", name);
|
||||
}
|
||||
|
||||
/// Compute digest value for given `Reader` and print it
|
||||
/// On any error simply return without doing anything
|
||||
fn process<D: Digest + Default, R: Read>(reader: &mut R, name: &str) {
|
||||
let mut sh = D::default();
|
||||
let mut buffer = [0u8; BUFFER_SIZE];
|
||||
loop {
|
||||
let n = match reader.read(&mut buffer) {
|
||||
Ok(n) => n,
|
||||
Err(_) => return,
|
||||
};
|
||||
sh.update(&buffer[..n]);
|
||||
if n == 0 || n < BUFFER_SIZE {
|
||||
break;
|
||||
}
|
||||
}
|
||||
print_result(&sh.finalize(), name);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = env::args();
|
||||
// Process files listed in command line arguments one by one
|
||||
// If no files provided process input from stdin
|
||||
if args.len() > 1 {
|
||||
for path in args.skip(1) {
|
||||
if let Ok(mut file) = fs::File::open(&path) {
|
||||
process::<Blake2s, _>(&mut file, &path);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
process::<Blake2s, _>(&mut io::stdin(), "-");
|
||||
}
|
||||
}
|
||||
@@ -1,414 +0,0 @@
|
||||
macro_rules! blake2_impl {
|
||||
(
|
||||
$state:ident, $fix_state:ident, $word:ident, $vec:ident, $bytes:ident,
|
||||
$block_size:ident, $R1:expr, $R2:expr, $R3:expr, $R4:expr, $IV:expr,
|
||||
$vardoc:expr, $doc:expr,
|
||||
) => {
|
||||
use $crate::as_bytes::AsBytes;
|
||||
use $crate::simd::{$vec, Vector4};
|
||||
|
||||
use core::{cmp, convert::TryInto, ops::Div};
|
||||
use crypto_mac::{InvalidKeyLength, Mac, NewMac};
|
||||
use digest::generic_array::typenum::{Unsigned, U4};
|
||||
use digest::generic_array::GenericArray;
|
||||
use digest::InvalidOutputSize;
|
||||
use digest::{BlockInput, FixedOutputDirty, Reset, Update, VariableOutputDirty};
|
||||
|
||||
type Output = GenericArray<u8, $bytes>;
|
||||
|
||||
#[derive(Clone)]
|
||||
#[doc=$vardoc]
|
||||
pub struct $state {
|
||||
m: [$word; 16],
|
||||
h: [$vec; 2],
|
||||
t: u64,
|
||||
n: usize,
|
||||
|
||||
h0: [$vec; 2],
|
||||
m0: [$word; 16],
|
||||
t0: u64,
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn iv0() -> $vec {
|
||||
$vec::new($IV[0], $IV[1], $IV[2], $IV[3])
|
||||
}
|
||||
#[inline(always)]
|
||||
fn iv1() -> $vec {
|
||||
$vec::new($IV[4], $IV[5], $IV[6], $IV[7])
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn quarter_round(v: &mut [$vec; 4], rd: u32, rb: u32, m: $vec) {
|
||||
v[0] = v[0].wrapping_add(v[1]).wrapping_add(m.from_le());
|
||||
v[3] = (v[3] ^ v[0]).rotate_right_const(rd);
|
||||
v[2] = v[2].wrapping_add(v[3]);
|
||||
v[1] = (v[1] ^ v[2]).rotate_right_const(rb);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn shuffle(v: &mut [$vec; 4]) {
|
||||
v[1] = v[1].shuffle_left_1();
|
||||
v[2] = v[2].shuffle_left_2();
|
||||
v[3] = v[3].shuffle_left_3();
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn unshuffle(v: &mut [$vec; 4]) {
|
||||
v[1] = v[1].shuffle_right_1();
|
||||
v[2] = v[2].shuffle_right_2();
|
||||
v[3] = v[3].shuffle_right_3();
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn round(v: &mut [$vec; 4], m: &[$word; 16], s: &[usize; 16]) {
|
||||
quarter_round(v, $R1, $R2, $vec::gather(m, s[0], s[2], s[4], s[6]));
|
||||
quarter_round(v, $R3, $R4, $vec::gather(m, s[1], s[3], s[5], s[7]));
|
||||
|
||||
shuffle(v);
|
||||
quarter_round(v, $R1, $R2, $vec::gather(m, s[8], s[10], s[12], s[14]));
|
||||
quarter_round(v, $R3, $R4, $vec::gather(m, s[9], s[11], s[13], s[15]));
|
||||
unshuffle(v);
|
||||
}
|
||||
|
||||
impl $state {
|
||||
/// Creates a new hashing context with a key.
|
||||
///
|
||||
/// **WARNING!** If you plan to use it for variable output MAC, then
|
||||
/// make sure to compare codes in constant time! It can be done
|
||||
/// for example by using `subtle` crate.
|
||||
pub fn new_keyed(key: &[u8], output_size: usize) -> Self {
|
||||
Self::with_params(key, &[], &[], output_size)
|
||||
}
|
||||
|
||||
/// Creates a new hashing context with the full set of sequential-mode parameters.
|
||||
pub fn with_params(
|
||||
key: &[u8],
|
||||
salt: &[u8],
|
||||
persona: &[u8],
|
||||
output_size: usize,
|
||||
) -> Self {
|
||||
let kk = key.len();
|
||||
assert!(kk <= $bytes::to_usize());
|
||||
assert!(output_size <= $bytes::to_usize());
|
||||
|
||||
// The number of bytes needed to express two words.
|
||||
let length = $bytes::to_usize() / 4;
|
||||
assert!(salt.len() <= length);
|
||||
assert!(persona.len() <= length);
|
||||
|
||||
// Build a parameter block
|
||||
let mut p = [0 as $word; 8];
|
||||
p[0] = 0x0101_0000 ^ ((kk as $word) << 8) ^ (output_size as $word);
|
||||
|
||||
// salt is two words long
|
||||
if salt.len() < length {
|
||||
let mut padded_salt =
|
||||
GenericArray::<u8, <$bytes as Div<U4>>::Output>::default();
|
||||
for i in 0..salt.len() {
|
||||
padded_salt[i] = salt[i];
|
||||
}
|
||||
p[4] = $word::from_le_bytes(padded_salt[0..length / 2].try_into().unwrap());
|
||||
p[5] = $word::from_le_bytes(
|
||||
padded_salt[length / 2..padded_salt.len()]
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
);
|
||||
} else {
|
||||
p[4] = $word::from_le_bytes(salt[0..salt.len() / 2].try_into().unwrap());
|
||||
p[5] =
|
||||
$word::from_le_bytes(salt[salt.len() / 2..salt.len()].try_into().unwrap());
|
||||
}
|
||||
|
||||
// persona is also two words long
|
||||
if persona.len() < length {
|
||||
let mut padded_persona =
|
||||
GenericArray::<u8, <$bytes as Div<U4>>::Output>::default();
|
||||
for i in 0..persona.len() {
|
||||
padded_persona[i] = persona[i];
|
||||
}
|
||||
p[6] = $word::from_le_bytes(padded_persona[0..length / 2].try_into().unwrap());
|
||||
p[7] = $word::from_le_bytes(
|
||||
padded_persona[length / 2..padded_persona.len()]
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
);
|
||||
} else {
|
||||
p[6] = $word::from_le_bytes(persona[0..length / 2].try_into().unwrap());
|
||||
p[7] = $word::from_le_bytes(
|
||||
persona[length / 2..persona.len()].try_into().unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
let mut state = Self::with_parameter_block(&p);
|
||||
|
||||
if kk > 0 {
|
||||
copy(key, state.m.as_mut_bytes());
|
||||
state.t = 2 * $bytes::to_u64();
|
||||
}
|
||||
|
||||
state.t0 = state.t;
|
||||
state.m0 = state.m;
|
||||
state
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn with_parameter_block(p: &[$word; 8]) -> Self {
|
||||
let nn = p[0] as u8 as usize;
|
||||
let kk = (p[0] >> 8) as u8 as usize;
|
||||
assert!(nn >= 1 && nn <= $bytes::to_usize());
|
||||
assert!(kk <= $bytes::to_usize());
|
||||
|
||||
let h0 = [
|
||||
iv0() ^ $vec::new(p[0], p[1], p[2], p[3]),
|
||||
iv1() ^ $vec::new(p[4], p[5], p[6], p[7]),
|
||||
];
|
||||
|
||||
$state {
|
||||
m: [0; 16],
|
||||
h: h0,
|
||||
t: 0,
|
||||
n: nn,
|
||||
|
||||
t0: 0,
|
||||
m0: [0; 16],
|
||||
h0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Updates the hashing context with more data.
|
||||
fn update(&mut self, data: &[u8]) {
|
||||
let mut rest = data;
|
||||
|
||||
let block = 2 * $bytes::to_usize();
|
||||
|
||||
let off = self.t as usize % block;
|
||||
if off != 0 || self.t == 0 {
|
||||
let len = cmp::min(block - off, rest.len());
|
||||
|
||||
let part = &rest[..len];
|
||||
rest = &rest[part.len()..];
|
||||
|
||||
copy(part, &mut self.m.as_mut_bytes()[off..]);
|
||||
self.t = self
|
||||
.t
|
||||
.checked_add(part.len() as u64)
|
||||
.expect("hash data length overflow");
|
||||
}
|
||||
|
||||
while rest.len() >= block {
|
||||
self.compress(0, 0);
|
||||
|
||||
let part = &rest[..block];
|
||||
rest = &rest[part.len()..];
|
||||
|
||||
copy(part, &mut self.m.as_mut_bytes());
|
||||
self.t = self
|
||||
.t
|
||||
.checked_add(part.len() as u64)
|
||||
.expect("hash data length overflow");
|
||||
}
|
||||
|
||||
let n = rest.len();
|
||||
if n > 0 {
|
||||
self.compress(0, 0);
|
||||
|
||||
copy(rest, &mut self.m.as_mut_bytes());
|
||||
self.t = self
|
||||
.t
|
||||
.checked_add(rest.len() as u64)
|
||||
.expect("hash data length overflow");
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn finalize_last_node(mut self) -> Output {
|
||||
self.finalize_with_flag(!0)
|
||||
}
|
||||
|
||||
fn finalize_with_flag(&mut self, f1: $word) -> Output {
|
||||
let off = self.t as usize % (2 * $bytes::to_usize());
|
||||
if off != 0 {
|
||||
self.m.as_mut_bytes()[off..].iter_mut().for_each(|b| *b = 0);
|
||||
}
|
||||
|
||||
self.compress(!0, f1);
|
||||
|
||||
let buf = [self.h[0].to_le(), self.h[1].to_le()];
|
||||
|
||||
let mut out = GenericArray::default();
|
||||
copy(buf.as_bytes(), &mut out);
|
||||
out
|
||||
}
|
||||
|
||||
fn compress(&mut self, f0: $word, f1: $word) {
|
||||
use $crate::consts::SIGMA;
|
||||
|
||||
let m = &self.m;
|
||||
let h = &mut self.h;
|
||||
|
||||
let t0 = self.t as $word;
|
||||
let t1 = match $bytes::to_u8() {
|
||||
64 => 0,
|
||||
32 => (self.t >> 32) as $word,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let mut v = [h[0], h[1], iv0(), iv1() ^ $vec::new(t0, t1, f0, f1)];
|
||||
|
||||
round(&mut v, m, &SIGMA[0]);
|
||||
round(&mut v, m, &SIGMA[1]);
|
||||
round(&mut v, m, &SIGMA[2]);
|
||||
round(&mut v, m, &SIGMA[3]);
|
||||
round(&mut v, m, &SIGMA[4]);
|
||||
round(&mut v, m, &SIGMA[5]);
|
||||
round(&mut v, m, &SIGMA[6]);
|
||||
round(&mut v, m, &SIGMA[7]);
|
||||
round(&mut v, m, &SIGMA[8]);
|
||||
round(&mut v, m, &SIGMA[9]);
|
||||
if $bytes::to_u8() == 64 {
|
||||
round(&mut v, m, &SIGMA[0]);
|
||||
round(&mut v, m, &SIGMA[1]);
|
||||
}
|
||||
|
||||
h[0] = h[0] ^ (v[0] ^ v[2]);
|
||||
h[1] = h[1] ^ (v[1] ^ v[3]);
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for $state {
|
||||
fn default() -> Self {
|
||||
Self::new_keyed(&[], $bytes::to_usize())
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockInput for $state {
|
||||
type BlockSize = $block_size;
|
||||
}
|
||||
|
||||
impl Update for $state {
|
||||
fn update(&mut self, data: impl AsRef<[u8]>) {
|
||||
self.update(data.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
impl VariableOutputDirty for $state {
|
||||
fn new(output_size: usize) -> Result<Self, InvalidOutputSize> {
|
||||
if output_size == 0 || output_size > $bytes::to_usize() {
|
||||
return Err(InvalidOutputSize);
|
||||
}
|
||||
Ok(Self::new_keyed(&[], output_size))
|
||||
}
|
||||
|
||||
fn output_size(&self) -> usize {
|
||||
self.n
|
||||
}
|
||||
|
||||
fn finalize_variable_dirty(&mut self, f: impl FnOnce(&[u8])) {
|
||||
let n = self.n;
|
||||
let res = self.finalize_with_flag(0);
|
||||
f(&res[..n]);
|
||||
}
|
||||
}
|
||||
|
||||
impl Reset for $state {
|
||||
fn reset(&mut self) {
|
||||
self.t = self.t0;
|
||||
self.m = self.m0;
|
||||
self.h = self.h0;
|
||||
}
|
||||
}
|
||||
|
||||
opaque_debug::implement!($state);
|
||||
digest::impl_write!($state);
|
||||
|
||||
#[derive(Clone)]
|
||||
#[doc=$doc]
|
||||
pub struct $fix_state {
|
||||
state: $state,
|
||||
}
|
||||
|
||||
impl $fix_state {
|
||||
/// Creates a new hashing context with the full set of sequential-mode parameters.
|
||||
pub fn with_params(key: &[u8], salt: &[u8], persona: &[u8]) -> Self {
|
||||
let state = $state::with_params(key, salt, persona, $bytes::to_usize());
|
||||
Self { state }
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for $fix_state {
|
||||
fn default() -> Self {
|
||||
let state = $state::new_keyed(&[], $bytes::to_usize());
|
||||
Self { state }
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockInput for $fix_state {
|
||||
type BlockSize = $block_size;
|
||||
}
|
||||
|
||||
impl Update for $fix_state {
|
||||
fn update(&mut self, data: impl AsRef<[u8]>) {
|
||||
self.state.update(data.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
impl FixedOutputDirty for $fix_state {
|
||||
type OutputSize = $bytes;
|
||||
|
||||
fn finalize_into_dirty(&mut self, out: &mut Output) {
|
||||
out.copy_from_slice(&self.state.finalize_with_flag(0));
|
||||
}
|
||||
}
|
||||
|
||||
impl Reset for $fix_state {
|
||||
fn reset(&mut self) {
|
||||
self.state.reset()
|
||||
}
|
||||
}
|
||||
|
||||
impl NewMac for $fix_state {
|
||||
type KeySize = $bytes;
|
||||
|
||||
fn new(key: &GenericArray<u8, $bytes>) -> Self {
|
||||
let state = $state::new_keyed(key, $bytes::to_usize());
|
||||
Self { state }
|
||||
}
|
||||
|
||||
fn new_varkey(key: &[u8]) -> Result<Self, InvalidKeyLength> {
|
||||
if key.len() > $bytes::to_usize() {
|
||||
Err(InvalidKeyLength)
|
||||
} else {
|
||||
let state = $state::new_keyed(key, $bytes::to_usize());
|
||||
Ok(Self { state })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Mac for $fix_state {
|
||||
type OutputSize = $bytes;
|
||||
|
||||
fn update(&mut self, data: &[u8]) {
|
||||
self.state.update(data);
|
||||
}
|
||||
|
||||
fn reset(&mut self) {
|
||||
<Self as Reset>::reset(self)
|
||||
}
|
||||
|
||||
fn finalize(mut self) -> crypto_mac::Output<Self> {
|
||||
crypto_mac::Output::new(self.state.finalize_with_flag(0))
|
||||
}
|
||||
}
|
||||
|
||||
opaque_debug::implement!($fix_state);
|
||||
digest::impl_write!($fix_state);
|
||||
|
||||
fn copy(src: &[u8], dst: &mut [u8]) {
|
||||
assert!(dst.len() >= src.len());
|
||||
unsafe {
|
||||
core::ptr::copy_nonoverlapping(src.as_ptr(), dst.as_mut_ptr(), src.len());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
use crate::consts::BLAKE2B_IV;
|
||||
use digest::generic_array::typenum::{U128, U64};
|
||||
|
||||
blake2_impl!(
|
||||
VarBlake2b,
|
||||
Blake2b,
|
||||
u64,
|
||||
u64x4,
|
||||
U64,
|
||||
U128,
|
||||
32,
|
||||
24,
|
||||
16,
|
||||
63,
|
||||
BLAKE2B_IV,
|
||||
"Blake2b instance with a variable output.",
|
||||
"Blake2b instance with a fixed output.",
|
||||
);
|
||||
@@ -1,18 +0,0 @@
|
||||
use crate::consts::BLAKE2S_IV;
|
||||
use digest::generic_array::typenum::{U32, U64};
|
||||
|
||||
blake2_impl!(
|
||||
VarBlake2s,
|
||||
Blake2s,
|
||||
u32,
|
||||
u32x4,
|
||||
U32,
|
||||
U64,
|
||||
16,
|
||||
12,
|
||||
8,
|
||||
7,
|
||||
BLAKE2S_IV,
|
||||
"Blake2s instance with a variable output.",
|
||||
"Blake2s instance with a fixed output.",
|
||||
);
|
||||
@@ -2,14 +2,14 @@
|
||||
//!
|
||||
//! # Usage
|
||||
//!
|
||||
//! `Blake2b` can be used in the following way:
|
||||
//! [`Blake2b512`] and [`Blake2s256`] can be used in the following way:
|
||||
//!
|
||||
//! ```rust
|
||||
//! use blake2::{Blake2b, Blake2s, Digest};
|
||||
//! use blake2::{Blake2b512, Blake2s256, Digest};
|
||||
//! use hex_literal::hex;
|
||||
//!
|
||||
//! // create a Blake2b object
|
||||
//! let mut hasher = Blake2b::new();
|
||||
//! // create a Blake2b512 object
|
||||
//! let mut hasher = Blake2b512::new();
|
||||
//!
|
||||
//! // write input message
|
||||
//! hasher.update(b"hello world");
|
||||
@@ -21,8 +21,8 @@
|
||||
//! c05a037cddbed06e309bf334942c4e58cdf1a46e237911ccd7fcf9787cbc7fd0
|
||||
//! ")[..]);
|
||||
//!
|
||||
//! // same example for `Blake2s`:
|
||||
//! let mut hasher = Blake2s::new();
|
||||
//! // same example for Blake2s256:
|
||||
//! let mut hasher = Blake2s256::new();
|
||||
//! hasher.update(b"hello world");
|
||||
//! let res = hasher.finalize();
|
||||
//! assert_eq!(res[..], hex!("
|
||||
@@ -34,45 +34,32 @@
|
||||
//!
|
||||
//! ## Variable output size
|
||||
//!
|
||||
//! If you need variable sized output you can use `VarBlake2b` and `VarBlake2s`
|
||||
//! which support variable output sizes through `VariableOutput` trait. `Update`
|
||||
//! trait has to be imported as well.
|
||||
//! This implementation supports run and compile time variable sizes.
|
||||
//!
|
||||
//! Run time variable output example:
|
||||
//! ```rust
|
||||
//! use blake2::VarBlake2b;
|
||||
//! use blake2::Blake2bVar;
|
||||
//! use blake2::digest::{Update, VariableOutput};
|
||||
//! use hex_literal::hex;
|
||||
//!
|
||||
//! let mut hasher = VarBlake2b::new(10).unwrap();
|
||||
//! let mut hasher = Blake2bVar::new(10).unwrap();
|
||||
//! hasher.update(b"my_input");
|
||||
//! hasher.finalize_variable(|res| {
|
||||
//! assert_eq!(res, [44, 197, 92, 132, 228, 22, 146, 78, 100, 0])
|
||||
//! })
|
||||
//! let mut buf = [0u8; 10];
|
||||
//! hasher.finalize_variable(&mut buf).unwrap();
|
||||
//! assert_eq!(buf, hex!("2cc55c84e416924e6400"));
|
||||
//! ```
|
||||
//!
|
||||
//! ## Message Authentication Code (MAC)
|
||||
//!
|
||||
//! BLAKE2 can be used as a MAC without any additional constructs:
|
||||
//!
|
||||
//! Compile time variable output example:
|
||||
//! ```rust
|
||||
//! use blake2::Blake2b;
|
||||
//! use blake2::crypto_mac::{Mac, NewMac};
|
||||
//! use blake2::{Blake2b, Digest, digest::consts::U10};
|
||||
//! use hex_literal::hex;
|
||||
//!
|
||||
//! let mut hasher = Blake2b::new_varkey(b"my key").unwrap();
|
||||
//! hasher.update(b"hello world");
|
||||
//! type Blake2b80 = Blake2b<U10>;
|
||||
//!
|
||||
//! // `result` has type `crypto_mac::Output` which is a thin wrapper around
|
||||
//! // a byte array and provides a constant time equality check
|
||||
//! let result = hasher.finalize();
|
||||
//! // To get underlying array use the `into_bytes` method, but be careful,
|
||||
//! // since incorrect use of the code value may permit timing attacks which
|
||||
//! // defeat the security provided by the `crypto_mac::Output`
|
||||
//! let code_bytes = result.into_bytes();
|
||||
//!
|
||||
//! // To verify the message it's recommended to use `verify` method
|
||||
//! let mut hasher = Blake2b::new_varkey(b"my key").unwrap();
|
||||
//! hasher.update(b"hello world");
|
||||
//! // `verify` return `Ok(())` if code is correct, `Err(MacError)` otherwise
|
||||
//! hasher.verify(&code_bytes).unwrap();
|
||||
//! let mut hasher = Blake2b80::new();
|
||||
//! hasher.update(b"my_input");
|
||||
//! let res = hasher.finalize();
|
||||
//! assert_eq!(res[..], hex!("2cc55c84e416924e6400")[..]);
|
||||
//! ```
|
||||
//!
|
||||
//! # Acknowledgment
|
||||
@@ -83,8 +70,9 @@
|
||||
|
||||
#![no_std]
|
||||
#![doc(
|
||||
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
|
||||
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
|
||||
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
|
||||
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
|
||||
html_root_url = "https://docs.rs/blake2/0.10.0"
|
||||
)]
|
||||
#![warn(missing_docs, rust_2018_idioms)]
|
||||
#![cfg_attr(feature = "simd", feature(platform_intrinsics, repr_simd))]
|
||||
@@ -94,19 +82,95 @@
|
||||
#[cfg(feature = "std")]
|
||||
extern crate std;
|
||||
|
||||
pub use digest::{self, Digest};
|
||||
|
||||
use core::{convert::TryInto, fmt, marker::PhantomData, ops::Div};
|
||||
use digest::{
|
||||
block_buffer::{Lazy, LazyBuffer},
|
||||
consts::{U128, U32, U4, U64},
|
||||
core_api::{
|
||||
AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, CoreWrapper,
|
||||
CtVariableCoreWrapper, OutputSizeUser, RtVariableCoreWrapper, TruncSide, UpdateCore,
|
||||
VariableOutputCore,
|
||||
},
|
||||
crypto_common::{InvalidLength, Key, KeyInit, KeySizeUser},
|
||||
generic_array::{
|
||||
typenum::{IsLessOrEqual, LeEq, NonZero, Unsigned},
|
||||
ArrayLength, GenericArray,
|
||||
},
|
||||
FixedOutput, HashMarker, InvalidOutputSize, MacMarker, Output, Update,
|
||||
};
|
||||
#[cfg(feature = "reset")]
|
||||
use digest::{FixedOutputReset, Reset};
|
||||
|
||||
mod as_bytes;
|
||||
mod consts;
|
||||
|
||||
mod simd;
|
||||
|
||||
#[macro_use]
|
||||
mod blake2;
|
||||
mod macros;
|
||||
|
||||
mod blake2b;
|
||||
mod blake2s;
|
||||
use as_bytes::AsBytes;
|
||||
use consts::{BLAKE2B_IV, BLAKE2S_IV};
|
||||
use simd::{u32x4, u64x4, Vector4};
|
||||
|
||||
pub use crypto_mac;
|
||||
pub use digest::{self, Digest};
|
||||
blake2_impl!(
|
||||
Blake2bVarCore,
|
||||
"Blake2b",
|
||||
u64,
|
||||
u64x4,
|
||||
U64,
|
||||
U128,
|
||||
32,
|
||||
24,
|
||||
16,
|
||||
63,
|
||||
BLAKE2B_IV,
|
||||
"Blake2b instance with a variable output.",
|
||||
"Blake2b instance with a fixed output.",
|
||||
);
|
||||
|
||||
pub use crate::blake2b::{Blake2b, VarBlake2b};
|
||||
pub use crate::blake2s::{Blake2s, VarBlake2s};
|
||||
/// BLAKE2b which allows to choose output size at runtime.
|
||||
pub type Blake2bVar = RtVariableCoreWrapper<Blake2bVarCore>;
|
||||
/// Core hasher state of BLAKE2b generic over output size.
|
||||
pub type Blake2bCore<OutSize> = CtVariableCoreWrapper<Blake2bVarCore, OutSize>;
|
||||
/// BLAKE2b generic over output size.
|
||||
pub type Blake2b<OutSize> = CoreWrapper<Blake2bCore<OutSize>>;
|
||||
/// BLAKE2b-512 hasher state.
|
||||
pub type Blake2b512 = Blake2b<U64>;
|
||||
|
||||
blake2_mac_impl!(Blake2bMac, Blake2bVarCore, U64, "Blake2b MAC function");
|
||||
|
||||
/// BLAKE2b-512 MAC state.
|
||||
pub type Blake2bMac512 = Blake2bMac<U64>;
|
||||
|
||||
blake2_impl!(
|
||||
Blake2sVarCore,
|
||||
"Blake2s",
|
||||
u32,
|
||||
u32x4,
|
||||
U32,
|
||||
U64,
|
||||
16,
|
||||
12,
|
||||
8,
|
||||
7,
|
||||
BLAKE2S_IV,
|
||||
"Blake2s instance with a variable output.",
|
||||
"Blake2s instance with a fixed output.",
|
||||
);
|
||||
|
||||
/// BLAKE2s which allows to choose output size at runtime.
|
||||
pub type Blake2sVar = RtVariableCoreWrapper<Blake2sVarCore>;
|
||||
/// Core hasher state of BLAKE2s generic over output size.
|
||||
pub type Blake2sCore<OutSize> = CtVariableCoreWrapper<Blake2sVarCore, OutSize>;
|
||||
/// BLAKE2s generic over output size.
|
||||
pub type Blake2s<OutSize> = CoreWrapper<Blake2sCore<OutSize>>;
|
||||
/// BLAKE2s-256 hasher state.
|
||||
pub type Blake2s256 = Blake2s<U32>;
|
||||
|
||||
blake2_mac_impl!(Blake2sMac, Blake2sVarCore, U32, "Blake2s MAC function");
|
||||
|
||||
/// BLAKE2s-256 MAC state.
|
||||
pub type Blake2sMac256 = Blake2sMac<U32>;
|
||||
|
||||
430
blake2/src/macros.rs
Normal file
430
blake2/src/macros.rs
Normal file
@@ -0,0 +1,430 @@
|
||||
macro_rules! blake2_impl {
|
||||
(
|
||||
$name:ident, $alg_name:expr, $word:ident, $vec:ident, $bytes:ident,
|
||||
$block_size:ident, $R1:expr, $R2:expr, $R3:expr, $R4:expr, $IV:expr,
|
||||
$vardoc:expr, $doc:expr,
|
||||
) => {
|
||||
#[derive(Clone)]
|
||||
#[doc=$vardoc]
|
||||
pub struct $name {
|
||||
h: [$vec; 2],
|
||||
t: u64,
|
||||
#[cfg(feature = "reset")]
|
||||
h0: [$vec; 2],
|
||||
}
|
||||
|
||||
impl $name {
|
||||
#[inline(always)]
|
||||
fn iv0() -> $vec {
|
||||
$vec::new($IV[0], $IV[1], $IV[2], $IV[3])
|
||||
}
|
||||
#[inline(always)]
|
||||
fn iv1() -> $vec {
|
||||
$vec::new($IV[4], $IV[5], $IV[6], $IV[7])
|
||||
}
|
||||
|
||||
/// Creates a new context with the full set of sequential-mode parameters.
|
||||
pub fn new_with_params(
|
||||
salt: &[u8],
|
||||
persona: &[u8],
|
||||
key_size: usize,
|
||||
output_size: usize,
|
||||
) -> Self {
|
||||
assert!(key_size <= $bytes::to_usize());
|
||||
assert!(output_size <= $bytes::to_usize());
|
||||
|
||||
// The number of bytes needed to express two words.
|
||||
let length = $bytes::to_usize() / 4;
|
||||
assert!(salt.len() <= length);
|
||||
assert!(persona.len() <= length);
|
||||
|
||||
// Build a parameter block
|
||||
let mut p = [0 as $word; 8];
|
||||
p[0] = 0x0101_0000 ^ ((key_size as $word) << 8) ^ (output_size as $word);
|
||||
|
||||
// salt is two words long
|
||||
if salt.len() < length {
|
||||
let mut padded_salt =
|
||||
GenericArray::<u8, <$bytes as Div<U4>>::Output>::default();
|
||||
for i in 0..salt.len() {
|
||||
padded_salt[i] = salt[i];
|
||||
}
|
||||
p[4] = $word::from_le_bytes(padded_salt[0..length / 2].try_into().unwrap());
|
||||
p[5] = $word::from_le_bytes(
|
||||
padded_salt[length / 2..padded_salt.len()]
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
);
|
||||
} else {
|
||||
p[4] = $word::from_le_bytes(salt[0..salt.len() / 2].try_into().unwrap());
|
||||
p[5] =
|
||||
$word::from_le_bytes(salt[salt.len() / 2..salt.len()].try_into().unwrap());
|
||||
}
|
||||
|
||||
// persona is also two words long
|
||||
if persona.len() < length {
|
||||
let mut padded_persona =
|
||||
GenericArray::<u8, <$bytes as Div<U4>>::Output>::default();
|
||||
for i in 0..persona.len() {
|
||||
padded_persona[i] = persona[i];
|
||||
}
|
||||
p[6] = $word::from_le_bytes(padded_persona[0..length / 2].try_into().unwrap());
|
||||
p[7] = $word::from_le_bytes(
|
||||
padded_persona[length / 2..padded_persona.len()]
|
||||
.try_into()
|
||||
.unwrap(),
|
||||
);
|
||||
} else {
|
||||
p[6] = $word::from_le_bytes(persona[0..length / 2].try_into().unwrap());
|
||||
p[7] = $word::from_le_bytes(
|
||||
persona[length / 2..persona.len()].try_into().unwrap(),
|
||||
);
|
||||
}
|
||||
|
||||
let h = [
|
||||
Self::iv0() ^ $vec::new(p[0], p[1], p[2], p[3]),
|
||||
Self::iv1() ^ $vec::new(p[4], p[5], p[6], p[7]),
|
||||
];
|
||||
$name {
|
||||
#[cfg(feature = "reset")]
|
||||
h0: h.clone(),
|
||||
h,
|
||||
t: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn finalize_with_flag(
|
||||
&mut self,
|
||||
final_block: &GenericArray<u8, $block_size>,
|
||||
flag: $word,
|
||||
out: &mut Output<Self>,
|
||||
) {
|
||||
self.compress(final_block, !0, flag);
|
||||
let buf = [self.h[0].to_le(), self.h[1].to_le()];
|
||||
out.copy_from_slice(buf.as_bytes())
|
||||
}
|
||||
|
||||
fn compress(&mut self, block: &Block<Self>, f0: $word, f1: $word) {
|
||||
use $crate::consts::SIGMA;
|
||||
|
||||
#[inline(always)]
|
||||
fn quarter_round(v: &mut [$vec; 4], rd: u32, rb: u32, m: $vec) {
|
||||
v[0] = v[0].wrapping_add(v[1]).wrapping_add(m.from_le());
|
||||
v[3] = (v[3] ^ v[0]).rotate_right_const(rd);
|
||||
v[2] = v[2].wrapping_add(v[3]);
|
||||
v[1] = (v[1] ^ v[2]).rotate_right_const(rb);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn shuffle(v: &mut [$vec; 4]) {
|
||||
v[1] = v[1].shuffle_left_1();
|
||||
v[2] = v[2].shuffle_left_2();
|
||||
v[3] = v[3].shuffle_left_3();
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn unshuffle(v: &mut [$vec; 4]) {
|
||||
v[1] = v[1].shuffle_right_1();
|
||||
v[2] = v[2].shuffle_right_2();
|
||||
v[3] = v[3].shuffle_right_3();
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn round(v: &mut [$vec; 4], m: &[$word; 16], s: &[usize; 16]) {
|
||||
quarter_round(v, $R1, $R2, $vec::gather(m, s[0], s[2], s[4], s[6]));
|
||||
quarter_round(v, $R3, $R4, $vec::gather(m, s[1], s[3], s[5], s[7]));
|
||||
|
||||
shuffle(v);
|
||||
quarter_round(v, $R1, $R2, $vec::gather(m, s[8], s[10], s[12], s[14]));
|
||||
quarter_round(v, $R3, $R4, $vec::gather(m, s[9], s[11], s[13], s[15]));
|
||||
unshuffle(v);
|
||||
}
|
||||
|
||||
let mut m: [$word; 16] = Default::default();
|
||||
let n = core::mem::size_of::<$word>();
|
||||
for (v, chunk) in m.iter_mut().zip(block.chunks_exact(n)) {
|
||||
*v = $word::from_le_bytes(chunk.try_into().unwrap());
|
||||
}
|
||||
let h = &mut self.h;
|
||||
|
||||
let t0 = self.t as $word;
|
||||
let t1 = match $bytes::to_u8() {
|
||||
64 => 0,
|
||||
32 => (self.t >> 32) as $word,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let mut v = [
|
||||
h[0],
|
||||
h[1],
|
||||
Self::iv0(),
|
||||
Self::iv1() ^ $vec::new(t0, t1, f0, f1),
|
||||
];
|
||||
|
||||
round(&mut v, &m, &SIGMA[0]);
|
||||
round(&mut v, &m, &SIGMA[1]);
|
||||
round(&mut v, &m, &SIGMA[2]);
|
||||
round(&mut v, &m, &SIGMA[3]);
|
||||
round(&mut v, &m, &SIGMA[4]);
|
||||
round(&mut v, &m, &SIGMA[5]);
|
||||
round(&mut v, &m, &SIGMA[6]);
|
||||
round(&mut v, &m, &SIGMA[7]);
|
||||
round(&mut v, &m, &SIGMA[8]);
|
||||
round(&mut v, &m, &SIGMA[9]);
|
||||
if $bytes::to_u8() == 64 {
|
||||
round(&mut v, &m, &SIGMA[0]);
|
||||
round(&mut v, &m, &SIGMA[1]);
|
||||
}
|
||||
|
||||
h[0] = h[0] ^ (v[0] ^ v[2]);
|
||||
h[1] = h[1] ^ (v[1] ^ v[3]);
|
||||
}
|
||||
}
|
||||
|
||||
impl HashMarker for $name {}
|
||||
|
||||
impl BlockSizeUser for $name {
|
||||
type BlockSize = $block_size;
|
||||
}
|
||||
|
||||
impl BufferKindUser for $name {
|
||||
type BufferKind = Lazy;
|
||||
}
|
||||
|
||||
impl UpdateCore for $name {
|
||||
#[inline]
|
||||
fn update_blocks(&mut self, blocks: &[Block<Self>]) {
|
||||
for block in blocks {
|
||||
self.t += block.len() as u64;
|
||||
self.compress(block, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OutputSizeUser for $name {
|
||||
type OutputSize = $bytes;
|
||||
}
|
||||
|
||||
impl VariableOutputCore for $name {
|
||||
const TRUNC_SIDE: TruncSide = TruncSide::Left;
|
||||
|
||||
#[inline]
|
||||
fn new(output_size: usize) -> Result<Self, InvalidOutputSize> {
|
||||
if output_size > Self::OutputSize::USIZE {
|
||||
return Err(InvalidOutputSize);
|
||||
}
|
||||
Ok(Self::new_with_params(&[], &[], 0, output_size))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn finalize_variable_core(
|
||||
&mut self,
|
||||
buffer: &mut Buffer<Self>,
|
||||
out: &mut Output<Self>,
|
||||
) {
|
||||
self.t += buffer.get_pos() as u64;
|
||||
let block = buffer.pad_with_zeros();
|
||||
self.finalize_with_flag(block, 0, out);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "reset")]
|
||||
impl Reset for $name {
|
||||
fn reset(&mut self) {
|
||||
self.h = self.h0;
|
||||
self.t = 0;
|
||||
}
|
||||
}
|
||||
|
||||
impl AlgorithmName for $name {
|
||||
#[inline]
|
||||
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str($alg_name)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for $name {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(concat!(stringify!($name), " { ... }"))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! blake2_mac_impl {
|
||||
(
|
||||
$name:ident, $hash:ty, $max_size:ty, $doc:expr
|
||||
) => {
|
||||
#[derive(Clone)]
|
||||
#[doc=$doc]
|
||||
pub struct $name<OutSize>
|
||||
where
|
||||
OutSize: ArrayLength<u8> + IsLessOrEqual<$max_size>,
|
||||
LeEq<OutSize, $max_size>: NonZero,
|
||||
{
|
||||
core: $hash,
|
||||
buffer: LazyBuffer<<$hash as BlockSizeUser>::BlockSize>,
|
||||
#[cfg(feature = "reset")]
|
||||
key_block: Block<$hash>,
|
||||
_out: PhantomData<OutSize>,
|
||||
}
|
||||
|
||||
impl<OutSize> $name<OutSize>
|
||||
where
|
||||
OutSize: ArrayLength<u8> + IsLessOrEqual<$max_size>,
|
||||
LeEq<OutSize, $max_size>: NonZero,
|
||||
{
|
||||
/// Create new instance using provided key, salt, and persona.
|
||||
///
|
||||
/// Key length should not be bigger than block size, salt and persona
|
||||
/// length should not be bigger than quarter of block size. If any
|
||||
/// of those conditions is false the method will return an error.
|
||||
#[inline]
|
||||
pub fn new_with_salt_and_personal(
|
||||
key: &[u8],
|
||||
salt: &[u8],
|
||||
persona: &[u8],
|
||||
) -> Result<Self, InvalidLength> {
|
||||
let kl = key.len();
|
||||
let bs = <$hash as BlockSizeUser>::BlockSize::USIZE;
|
||||
let qbs = bs / 4;
|
||||
if kl > bs || salt.len() > qbs || persona.len() > qbs {
|
||||
return Err(InvalidLength);
|
||||
}
|
||||
let mut key_block = Block::<$hash>::default();
|
||||
key_block[..kl].copy_from_slice(key);
|
||||
let buffer = LazyBuffer::new(&key_block);
|
||||
Ok(Self {
|
||||
core: <$hash>::new_with_params(salt, persona, key.len(), OutSize::USIZE),
|
||||
buffer,
|
||||
#[cfg(feature = "reset")]
|
||||
key_block,
|
||||
_out: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<OutSize> KeySizeUser for $name<OutSize>
|
||||
where
|
||||
OutSize: ArrayLength<u8> + IsLessOrEqual<$max_size>,
|
||||
LeEq<OutSize, $max_size>: NonZero,
|
||||
{
|
||||
type KeySize = <$hash as BlockSizeUser>::BlockSize;
|
||||
}
|
||||
|
||||
impl<OutSize> KeyInit for $name<OutSize>
|
||||
where
|
||||
OutSize: ArrayLength<u8> + IsLessOrEqual<$max_size>,
|
||||
LeEq<OutSize, $max_size>: NonZero,
|
||||
{
|
||||
fn new(key: &Key<Self>) -> Self {
|
||||
Self {
|
||||
core: <$hash>::new_with_params(key, &[], key.len(), OutSize::USIZE),
|
||||
buffer: LazyBuffer::new(key),
|
||||
#[cfg(feature = "reset")]
|
||||
key_block: key.clone(),
|
||||
_out: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn new_from_slice(key: &[u8]) -> Result<Self, InvalidLength> {
|
||||
let kl = key.len();
|
||||
if kl > <$hash as BlockSizeUser>::BlockSize::USIZE {
|
||||
return Err(InvalidLength);
|
||||
}
|
||||
let mut key_block = Block::<$hash>::default();
|
||||
key_block[..kl].copy_from_slice(key);
|
||||
Ok(Self {
|
||||
core: <$hash>::new_with_params(&[], &[], key.len(), OutSize::USIZE),
|
||||
buffer: LazyBuffer::new(&key_block),
|
||||
#[cfg(feature = "reset")]
|
||||
key_block,
|
||||
_out: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<OutSize> Update for $name<OutSize>
|
||||
where
|
||||
OutSize: ArrayLength<u8> + IsLessOrEqual<$max_size>,
|
||||
LeEq<OutSize, $max_size>: NonZero,
|
||||
{
|
||||
#[inline]
|
||||
fn update(&mut self, input: &[u8]) {
|
||||
let Self { core, buffer, .. } = self;
|
||||
buffer.digest_blocks(input, |blocks| core.update_blocks(blocks));
|
||||
}
|
||||
}
|
||||
|
||||
impl<OutSize> OutputSizeUser for $name<OutSize>
|
||||
where
|
||||
OutSize: ArrayLength<u8> + IsLessOrEqual<$max_size>,
|
||||
LeEq<OutSize, $max_size>: NonZero,
|
||||
{
|
||||
type OutputSize = OutSize;
|
||||
}
|
||||
|
||||
impl<OutSize> FixedOutput for $name<OutSize>
|
||||
where
|
||||
OutSize: ArrayLength<u8> + IsLessOrEqual<$max_size>,
|
||||
LeEq<OutSize, $max_size>: NonZero,
|
||||
{
|
||||
#[inline]
|
||||
fn finalize_into(mut self, out: &mut Output<Self>) {
|
||||
let Self { core, buffer, .. } = &mut self;
|
||||
let mut full_res = Default::default();
|
||||
core.finalize_variable_core(buffer, &mut full_res);
|
||||
out.copy_from_slice(&full_res[..OutSize::USIZE]);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "reset")]
|
||||
impl<OutSize> Reset for $name<OutSize>
|
||||
where
|
||||
OutSize: ArrayLength<u8> + IsLessOrEqual<$max_size>,
|
||||
LeEq<OutSize, $max_size>: NonZero,
|
||||
{
|
||||
fn reset(&mut self) {
|
||||
self.core.reset();
|
||||
self.buffer = LazyBuffer::new(&self.key_block);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "reset")]
|
||||
impl<OutSize> FixedOutputReset for $name<OutSize>
|
||||
where
|
||||
OutSize: ArrayLength<u8> + IsLessOrEqual<$max_size>,
|
||||
LeEq<OutSize, $max_size>: NonZero,
|
||||
{
|
||||
#[inline]
|
||||
fn finalize_into_reset(&mut self, out: &mut Output<Self>) {
|
||||
let Self {
|
||||
core,
|
||||
buffer,
|
||||
key_block,
|
||||
..
|
||||
} = self;
|
||||
core.finalize_variable_core(buffer, out);
|
||||
core.reset();
|
||||
*buffer = LazyBuffer::new(key_block);
|
||||
}
|
||||
}
|
||||
|
||||
impl<OutSize> MacMarker for $name<OutSize>
|
||||
where
|
||||
OutSize: ArrayLength<u8> + IsLessOrEqual<$max_size>,
|
||||
LeEq<OutSize, $max_size>: NonZero,
|
||||
{
|
||||
}
|
||||
|
||||
impl<OutSize> fmt::Debug for $name<OutSize>
|
||||
where
|
||||
OutSize: ArrayLength<u8> + IsLessOrEqual<$max_size>,
|
||||
LeEq<OutSize, $max_size>: NonZero,
|
||||
{
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}{} {{ ... }}", stringify!($name), OutSize::USIZE)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,18 +0,0 @@
|
||||
#![no_std]
|
||||
|
||||
use digest::dev::{digest_test, variable_test};
|
||||
use digest::new_test;
|
||||
|
||||
new_test!(blake2b_fixed, "blake2b/fixed", blake2::Blake2b, digest_test);
|
||||
new_test!(
|
||||
blake2b_variable,
|
||||
"blake2b/variable",
|
||||
blake2::VarBlake2b,
|
||||
variable_test
|
||||
);
|
||||
new_test!(
|
||||
blake2s_variable,
|
||||
"blake2s/variable",
|
||||
blake2::VarBlake2s,
|
||||
variable_test
|
||||
);
|
||||
@@ -1,6 +1,7 @@
|
||||
#![no_std]
|
||||
#[cfg(not(feature = "reset"))]
|
||||
use digest::new_mac_test as new_test;
|
||||
#[cfg(feature = "reset")]
|
||||
use digest::new_resettable_mac_test as new_test;
|
||||
|
||||
use crypto_mac::new_test;
|
||||
|
||||
new_test!(blake2b_mac, "blake2b/mac", blake2::Blake2b);
|
||||
new_test!(blake2s_mac, "blake2s/mac", blake2::Blake2s);
|
||||
new_test!(blake2b_mac, "blake2b/mac", blake2::Blake2bMac512);
|
||||
new_test!(blake2s_mac, "blake2s/mac", blake2::Blake2sMac256);
|
||||
|
||||
19
blake2/tests/mod.rs
Normal file
19
blake2/tests/mod.rs
Normal file
@@ -0,0 +1,19 @@
|
||||
#[cfg(feature = "reset")]
|
||||
use digest::dev::{fixed_reset_test as fixed_fn, variable_reset_test as varaible_fn};
|
||||
#[cfg(not(feature = "reset"))]
|
||||
use digest::dev::{fixed_test as fixed_fn, variable_test as varaible_fn};
|
||||
use digest::new_test;
|
||||
|
||||
new_test!(blake2b_fixed, "blake2b/fixed", blake2::Blake2b512, fixed_fn,);
|
||||
new_test!(
|
||||
blake2b_variable,
|
||||
"blake2b/variable",
|
||||
blake2::Blake2bVar,
|
||||
varaible_fn,
|
||||
);
|
||||
new_test!(
|
||||
blake2s_variable,
|
||||
"blake2s/variable",
|
||||
blake2::Blake2sVar,
|
||||
varaible_fn,
|
||||
);
|
||||
@@ -1,23 +1,40 @@
|
||||
use blake2::{Blake2b, Blake2s, Digest};
|
||||
use blake2::{digest::FixedOutput, Blake2bMac512, Blake2sMac256};
|
||||
use hex_literal::hex;
|
||||
|
||||
#[test]
|
||||
#[rustfmt::skip]
|
||||
fn blake2s_persona() {
|
||||
let key_bytes = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
|
||||
let persona = "personal";
|
||||
let persona_bytes = persona.as_bytes();
|
||||
let ctx = Blake2s::with_params(&key_bytes, &[], persona_bytes);
|
||||
let key= hex!("
|
||||
000102030405060708090a0b0c0d0e0f
|
||||
101112131415161718191a1b1c1d1e1f
|
||||
");
|
||||
let persona = b"personal";
|
||||
let ctx = Blake2sMac256::new_with_salt_and_personal(&key, &[], persona).unwrap();
|
||||
assert_eq!(
|
||||
ctx.finalize().as_slice(),
|
||||
&hex!("25a4ee63b594aed3f88a971e1877ef7099534f9097291f88fb86c79b5e70d022")[..]
|
||||
ctx.finalize_fixed()[..],
|
||||
hex!("
|
||||
25a4ee63b594aed3f88a971e1877ef70
|
||||
99534f9097291f88fb86c79b5e70d022
|
||||
")[..],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[rustfmt::skip]
|
||||
fn blake2b_persona() {
|
||||
let key_bytes = hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f");
|
||||
let persona = "personal";
|
||||
let persona_bytes = persona.as_bytes();
|
||||
let ctx = Blake2b::with_params(&key_bytes, &[], persona_bytes);
|
||||
assert_eq!(ctx.finalize().as_slice(), &hex!("03de3b295dcfc3b25b05abb09bc95fe3e9ff3073638badc68101d1e42019d0771dd07525a3aae8318e92c5e5d967ba92e4810d0021d7bf3b49da0b4b4a8a4e1f")[..]);
|
||||
let key = hex!("
|
||||
000102030405060708090a0b0c0d0e0f
|
||||
101112131415161718191a1b1c1d1e1f
|
||||
");
|
||||
let persona = b"personal";
|
||||
let ctx = Blake2bMac512::new_with_salt_and_personal(&key, &[], persona).unwrap();
|
||||
assert_eq!(
|
||||
ctx.finalize_fixed()[..],
|
||||
hex!("
|
||||
03de3b295dcfc3b25b05abb09bc95fe3
|
||||
e9ff3073638badc68101d1e42019d077
|
||||
1dd07525a3aae8318e92c5e5d967ba92
|
||||
e4810d0021d7bf3b49da0b4b4a8a4e1f
|
||||
")[..],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.1.0 (2021-12-07)
|
||||
### Changed
|
||||
- Update to `digest` v0.10 ([#217])
|
||||
|
||||
[#217]: https://github.com/RustCrypto/hashes/pull/217
|
||||
|
||||
## 0.0.2 (2020-07-21)
|
||||
- Fixed `Reset` implementation bug. Reduce crate size by using binary dump
|
||||
of `PI` ([#300])
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "fsb"
|
||||
description = "FSB hash function"
|
||||
version = "0.0.2"
|
||||
version = "0.1.0" # Also update html_root_url in lib.rs when bumping this
|
||||
authors = ["RustCrypto Developers"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
readme = "README.md"
|
||||
@@ -11,15 +11,13 @@ keywords = ["crypto", "fsb", "hash", "digest"]
|
||||
categories = ["cryptography", "no-std"]
|
||||
|
||||
[dependencies]
|
||||
whirlpool = { version = "0.9", path = "../whirlpool", default-features = false }
|
||||
digest = "0.9"
|
||||
block-buffer = { version = "0.9", features = ["block-padding"] }
|
||||
opaque-debug = "0.3"
|
||||
digest = "0.10"
|
||||
whirlpool = { version = "0.10", path = "../whirlpool", default-features = false }
|
||||
|
||||
[dev-dependencies]
|
||||
digest = { version = "0.10", features = ["dev"] }
|
||||
hex-literal = "0.2"
|
||||
digest = { version = "0.9", features = ["dev"] }
|
||||
|
||||
[features]
|
||||
asm = ["whirlpool/asm"]
|
||||
std = ["whirlpool/std"]
|
||||
default = ["std"]
|
||||
std = ["digest/std"]
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
Copyright (c) 2006-2009 Graydon Hoare
|
||||
Copyright (c) 2009-2013 Mozilla Foundation
|
||||
Copyright (c) 2016 Artyom Pavlov
|
||||
Copyright (c) 2021 The RustCrypto Project Developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
@@ -13,7 +13,7 @@ Pure Rust implementation of the [FSB hash function][1] family.
|
||||
|
||||
## Minimum Supported Rust Version
|
||||
|
||||
Rust **1.47** or higher.
|
||||
Rust **1.41** or higher.
|
||||
|
||||
Minimum supported Rust version can be changed in the future, but it will be
|
||||
done with a minor version bump.
|
||||
|
||||
46
fsb/benches/mod.rs
Normal file
46
fsb/benches/mod.rs
Normal file
@@ -0,0 +1,46 @@
|
||||
#![feature(test)]
|
||||
extern crate test;
|
||||
|
||||
use digest::bench_update;
|
||||
use fsb::{Fsb160, Fsb224, Fsb256, Fsb384, Fsb512};
|
||||
use test::Bencher;
|
||||
|
||||
bench_update!(
|
||||
Fsb160::default();
|
||||
fsb160_10 10;
|
||||
fsb160_100 100;
|
||||
fsb160_1000 1000;
|
||||
fsb160_10000 10000;
|
||||
);
|
||||
|
||||
bench_update!(
|
||||
Fsb224::default();
|
||||
fsb224_10 10;
|
||||
fsb224_100 100;
|
||||
fsb224_1000 1000;
|
||||
fsb224_10000 10000;
|
||||
);
|
||||
|
||||
bench_update!(
|
||||
Fsb256::default();
|
||||
fsb256_10 10;
|
||||
fsb256_100 100;
|
||||
fsb256_1000 1000;
|
||||
fsb256_10000 10000;
|
||||
);
|
||||
|
||||
bench_update!(
|
||||
Fsb384::default();
|
||||
fsb384_10 10;
|
||||
fsb384_100 100;
|
||||
fsb384_1000 1000;
|
||||
fsb384_10000 10000;
|
||||
);
|
||||
|
||||
bench_update!(
|
||||
Fsb512::default();
|
||||
fsb512_10 10;
|
||||
fsb512_100 100;
|
||||
fsb512_1000 1000;
|
||||
fsb512_10000 10000;
|
||||
);
|
||||
@@ -39,38 +39,36 @@
|
||||
|
||||
#![no_std]
|
||||
#![doc(
|
||||
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
|
||||
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
|
||||
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
|
||||
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
|
||||
html_root_url = "https://docs.rs/fsb/0.1.0"
|
||||
)]
|
||||
#![deny(unsafe_code)]
|
||||
#![warn(missing_docs, rust_2018_idioms)]
|
||||
#![allow(non_snake_case)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
extern crate std;
|
||||
|
||||
use alloc::vec;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
|
||||
use core::fmt;
|
||||
pub use digest::{self, Digest};
|
||||
use whirlpool::Whirlpool;
|
||||
|
||||
use core::convert::TryInto;
|
||||
|
||||
// Double check this contains all values in the reference implementation
|
||||
static PI: &[u8; 272384] = include_bytes!("pi.bin");
|
||||
|
||||
use block_buffer::BlockBuffer;
|
||||
use digest::generic_array::GenericArray;
|
||||
use digest::{BlockInput, FixedOutputDirty, Reset, Update};
|
||||
use digest::{
|
||||
block_buffer::Eager,
|
||||
core_api::{
|
||||
AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, CoreWrapper, FixedOutputCore,
|
||||
OutputSizeUser, Reset, UpdateCore,
|
||||
},
|
||||
generic_array::{typenum::Unsigned, GenericArray},
|
||||
HashMarker, Output,
|
||||
};
|
||||
|
||||
// FSB-160
|
||||
fsb_impl!(
|
||||
Fsb160,
|
||||
Fsb160Core,
|
||||
160,
|
||||
U60,
|
||||
U20,
|
||||
@@ -79,12 +77,14 @@ fsb_impl!(
|
||||
640,
|
||||
653,
|
||||
1120,
|
||||
"FSB-160 hash function."
|
||||
"FSB-160 hasher state",
|
||||
"Core FSB-160 hasher state",
|
||||
);
|
||||
|
||||
// FSB-224
|
||||
fsb_impl!(
|
||||
Fsb224,
|
||||
Fsb224Core,
|
||||
224,
|
||||
U84,
|
||||
U28,
|
||||
@@ -93,12 +93,14 @@ fsb_impl!(
|
||||
896,
|
||||
907,
|
||||
1568,
|
||||
"FSB-224 hash function."
|
||||
"FSB-224 hasher state",
|
||||
"Core FSB-224 hasher state",
|
||||
);
|
||||
|
||||
// FSB-256
|
||||
fsb_impl!(
|
||||
Fsb256,
|
||||
Fsb256Core,
|
||||
256,
|
||||
U96,
|
||||
U32,
|
||||
@@ -107,12 +109,14 @@ fsb_impl!(
|
||||
1024,
|
||||
1061,
|
||||
1792,
|
||||
"FSB-256 hash function."
|
||||
"FSB-256 hasher state",
|
||||
"Core FSB-256 hasher state",
|
||||
);
|
||||
|
||||
// FSB-384
|
||||
fsb_impl!(
|
||||
Fsb384,
|
||||
Fsb384Core,
|
||||
384,
|
||||
U115,
|
||||
U48,
|
||||
@@ -121,12 +125,14 @@ fsb_impl!(
|
||||
1472,
|
||||
1483,
|
||||
2392,
|
||||
"FSB-384 hash function."
|
||||
"FSB-384 hasher state",
|
||||
"Core FSB-384 hasher state",
|
||||
);
|
||||
|
||||
// FSB-512
|
||||
fsb_impl!(
|
||||
Fsb512,
|
||||
Fsb512Core,
|
||||
512,
|
||||
U155,
|
||||
U64,
|
||||
@@ -135,5 +141,6 @@ fsb_impl!(
|
||||
1984,
|
||||
1987,
|
||||
3224,
|
||||
"FSB-512 hash function."
|
||||
"FSB-512 hasher state",
|
||||
"Core FSB-512 hasher state",
|
||||
);
|
||||
|
||||
@@ -1,57 +1,94 @@
|
||||
macro_rules! fsb_impl {
|
||||
(
|
||||
$state:ident, $state_num:expr, $blocksize:ident, $outputsize:ident, $n:expr, $w:expr,
|
||||
$r:expr, $p:expr, $s:expr, $doc:expr
|
||||
$full_state:ident, $state:ident, $state_num:expr, $blocksize:ident, $outputsize:ident, $n:expr, $w:expr,
|
||||
$r:expr, $p:expr, $s:expr, $full_doc:expr, $doc:expr,
|
||||
) => {
|
||||
use digest::consts::{$blocksize, $outputsize};
|
||||
|
||||
#[derive(Clone)]
|
||||
#[doc=$doc]
|
||||
pub struct $state {
|
||||
/// bit size of the message till the current moment (the bit size is represented by a 64 bit
|
||||
/// number)
|
||||
bit_length: u64,
|
||||
/// size of the message being processed
|
||||
buffer: BlockBuffer<$blocksize>,
|
||||
/// value of the input vector
|
||||
hash: [u8; $r / 8],
|
||||
blocks_len: u64,
|
||||
state: [u8; $r / 8],
|
||||
}
|
||||
|
||||
impl HashMarker for $state {}
|
||||
|
||||
impl BlockSizeUser for $state {
|
||||
type BlockSize = $blocksize;
|
||||
}
|
||||
|
||||
impl OutputSizeUser for $state {
|
||||
type OutputSize = $outputsize;
|
||||
}
|
||||
|
||||
impl BufferKindUser for $state {
|
||||
type BufferKind = Eager;
|
||||
}
|
||||
|
||||
impl UpdateCore for $state {
|
||||
#[inline]
|
||||
fn update_blocks(&mut self, blocks: &[Block<Self>]) {
|
||||
self.blocks_len += blocks.len() as u64;
|
||||
for block in blocks {
|
||||
Self::compress(&mut self.state, Self::convert(block));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FixedOutputCore for $state {
|
||||
#[inline]
|
||||
fn finalize_fixed_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
|
||||
let block_bytes = self.blocks_len * Self::BlockSize::U64;
|
||||
let bit_len = 8 * (block_bytes + buffer.get_pos() as u64);
|
||||
let mut h = self.state;
|
||||
buffer.len64_padding_be(bit_len, |b| Self::compress(&mut h, Self::convert(b)));
|
||||
|
||||
let res = whirlpool::Whirlpool::digest(&h[..]);
|
||||
let n = out.len();
|
||||
out.copy_from_slice(&res[..n]);
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for $state {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
blocks_len: 0u64,
|
||||
state: [0u8; $r / 8],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Reset for $state {
|
||||
#[inline]
|
||||
fn reset(&mut self) {
|
||||
*self = Default::default();
|
||||
}
|
||||
}
|
||||
|
||||
impl AlgorithmName for $state {
|
||||
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(stringify!($full_state))
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for $state {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(concat!(stringify!($state), " { ... }"))
|
||||
}
|
||||
}
|
||||
|
||||
#[doc=$full_doc]
|
||||
pub type $full_state = CoreWrapper<$state>;
|
||||
|
||||
impl $state {
|
||||
// constants
|
||||
const SIZE_OUTPUT_COMPRESS: usize = $r / 8;
|
||||
const SIZE_INPUT_COMPRESS: usize = $s / 8;
|
||||
const HASH_OUTPUT_SIZE: usize = $state_num / 8;
|
||||
const SIZE_MSG_CHUNKS: usize = Self::SIZE_INPUT_COMPRESS - Self::SIZE_OUTPUT_COMPRESS;
|
||||
const SIZE_VECTORS: usize = $p / 8 + 1;
|
||||
const SHIFT: u8 = 8 - ($p % 8) as u8;
|
||||
|
||||
fn update_len(&mut self, len: u64) {
|
||||
self.bit_length += len * 8;
|
||||
}
|
||||
|
||||
fn finalize_inner(&mut self) {
|
||||
let hash = &mut self.hash;
|
||||
let pos = self.buffer.position();
|
||||
if pos < Self::SIZE_MSG_CHUNKS - 8 {
|
||||
let mut padding = vec![0; Self::SIZE_MSG_CHUNKS - pos - 8];
|
||||
padding[0] = 128u8;
|
||||
padding.extend_from_slice(&Self::helper_transform_usize(self.bit_length));
|
||||
self.buffer
|
||||
.input_block(&padding, |b| Self::compress(hash, Self::convert(b)));
|
||||
} else {
|
||||
let mut padding = vec![0; Self::SIZE_MSG_CHUNKS - pos];
|
||||
padding[0] = 128u8;
|
||||
self.buffer
|
||||
.input_block(&padding, |b| Self::compress(hash, Self::convert(b)));
|
||||
let mut second_padding = vec![0; Self::SIZE_MSG_CHUNKS - 8];
|
||||
second_padding
|
||||
.extend_from_slice(&Self::helper_transform_usize(self.bit_length));
|
||||
self.buffer
|
||||
.input_block(&second_padding, |b| Self::compress(hash, Self::convert(b)));
|
||||
}
|
||||
}
|
||||
|
||||
fn define_iv(index: usize) -> [u8; Self::SIZE_VECTORS] {
|
||||
let mut subset_pi: [u8; Self::SIZE_VECTORS] = [0u8; Self::SIZE_VECTORS];
|
||||
subset_pi.copy_from_slice(
|
||||
@@ -72,21 +109,21 @@ macro_rules! fsb_impl {
|
||||
/// $(W_i)_{i\in[0;w-1]}$ between $0$ and $n - 1$. The value of each $W_i$ is computed
|
||||
/// from the inputs bits like this:
|
||||
/// $W_i = i \times (n / w) + IV_i + M_i \times 2^{r / w}.
|
||||
fn computing_W_indices(
|
||||
fn computing_w_indices(
|
||||
input_vector: &[u8; Self::SIZE_OUTPUT_COMPRESS],
|
||||
message: &[u8; Self::SIZE_MSG_CHUNKS],
|
||||
) -> [u32; $w] {
|
||||
let mut W_indices: [u32; $w] = [0; $w];
|
||||
let mut wind: [u32; $w] = [0; $w];
|
||||
let divided_message: [u8; $w] = Self::dividing_bits(message, ($s - $r) / $w);
|
||||
for i in 0..($w) {
|
||||
let message_i = divided_message[i] as u32;
|
||||
|
||||
W_indices[i] = (i * $n / $w) as u32
|
||||
wind[i] = (i * $n / $w) as u32
|
||||
+ input_vector[i] as u32
|
||||
+ (message_i << ($r / $w) as u8);
|
||||
}
|
||||
|
||||
W_indices
|
||||
wind
|
||||
}
|
||||
|
||||
/// This function servers the purpose presented in table 3, of breaking a bit array into
|
||||
@@ -133,7 +170,7 @@ macro_rules! fsb_impl {
|
||||
) {
|
||||
let mut initial_vector = [0u8; Self::SIZE_OUTPUT_COMPRESS];
|
||||
|
||||
let w_indices = Self::computing_W_indices(hash, message_block);
|
||||
let w_indices = Self::computing_w_indices(hash, message_block);
|
||||
for w_index in w_indices.iter() {
|
||||
let chosen_vec = w_index / $r as u32;
|
||||
let shift_value = w_index % $r as u32;
|
||||
@@ -149,18 +186,6 @@ macro_rules! fsb_impl {
|
||||
*hash = initial_vector;
|
||||
}
|
||||
|
||||
fn final_compression(
|
||||
initial_vector: [u8; Self::SIZE_OUTPUT_COMPRESS],
|
||||
) -> [u8; Self::HASH_OUTPUT_SIZE] {
|
||||
// Now we use Whirpool
|
||||
let mut result = [0u8; Self::HASH_OUTPUT_SIZE];
|
||||
let mut hasher = Whirlpool::new();
|
||||
|
||||
Update::update(&mut hasher, &initial_vector);
|
||||
result.copy_from_slice(&hasher.finalize()[..Self::HASH_OUTPUT_SIZE]);
|
||||
result
|
||||
}
|
||||
|
||||
fn shift_and_truncate(
|
||||
array: &mut [u8; Self::SIZE_VECTORS],
|
||||
shift_value: u32,
|
||||
@@ -170,9 +195,7 @@ macro_rules! fsb_impl {
|
||||
let mut truncated = [0u8; Self::SIZE_OUTPUT_COMPRESS];
|
||||
|
||||
if shift_value == 0 {
|
||||
array[..Self::SIZE_OUTPUT_COMPRESS]
|
||||
.try_into()
|
||||
.expect("SIZE_VECTORS is always bigger than SIZE_OUTPUT_COMPRESS")
|
||||
truncated.copy_from_slice(&array[..Self::SIZE_OUTPUT_COMPRESS]);
|
||||
} else if shift_value <= (bits_in_cue as u32) {
|
||||
let bytes_to_shift = 1;
|
||||
let starting_byte = (array_len - bytes_to_shift) as usize;
|
||||
@@ -183,8 +206,6 @@ macro_rules! fsb_impl {
|
||||
truncated[position] ^= array[position - 1] >> (8 - shift_value);
|
||||
truncated[position] ^= array[position] << shift_value;
|
||||
}
|
||||
|
||||
truncated
|
||||
} else {
|
||||
// First we need to decide which is the last byte and bit that will go to the first position.
|
||||
// Then, we build our truncated array from there. Recall that the last byte is not complete,
|
||||
@@ -246,8 +267,6 @@ macro_rules! fsb_impl {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
truncated
|
||||
} else {
|
||||
truncated[..bytes_to_shift].clone_from_slice(
|
||||
&array[starting_byte..(starting_byte + bytes_to_shift)],
|
||||
@@ -261,76 +280,14 @@ macro_rules! fsb_impl {
|
||||
truncated[position] ^= array[index] << (8 - bits_in_cue);
|
||||
truncated[position] ^= array[index + 1] >> bits_in_cue;
|
||||
}
|
||||
truncated
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// I'm trying to avoid use unsafe code for this transformation. We are certain that the bit
|
||||
// size of the buffer can be represented in 8 bytes.
|
||||
fn helper_transform_usize(x: u64) -> [u8; 8] {
|
||||
let b1: u8 = ((x >> 56) & 0xff) as u8;
|
||||
let b2: u8 = ((x >> 48) & 0xff) as u8;
|
||||
let b3: u8 = ((x >> 40) & 0xff) as u8;
|
||||
let b4: u8 = ((x >> 32) & 0xff) as u8;
|
||||
let b5: u8 = ((x >> 24) & 0xff) as u8;
|
||||
let b6: u8 = ((x >> 16) & 0xff) as u8;
|
||||
let b7: u8 = ((x >> 8) & 0xff) as u8;
|
||||
let b8: u8 = (x & 0xff) as u8;
|
||||
[b1, b2, b3, b4, b5, b6, b7, b8]
|
||||
truncated
|
||||
}
|
||||
|
||||
fn convert(block: &GenericArray<u8, $blocksize>) -> &[u8; Self::SIZE_MSG_CHUNKS] {
|
||||
#[allow(unsafe_code)]
|
||||
unsafe {
|
||||
&*(block.as_ptr() as *const [u8; Self::SIZE_MSG_CHUNKS])
|
||||
}
|
||||
unsafe { &*(block.as_ptr() as *const [u8; Self::SIZE_MSG_CHUNKS]) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for $state {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
bit_length: 0u64,
|
||||
buffer: BlockBuffer::default(),
|
||||
hash: [0u8; $r / 8],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockInput for $state {
|
||||
type BlockSize = $blocksize;
|
||||
}
|
||||
|
||||
impl Update for $state {
|
||||
fn update(&mut self, input: impl AsRef<[u8]>) {
|
||||
let input = input.as_ref();
|
||||
self.update_len(input.len() as u64);
|
||||
|
||||
let hash = &mut self.hash;
|
||||
self.buffer
|
||||
.input_block(input, |b| $state::compress(hash, $state::convert(b)));
|
||||
}
|
||||
}
|
||||
|
||||
impl FixedOutputDirty for $state {
|
||||
type OutputSize = $outputsize;
|
||||
|
||||
fn finalize_into_dirty(&mut self, out: &mut GenericArray<u8, Self::OutputSize>) {
|
||||
self.finalize_inner();
|
||||
let final_whirpool = $state::final_compression(self.hash);
|
||||
out.copy_from_slice(&final_whirpool)
|
||||
}
|
||||
}
|
||||
|
||||
impl Reset for $state {
|
||||
fn reset(&mut self) {
|
||||
self.buffer.reset();
|
||||
self.hash = [0u8; $r / 8];
|
||||
self.bit_length = 0;
|
||||
}
|
||||
}
|
||||
opaque_debug::implement!($state);
|
||||
digest::impl_write!($state);
|
||||
};
|
||||
}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,8 +0,0 @@
|
||||
use digest::dev::digest_test;
|
||||
use digest::new_test;
|
||||
|
||||
new_test!(fsb160_main, "fsb160", fsb::Fsb160, digest_test);
|
||||
new_test!(fsb224_main, "fsb224", fsb::Fsb224, digest_test);
|
||||
new_test!(fsb256_main, "fsb256", fsb::Fsb256, digest_test);
|
||||
new_test!(fsb384_main, "fsb384", fsb::Fsb384, digest_test);
|
||||
new_test!(fsb512_main, "fsb512", fsb::Fsb512, digest_test);
|
||||
68
fsb/tests/mod.rs
Normal file
68
fsb/tests/mod.rs
Normal file
@@ -0,0 +1,68 @@
|
||||
use digest::dev::{feed_rand_16mib, fixed_reset_test};
|
||||
use digest::new_test;
|
||||
use fsb::{Digest, Fsb160, Fsb224, Fsb256, Fsb384, Fsb512};
|
||||
use hex_literal::hex;
|
||||
|
||||
new_test!(fsb160_main, "fsb160", Fsb160, fixed_reset_test);
|
||||
new_test!(fsb224_main, "fsb224", Fsb224, fixed_reset_test);
|
||||
new_test!(fsb256_main, "fsb256", Fsb256, fixed_reset_test);
|
||||
new_test!(fsb384_main, "fsb384", Fsb384, fixed_reset_test);
|
||||
new_test!(fsb512_main, "fsb512", Fsb512, fixed_reset_test);
|
||||
|
||||
#[test]
|
||||
fn fsb160_rand() {
|
||||
let mut h = Fsb160::new();
|
||||
feed_rand_16mib(&mut h);
|
||||
assert_eq!(
|
||||
h.finalize()[..],
|
||||
hex!("454b28a8d158ad63ff59e3f761919c7581ee78d3")[..]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fsb224_rand() {
|
||||
let mut h = Fsb224::new();
|
||||
feed_rand_16mib(&mut h);
|
||||
assert_eq!(
|
||||
h.finalize()[..],
|
||||
hex!("80ef345c462dc88261355eaf44ee2bb7277d01db77b46b2828a918b6")[..]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fsb256_rand() {
|
||||
let mut h = Fsb256::new();
|
||||
feed_rand_16mib(&mut h);
|
||||
assert_eq!(
|
||||
h.finalize()[..],
|
||||
hex!("301cbfd7031de3568bf4c4ffa86c2295bde89937acc8ee470446b8c55b88334a")[..]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[rustfmt::skip]
|
||||
fn fsb384_rand() {
|
||||
let mut h = Fsb384::new();
|
||||
feed_rand_16mib(&mut h);
|
||||
assert_eq!(
|
||||
h.finalize()[..],
|
||||
hex!("
|
||||
d11c0ea4ef363916ad8c2a4d8b4758bf0c36e4de93f2bbaeba037b0726c83179
|
||||
0ec4e5d9d3e9d66e0810d391a00bf60e
|
||||
")[..]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[rustfmt::skip]
|
||||
fn fsb512_rand() {
|
||||
let mut h = Fsb512::new();
|
||||
feed_rand_16mib(&mut h);
|
||||
assert_eq!(
|
||||
h.finalize()[..],
|
||||
hex!("
|
||||
eb15b6c3626e38141e4f17b3b89d7deed007c4ae727452010601bc4e16deef82
|
||||
f81415566defb1aba3db9b1b14746bd81cf3689a0f79e6d00434ff4ca19b3e66
|
||||
")[..]
|
||||
);
|
||||
}
|
||||
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.10.0 (2021-12-07)
|
||||
### Changed
|
||||
- Update to `digest` v0.10 ([#217])
|
||||
|
||||
[#217]: https://github.com/RustCrypto/hashes/pull/217
|
||||
|
||||
## 0.9.1 (2020-11-03)
|
||||
### Fixed
|
||||
- Arithmetic overflow bug. ([#193])
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "gost94"
|
||||
version = "0.9.1"
|
||||
version = "0.10.0" # Also update html_root_url in lib.rs when bumping this
|
||||
description = "GOST R 34.11-94 hash function"
|
||||
authors = ["RustCrypto Developers"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
@@ -12,12 +12,10 @@ keywords = ["crypto", "gost94", "gost", "hash", "digest"]
|
||||
categories = ["cryptography", "no-std"]
|
||||
|
||||
[dependencies]
|
||||
digest = "0.9"
|
||||
block-buffer = { version = "0.9", features = ["block-padding"] }
|
||||
opaque-debug = "0.3"
|
||||
digest = "0.10"
|
||||
|
||||
[dev-dependencies]
|
||||
digest = { version = "0.9", features = ["dev"] }
|
||||
digest = { version = "0.10", features = ["dev"] }
|
||||
hex-literal = "0.2"
|
||||
|
||||
[features]
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
#![no_std]
|
||||
#![feature(test)]
|
||||
|
||||
digest::bench!(gost94::Gost94Test);
|
||||
14
gost94/benches/mod.rs
Normal file
14
gost94/benches/mod.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
#![feature(test)]
|
||||
extern crate test;
|
||||
|
||||
use digest::bench_update;
|
||||
use gost94::Gost94Test;
|
||||
use test::Bencher;
|
||||
|
||||
bench_update!(
|
||||
Gost94Test::default();
|
||||
md2_10 10;
|
||||
md2_100 100;
|
||||
md2_1000 1000;
|
||||
md2_10000 10000;
|
||||
);
|
||||
@@ -1,47 +0,0 @@
|
||||
use gost94::{Digest, Gost94CryptoPro};
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::io::{self, Read};
|
||||
|
||||
const BUFFER_SIZE: usize = 1024;
|
||||
|
||||
/// Print digest result as hex string and name pair
|
||||
fn print_result(sum: &[u8], name: &str) {
|
||||
for byte in sum {
|
||||
print!("{:02x}", byte);
|
||||
}
|
||||
println!("\t{}", name);
|
||||
}
|
||||
|
||||
/// Compute digest value for given `Reader` and print it
|
||||
/// On any error simply return without doing anything
|
||||
fn process<D: Digest + Default, R: Read>(reader: &mut R, name: &str) {
|
||||
let mut sh = D::default();
|
||||
let mut buffer = [0u8; BUFFER_SIZE];
|
||||
loop {
|
||||
let n = match reader.read(&mut buffer) {
|
||||
Ok(n) => n,
|
||||
Err(_) => return,
|
||||
};
|
||||
sh.update(&buffer[..n]);
|
||||
if n == 0 || n < BUFFER_SIZE {
|
||||
break;
|
||||
}
|
||||
}
|
||||
print_result(&sh.finalize(), name);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = env::args();
|
||||
// Process files listed in command line arguments one by one
|
||||
// If no files provided process input from stdin
|
||||
if args.len() > 1 {
|
||||
for path in args.skip(1) {
|
||||
if let Ok(mut file) = fs::File::open(&path) {
|
||||
process::<Gost94CryptoPro, _>(&mut file, &path);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
process::<Gost94CryptoPro, _>(&mut io::stdin(), "-");
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
use gost94::{Digest, Gost94Test};
|
||||
use std::env;
|
||||
use std::fs;
|
||||
use std::io::{self, Read};
|
||||
|
||||
const BUFFER_SIZE: usize = 1024;
|
||||
|
||||
/// Print digest result as hex string and name pair
|
||||
fn print_result(sum: &[u8], name: &str) {
|
||||
for byte in sum {
|
||||
print!("{:02x}", byte);
|
||||
}
|
||||
println!("\t{}", name);
|
||||
}
|
||||
|
||||
/// Compute digest value for given `Reader` and print it
|
||||
/// On any error simply return without doing anything
|
||||
fn process<D: Digest + Default, R: Read>(reader: &mut R, name: &str) {
|
||||
let mut sh = D::default();
|
||||
let mut buffer = [0u8; BUFFER_SIZE];
|
||||
loop {
|
||||
let n = match reader.read(&mut buffer) {
|
||||
Ok(n) => n,
|
||||
Err(_) => return,
|
||||
};
|
||||
sh.update(&buffer[..n]);
|
||||
if n == 0 || n < BUFFER_SIZE {
|
||||
break;
|
||||
}
|
||||
}
|
||||
print_result(&sh.finalize(), name);
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let args = env::args();
|
||||
// Process files listed in command line arguments one by one
|
||||
// If no files provided process input from stdin
|
||||
if args.len() > 1 {
|
||||
for path in args.skip(1) {
|
||||
if let Ok(mut file) = fs::File::open(&path) {
|
||||
process::<Gost94Test, _>(&mut file, &path);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
process::<Gost94Test, _>(&mut io::stdin(), "-");
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
const S_CRYPTO_PRO: SBox = [
|
||||
[10, 4, 5, 6, 8, 1, 3, 7, 13, 12, 14, 0, 9, 2, 11, 15],
|
||||
[5, 15, 4, 0, 2, 13, 11, 9, 1, 7, 6, 3, 12, 14, 10, 8],
|
||||
[7, 15, 12, 14, 9, 4, 1, 0, 3, 11, 5, 2, 6, 10, 8, 13],
|
||||
[4, 10, 7, 12, 0, 15, 2, 8, 14, 1, 6, 5, 13, 11, 9, 3],
|
||||
[7, 6, 4, 11, 9, 12, 2, 10, 1, 8, 0, 14, 15, 13, 3, 5],
|
||||
[7, 6, 2, 4, 13, 9, 15, 0, 10, 1, 5, 11, 8, 14, 12, 3],
|
||||
[13, 14, 4, 1, 7, 0, 5, 10, 3, 12, 8, 15, 6, 2, 9, 11],
|
||||
[1, 3, 10, 9, 5, 11, 4, 15, 8, 6, 7, 14, 13, 0, 2, 12],
|
||||
];
|
||||
|
||||
gost94_impl!(Gost94CryptoPro, S_CRYPTO_PRO);
|
||||
@@ -1,19 +1,23 @@
|
||||
#![allow(clippy::many_single_char_names)]
|
||||
use block_buffer::block_padding::ZeroPadding;
|
||||
use block_buffer::BlockBuffer;
|
||||
use core::convert::TryInto;
|
||||
use digest::{consts::U32, generic_array::GenericArray};
|
||||
use digest::{BlockInput, FixedOutputDirty, Reset, Update};
|
||||
use core::{convert::TryInto, fmt};
|
||||
use digest::{
|
||||
block_buffer::Eager,
|
||||
consts::U32,
|
||||
core_api::{
|
||||
AlgorithmName, Block as TBlock, BlockSizeUser, Buffer, BufferKindUser, FixedOutputCore,
|
||||
OutputSizeUser, Reset, UpdateCore,
|
||||
},
|
||||
generic_array::{typenum::Unsigned, GenericArray},
|
||||
HashMarker, Output,
|
||||
};
|
||||
|
||||
pub(crate) type Block = [u8; 32];
|
||||
use crate::params::{Block, Gost94Params, SBox};
|
||||
|
||||
const C: Block = [
|
||||
0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00, 0xff, 0x00,
|
||||
0x00, 0xff, 0xff, 0x00, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0xff,
|
||||
];
|
||||
|
||||
pub type SBox = [[u8; 16]; 8];
|
||||
|
||||
fn sbox(a: u32, s: &SBox) -> u32 {
|
||||
let mut v = 0;
|
||||
|
||||
@@ -114,15 +118,23 @@ fn psi(block: &mut Block) {
|
||||
block.copy_from_slice(&out);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn adc(a: &mut u64, b: u64, carry: &mut u64) {
|
||||
let ret = (*a as u128) + (b as u128) + (*carry as u128);
|
||||
*a = ret as u64;
|
||||
*carry = (ret >> 64) as u64;
|
||||
}
|
||||
|
||||
/// Core GOST94 algorithm generic over parameters.
|
||||
#[derive(Clone)]
|
||||
struct Gost94State {
|
||||
s: SBox,
|
||||
pub struct Gost94Core<P: Gost94Params> {
|
||||
h: Block,
|
||||
n: [u64; 4],
|
||||
sigma: [u64; 4],
|
||||
_m: core::marker::PhantomData<P>,
|
||||
}
|
||||
|
||||
impl Gost94State {
|
||||
impl<P: Gost94Params> Gost94Core<P> {
|
||||
fn shuffle(&mut self, m: &Block, s: &Block) {
|
||||
let mut res = Block::default();
|
||||
res.copy_from_slice(s);
|
||||
@@ -141,23 +153,23 @@ impl Gost94State {
|
||||
let mut s = Block::default();
|
||||
s.copy_from_slice(&self.h);
|
||||
let k = p(x(&self.h, m));
|
||||
encrypt(&mut s[0..8], k, &self.s);
|
||||
encrypt(&mut s[0..8], k, &P::S_BOX);
|
||||
|
||||
let u = a(self.h);
|
||||
let v = a(a(*m));
|
||||
let k = p(x(&u, &v));
|
||||
encrypt(&mut s[8..16], k, &self.s);
|
||||
encrypt(&mut s[8..16], k, &P::S_BOX);
|
||||
|
||||
let mut u = a(u);
|
||||
x_mut(&mut u, &C);
|
||||
let v = a(a(v));
|
||||
let k = p(x(&u, &v));
|
||||
encrypt(&mut s[16..24], k, &self.s);
|
||||
encrypt(&mut s[16..24], k, &P::S_BOX);
|
||||
|
||||
let u = a(u);
|
||||
let v = a(a(v));
|
||||
let k = p(x(&u, &v));
|
||||
encrypt(&mut s[24..32], k, &self.s);
|
||||
encrypt(&mut s[24..32], k, &P::S_BOX);
|
||||
|
||||
self.shuffle(m, &s);
|
||||
}
|
||||
@@ -178,92 +190,88 @@ impl Gost94State {
|
||||
adc(&mut self.n[3], 0, &mut carry);
|
||||
}
|
||||
|
||||
fn process_block(&mut self, block: &GenericArray<u8, U32>) {
|
||||
#[inline(always)]
|
||||
fn compress(&mut self, block: &GenericArray<u8, U32>) {
|
||||
let block = unsafe { &*(block.as_ptr() as *const [u8; 32]) };
|
||||
self.f(block);
|
||||
self.update_sigma(block);
|
||||
}
|
||||
}
|
||||
|
||||
/// GOST94
|
||||
#[derive(Clone)]
|
||||
pub struct Gost94 {
|
||||
buffer: BlockBuffer<U32>,
|
||||
state: Gost94State,
|
||||
h0: Block,
|
||||
}
|
||||
impl<P: Gost94Params> HashMarker for Gost94Core<P> {}
|
||||
|
||||
impl Gost94 {
|
||||
/// Create new [`Gost94`] instance with given S-Box and IV
|
||||
pub fn new(s: SBox, h: Block) -> Self {
|
||||
let n = Default::default();
|
||||
let sigma = Default::default();
|
||||
Gost94 {
|
||||
buffer: Default::default(),
|
||||
h0: h,
|
||||
state: Gost94State { s, h, n, sigma },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockInput for Gost94 {
|
||||
impl<P: Gost94Params> BlockSizeUser for Gost94Core<P> {
|
||||
type BlockSize = U32;
|
||||
}
|
||||
|
||||
impl Update for Gost94 {
|
||||
fn update(&mut self, input: impl AsRef<[u8]>) {
|
||||
let input = input.as_ref();
|
||||
let s = &mut self.state;
|
||||
s.update_n(input.len());
|
||||
self.buffer.input_block(input, |d| s.process_block(d));
|
||||
impl<P: Gost94Params> BufferKindUser for Gost94Core<P> {
|
||||
type BufferKind = Eager;
|
||||
}
|
||||
|
||||
impl<P: Gost94Params> OutputSizeUser for Gost94Core<P> {
|
||||
type OutputSize = U32;
|
||||
}
|
||||
|
||||
impl<P: Gost94Params> UpdateCore for Gost94Core<P> {
|
||||
#[inline]
|
||||
fn update_blocks(&mut self, blocks: &[TBlock<Self>]) {
|
||||
let len = Self::BlockSize::USIZE * blocks.len();
|
||||
self.update_n(len);
|
||||
blocks.iter().for_each(|b| self.compress(b));
|
||||
}
|
||||
}
|
||||
|
||||
impl FixedOutputDirty for Gost94 {
|
||||
type OutputSize = U32;
|
||||
|
||||
fn finalize_into_dirty(&mut self, out: &mut GenericArray<u8, U32>) {
|
||||
let self_state = &mut self.state;
|
||||
|
||||
if self.buffer.position() != 0 {
|
||||
let block = self
|
||||
.buffer
|
||||
.pad_with::<ZeroPadding>()
|
||||
.expect("we never use input_lazy");
|
||||
|
||||
self_state.process_block(block);
|
||||
impl<P: Gost94Params> FixedOutputCore for Gost94Core<P> {
|
||||
#[inline]
|
||||
fn finalize_fixed_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
|
||||
if buffer.get_pos() != 0 {
|
||||
self.update_n(buffer.get_pos());
|
||||
self.compress(buffer.pad_with_zeros());
|
||||
}
|
||||
|
||||
let mut buf = Block::default();
|
||||
for (o, v) in buf.chunks_exact_mut(8).zip(self_state.n.iter()) {
|
||||
for (o, v) in buf.chunks_exact_mut(8).zip(self.n.iter()) {
|
||||
o.copy_from_slice(&v.to_le_bytes());
|
||||
}
|
||||
self_state.f(&buf);
|
||||
self.f(&buf);
|
||||
|
||||
for (o, v) in buf.chunks_exact_mut(8).zip(self_state.sigma.iter()) {
|
||||
for (o, v) in buf.chunks_exact_mut(8).zip(self.sigma.iter()) {
|
||||
o.copy_from_slice(&v.to_le_bytes());
|
||||
}
|
||||
self_state.f(&buf);
|
||||
self.f(&buf);
|
||||
|
||||
out.copy_from_slice(&self.state.h);
|
||||
out.copy_from_slice(&self.h);
|
||||
}
|
||||
}
|
||||
|
||||
impl Reset for Gost94 {
|
||||
impl<P: Gost94Params> Default for Gost94Core<P> {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
h: P::H0,
|
||||
n: Default::default(),
|
||||
sigma: Default::default(),
|
||||
_m: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Gost94Params> Reset for Gost94Core<P> {
|
||||
#[inline]
|
||||
fn reset(&mut self) {
|
||||
self.buffer.reset();
|
||||
self.state.n = Default::default();
|
||||
self.state.h = self.h0;
|
||||
self.state.sigma = Default::default();
|
||||
*self = Default::default();
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn adc(a: &mut u64, b: u64, carry: &mut u64) {
|
||||
let ret = (*a as u128) + (b as u128) + (*carry as u128);
|
||||
*a = ret as u64;
|
||||
*carry = (ret >> 64) as u64;
|
||||
impl<P: Gost94Params> AlgorithmName for Gost94Core<P> {
|
||||
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(P::NAME)
|
||||
}
|
||||
}
|
||||
|
||||
opaque_debug::implement!(Gost94);
|
||||
digest::impl_write!(Gost94);
|
||||
impl<P: Gost94Params> fmt::Debug for Gost94Core<P> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
f.write_str(P::NAME)?;
|
||||
f.write_str("Core { .. }")
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,21 @@
|
||||
//! An implementation of the [GOST R 34.11-94][1] cryptographic hash algorithm.
|
||||
//!
|
||||
//! # Usage
|
||||
//!
|
||||
//! ```rust
|
||||
//! use gost94::{Gost94Test, Digest};
|
||||
//! use gost94::{Gost94CryptoPro, Digest};
|
||||
//! use hex_literal::hex;
|
||||
//!
|
||||
//! // create a Gost94 hasher instance with test S-box
|
||||
//! let mut hasher = Gost94Test::new();
|
||||
//! // create Gost94 hasher instance with CryptoPro params
|
||||
//! let mut hasher = Gost94CryptoPro::new();
|
||||
//!
|
||||
//! // process input message
|
||||
//! hasher.update(b"hello world");
|
||||
//! hasher.update("The quick brown fox jumps over the lazy dog");
|
||||
//!
|
||||
//! // acquire hash digest in the form of GenericArray,
|
||||
//! // which in this case is equivalent to [u8; 32]
|
||||
//! let result = hasher.finalize();
|
||||
//! assert_eq!(result[..], hex!("
|
||||
//! 1bb6ce69d2e895a78489c87a0712a2f40258d1fae3a4666c23f8f487bef0e22a
|
||||
//! 9004294a361a508c586fe53d1f1b02746765e71b765472786e4770d565830a76
|
||||
//! "));
|
||||
//! ```
|
||||
//!
|
||||
@@ -27,25 +26,28 @@
|
||||
|
||||
#![no_std]
|
||||
#![doc(
|
||||
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
|
||||
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
|
||||
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
|
||||
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
|
||||
html_root_url = "https://docs.rs/gost94/0.10.0"
|
||||
)]
|
||||
#![warn(missing_docs, rust_2018_idioms)]
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
extern crate std;
|
||||
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
use digest::core_api::CoreWrapper;
|
||||
|
||||
mod cryptopro;
|
||||
mod gost94;
|
||||
mod s2015;
|
||||
mod test_param;
|
||||
mod gost94_core;
|
||||
/// GOST94 parameters.
|
||||
pub mod params;
|
||||
|
||||
pub use digest::{self, Digest};
|
||||
|
||||
pub use crate::cryptopro::Gost94CryptoPro;
|
||||
pub use crate::gost94::Gost94;
|
||||
pub use crate::s2015::Gost94s2015;
|
||||
pub use crate::test_param::Gost94Test;
|
||||
pub use gost94_core::Gost94Core;
|
||||
|
||||
/// GOST94 hash function with CryptoPro parameters.
|
||||
pub type Gost94CryptoPro = CoreWrapper<Gost94Core<params::CryptoProParam>>;
|
||||
/// GOST94 hash function with S-box defined in GOST R 34.12-2015.
|
||||
pub type Gost94s2015 = CoreWrapper<Gost94Core<params::S2015Param>>;
|
||||
/// GOST94 hash function with test parameters.
|
||||
pub type Gost94Test = CoreWrapper<Gost94Core<params::TestParam>>;
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
macro_rules! gost94_impl {
|
||||
($state:ident, $sbox:expr) => {
|
||||
use digest::{consts::U32, BlockInput, FixedOutputDirty, Reset, Update};
|
||||
use $crate::gost94::{Block, Gost94, SBox};
|
||||
|
||||
/// GOST94 state
|
||||
#[derive(Clone)]
|
||||
pub struct $state {
|
||||
sh: Gost94,
|
||||
}
|
||||
|
||||
impl Default for $state {
|
||||
fn default() -> Self {
|
||||
$state {
|
||||
sh: Gost94::new($sbox, Block::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockInput for $state {
|
||||
type BlockSize = U32;
|
||||
}
|
||||
|
||||
impl Update for $state {
|
||||
fn update(&mut self, input: impl AsRef<[u8]>) {
|
||||
let input = input.as_ref();
|
||||
self.sh.update(input);
|
||||
}
|
||||
}
|
||||
|
||||
impl FixedOutputDirty for $state {
|
||||
type OutputSize = U32;
|
||||
|
||||
fn finalize_into_dirty(&mut self, out: &mut digest::Output<Self>) {
|
||||
self.sh.finalize_into_dirty(out)
|
||||
}
|
||||
}
|
||||
|
||||
impl Reset for $state {
|
||||
fn reset(&mut self) {
|
||||
self.sh.reset()
|
||||
}
|
||||
}
|
||||
|
||||
opaque_debug::implement!($state);
|
||||
digest::impl_write!($state);
|
||||
};
|
||||
}
|
||||
70
gost94/src/params.rs
Normal file
70
gost94/src/params.rs
Normal file
@@ -0,0 +1,70 @@
|
||||
pub(crate) type Block = [u8; 32];
|
||||
pub(crate) type SBox = [[u8; 16]; 8];
|
||||
|
||||
/// Trait for storing parameter constants.
|
||||
// TODO: replace with const generics
|
||||
pub trait Gost94Params {
|
||||
/// S-box value.
|
||||
const S_BOX: SBox;
|
||||
/// Initialization vector value.
|
||||
const H0: Block;
|
||||
/// Algorithm name
|
||||
const NAME: &'static str;
|
||||
}
|
||||
|
||||
/// CryptoPro parameters.
|
||||
#[derive(Copy, Clone, Default)]
|
||||
pub struct CryptoProParam;
|
||||
|
||||
impl Gost94Params for CryptoProParam {
|
||||
const S_BOX: SBox = [
|
||||
[10, 4, 5, 6, 8, 1, 3, 7, 13, 12, 14, 0, 9, 2, 11, 15],
|
||||
[5, 15, 4, 0, 2, 13, 11, 9, 1, 7, 6, 3, 12, 14, 10, 8],
|
||||
[7, 15, 12, 14, 9, 4, 1, 0, 3, 11, 5, 2, 6, 10, 8, 13],
|
||||
[4, 10, 7, 12, 0, 15, 2, 8, 14, 1, 6, 5, 13, 11, 9, 3],
|
||||
[7, 6, 4, 11, 9, 12, 2, 10, 1, 8, 0, 14, 15, 13, 3, 5],
|
||||
[7, 6, 2, 4, 13, 9, 15, 0, 10, 1, 5, 11, 8, 14, 12, 3],
|
||||
[13, 14, 4, 1, 7, 0, 5, 10, 3, 12, 8, 15, 6, 2, 9, 11],
|
||||
[1, 3, 10, 9, 5, 11, 4, 15, 8, 6, 7, 14, 13, 0, 2, 12],
|
||||
];
|
||||
const H0: Block = [0; 32];
|
||||
const NAME: &'static str = "Gost94CryptoPro";
|
||||
}
|
||||
|
||||
/// S-Box defined in GOST R 34.12-2015.
|
||||
#[derive(Copy, Clone, Default)]
|
||||
pub struct S2015Param;
|
||||
|
||||
impl Gost94Params for S2015Param {
|
||||
const S_BOX: SBox = [
|
||||
[12, 4, 6, 2, 10, 5, 11, 9, 14, 8, 13, 7, 0, 3, 15, 1],
|
||||
[6, 8, 2, 3, 9, 10, 5, 12, 1, 14, 4, 7, 11, 13, 0, 15],
|
||||
[11, 3, 5, 8, 2, 15, 10, 13, 14, 1, 7, 4, 12, 9, 6, 0],
|
||||
[12, 8, 2, 1, 13, 4, 15, 6, 7, 0, 10, 5, 3, 14, 9, 11],
|
||||
[7, 15, 5, 10, 8, 1, 6, 13, 0, 9, 3, 14, 11, 4, 2, 12],
|
||||
[5, 13, 15, 6, 9, 2, 12, 10, 11, 7, 8, 1, 4, 3, 14, 0],
|
||||
[8, 14, 2, 5, 6, 9, 1, 12, 15, 4, 11, 0, 13, 10, 3, 7],
|
||||
[1, 7, 14, 13, 0, 5, 8, 3, 4, 15, 10, 6, 9, 12, 11, 2],
|
||||
];
|
||||
const H0: Block = [0; 32];
|
||||
const NAME: &'static str = "Gost94s2015";
|
||||
}
|
||||
|
||||
/// Test parameters.
|
||||
#[derive(Copy, Clone, Default)]
|
||||
pub struct TestParam;
|
||||
|
||||
impl Gost94Params for TestParam {
|
||||
const S_BOX: SBox = [
|
||||
[4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3],
|
||||
[14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9],
|
||||
[5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11],
|
||||
[7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3],
|
||||
[6, 12, 7, 1, 5, 15, 13, 8, 4, 10, 9, 14, 0, 3, 11, 2],
|
||||
[4, 11, 10, 0, 7, 2, 1, 13, 3, 6, 8, 5, 9, 12, 15, 14],
|
||||
[13, 11, 4, 1, 3, 15, 5, 9, 0, 10, 14, 7, 6, 8, 2, 12],
|
||||
[1, 15, 13, 0, 5, 7, 10, 4, 9, 2, 3, 14, 6, 11, 8, 12],
|
||||
];
|
||||
const H0: Block = [0; 32];
|
||||
const NAME: &'static str = "Gost94Test";
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
const S2015: SBox = [
|
||||
[12, 4, 6, 2, 10, 5, 11, 9, 14, 8, 13, 7, 0, 3, 15, 1],
|
||||
[6, 8, 2, 3, 9, 10, 5, 12, 1, 14, 4, 7, 11, 13, 0, 15],
|
||||
[11, 3, 5, 8, 2, 15, 10, 13, 14, 1, 7, 4, 12, 9, 6, 0],
|
||||
[12, 8, 2, 1, 13, 4, 15, 6, 7, 0, 10, 5, 3, 14, 9, 11],
|
||||
[7, 15, 5, 10, 8, 1, 6, 13, 0, 9, 3, 14, 11, 4, 2, 12],
|
||||
[5, 13, 15, 6, 9, 2, 12, 10, 11, 7, 8, 1, 4, 3, 14, 0],
|
||||
[8, 14, 2, 5, 6, 9, 1, 12, 15, 4, 11, 0, 13, 10, 3, 7],
|
||||
[1, 7, 14, 13, 0, 5, 8, 3, 4, 15, 10, 6, 9, 12, 11, 2],
|
||||
];
|
||||
|
||||
gost94_impl!(Gost94s2015, S2015);
|
||||
@@ -1,12 +0,0 @@
|
||||
const S_TEST: SBox = [
|
||||
[4, 10, 9, 2, 13, 8, 0, 14, 6, 11, 1, 12, 7, 15, 5, 3],
|
||||
[14, 11, 4, 12, 6, 13, 15, 10, 2, 3, 8, 1, 0, 7, 5, 9],
|
||||
[5, 8, 1, 13, 10, 3, 4, 2, 14, 15, 12, 7, 6, 0, 9, 11],
|
||||
[7, 13, 10, 1, 0, 8, 9, 15, 14, 4, 6, 12, 11, 2, 5, 3],
|
||||
[6, 12, 7, 1, 5, 15, 13, 8, 4, 10, 9, 14, 0, 3, 11, 2],
|
||||
[4, 11, 10, 0, 7, 2, 1, 13, 3, 6, 8, 5, 9, 12, 15, 14],
|
||||
[13, 11, 4, 1, 3, 15, 5, 9, 0, 10, 14, 7, 6, 8, 2, 12],
|
||||
[1, 15, 13, 0, 5, 7, 10, 4, 9, 2, 3, 14, 6, 11, 8, 12],
|
||||
];
|
||||
|
||||
gost94_impl!(Gost94Test, S_TEST);
|
||||
Binary file not shown.
@@ -1 +0,0 @@
|
||||
†“(z¦/”x÷Ë1.À†klNJAèôÿÍ'ÝUO
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,34 +1,41 @@
|
||||
use digest::dev::{digest_test, one_million_a};
|
||||
use digest::dev::{feed_rand_16mib, fixed_reset_test};
|
||||
use digest::new_test;
|
||||
use gost94::{Digest, Gost94CryptoPro, Gost94Test};
|
||||
use hex_literal::hex;
|
||||
|
||||
new_test!(gost94_test_main, "test", gost94::Gost94Test, digest_test);
|
||||
new_test!(gost94_test_main, "test", Gost94Test, fixed_reset_test);
|
||||
new_test!(
|
||||
gost94_cryptopro_main,
|
||||
"cryptopro",
|
||||
gost94::Gost94CryptoPro,
|
||||
digest_test
|
||||
Gost94CryptoPro,
|
||||
fixed_reset_test
|
||||
);
|
||||
|
||||
#[test]
|
||||
fn gost94_test_1million_a() {
|
||||
let output = include_bytes!("data/test_one_million_a.bin");
|
||||
one_million_a::<gost94::Gost94Test>(output);
|
||||
fn gost94_test_rand() {
|
||||
let mut h = Gost94Test::new();
|
||||
feed_rand_16mib(&mut h);
|
||||
assert_eq!(
|
||||
h.finalize()[..],
|
||||
hex!("fdd1b9f220898c117f82d664716795e12f5e9f458ee8cd71d014329438db5089")[..]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn gost94_cryptopro_1million_a() {
|
||||
let output = include_bytes!("data/cryptopro_one_million_a.bin");
|
||||
one_million_a::<gost94::Gost94CryptoPro>(output);
|
||||
fn gost94_cryptopro_rand() {
|
||||
let mut h = Gost94CryptoPro::new();
|
||||
feed_rand_16mib(&mut h);
|
||||
assert_eq!(
|
||||
h.finalize()[..],
|
||||
hex!("1d539ea8a318df8c13d304fcfd9beeec188bb48683d9d7f4c4a3750cff6ef22a")[..]
|
||||
);
|
||||
}
|
||||
|
||||
/// Test vectors from:
|
||||
/// https://github.com/gost-engine/engine/blob/master/test/01-digest.t
|
||||
#[test]
|
||||
fn gost_engine_tests() {
|
||||
use digest::Digest;
|
||||
use hex_literal::hex;
|
||||
|
||||
let mut h = gost94::Gost94CryptoPro::new();
|
||||
let mut h = Gost94CryptoPro::new();
|
||||
for _ in 0..128 {
|
||||
h.update(b"12345670");
|
||||
}
|
||||
@@ -70,9 +77,7 @@ fn gost_engine_tests() {
|
||||
|
||||
#[test]
|
||||
fn arithmetic_overflow_regression() {
|
||||
use digest::Digest;
|
||||
|
||||
let mut h = gost94::Gost94Test::default();
|
||||
let mut h = Gost94Test::default();
|
||||
h.update(&include_bytes!("data/arithmetic_overflow.bin")[..]);
|
||||
h.finalize().as_slice();
|
||||
}
|
||||
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.10.0 (2021-12-07)
|
||||
### Changed
|
||||
- Update to `digest` v0.10 and significantly improve performance ([#217])
|
||||
|
||||
[#217]: https://github.com/RustCrypto/hashes/pull/217
|
||||
|
||||
## 0.9.0 (2020-06-12)
|
||||
### Changed
|
||||
- Bump `opaque-debug` to v0.3.0 ([#168])
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "groestl"
|
||||
version = "0.9.0"
|
||||
version = "0.10.0" # Also update html_root_url in lib.rs when bumping this
|
||||
description = "Grøstl hash function"
|
||||
authors = ["RustCrypto Developers"]
|
||||
license = "MIT OR Apache-2.0"
|
||||
@@ -12,12 +12,10 @@ keywords = ["crypto", "groestl", "grostl", "hash", "digest"]
|
||||
categories = ["cryptography", "no-std"]
|
||||
|
||||
[dependencies]
|
||||
digest = "0.9"
|
||||
block-buffer = "0.9"
|
||||
opaque-debug = "0.3"
|
||||
digest = "0.10"
|
||||
|
||||
[dev-dependencies]
|
||||
digest = { version = "0.9", features = ["dev"] }
|
||||
digest = { version = "0.10", features = ["dev"] }
|
||||
hex-literal = "0.2"
|
||||
|
||||
[features]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2017 Gulshan Singh
|
||||
Copyright (c) 2020 RustCrypto Developers
|
||||
|
||||
Permission is hereby granted, free of charge, to any
|
||||
person obtaining a copy of this software and associated
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
#![no_std]
|
||||
#![feature(test)]
|
||||
|
||||
digest::bench!(groestl::Groestl256);
|
||||
@@ -1,4 +0,0 @@
|
||||
#![no_std]
|
||||
#![feature(test)]
|
||||
|
||||
digest::bench!(groestl::Groestl512);
|
||||
22
groestl/benches/mod.rs
Normal file
22
groestl/benches/mod.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
#![feature(test)]
|
||||
extern crate test;
|
||||
|
||||
use digest::bench_update;
|
||||
use groestl::{Groestl256, Groestl512};
|
||||
use test::Bencher;
|
||||
|
||||
bench_update!(
|
||||
Groestl256::default();
|
||||
groestl256_10 10;
|
||||
groestl256_100 100;
|
||||
groestl256_1000 1000;
|
||||
groestl256_10000 10000;
|
||||
);
|
||||
|
||||
bench_update!(
|
||||
Groestl512::default();
|
||||
groestl512_10 10;
|
||||
groestl512_100 100;
|
||||
groestl512_1000 1000;
|
||||
groestl512_10000 10000;
|
||||
);
|
||||
99
groestl/src/compress1024.rs
Normal file
99
groestl/src/compress1024.rs
Normal file
@@ -0,0 +1,99 @@
|
||||
#![allow(clippy::needless_range_loop)]
|
||||
use crate::table::TABLE;
|
||||
use core::{convert::TryInto, u64};
|
||||
|
||||
pub(crate) const COLS: usize = 16;
|
||||
const ROUNDS: u64 = 14;
|
||||
type Block = super::Block<super::GroestlLongVarCore>;
|
||||
|
||||
#[inline(always)]
|
||||
fn column(x: &[u64; COLS], c: [usize; 8]) -> u64 {
|
||||
let mut t = 0;
|
||||
for i in 0..8 {
|
||||
let sl = 8 * (7 - i);
|
||||
let idx = ((x[c[i]] >> sl) & 0xFF) as usize;
|
||||
t ^= TABLE[i][idx];
|
||||
}
|
||||
t
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn rndq(mut x: [u64; COLS], r: u64) -> [u64; COLS] {
|
||||
for i in 0..COLS {
|
||||
x[i] ^= u64::MAX.wrapping_sub((i as u64) << 4) ^ r;
|
||||
}
|
||||
[
|
||||
column(&x, [1, 3, 5, 11, 0, 2, 4, 6]),
|
||||
column(&x, [2, 4, 6, 12, 1, 3, 5, 7]),
|
||||
column(&x, [3, 5, 7, 13, 2, 4, 6, 8]),
|
||||
column(&x, [4, 6, 8, 14, 3, 5, 7, 9]),
|
||||
column(&x, [5, 7, 9, 15, 4, 6, 8, 10]),
|
||||
column(&x, [6, 8, 10, 0, 5, 7, 9, 11]),
|
||||
column(&x, [7, 9, 11, 1, 6, 8, 10, 12]),
|
||||
column(&x, [8, 10, 12, 2, 7, 9, 11, 13]),
|
||||
column(&x, [9, 11, 13, 3, 8, 10, 12, 14]),
|
||||
column(&x, [10, 12, 14, 4, 9, 11, 13, 15]),
|
||||
column(&x, [11, 13, 15, 5, 10, 12, 14, 0]),
|
||||
column(&x, [12, 14, 0, 6, 11, 13, 15, 1]),
|
||||
column(&x, [13, 15, 1, 7, 12, 14, 0, 2]),
|
||||
column(&x, [14, 0, 2, 8, 13, 15, 1, 3]),
|
||||
column(&x, [15, 1, 3, 9, 14, 0, 2, 4]),
|
||||
column(&x, [0, 2, 4, 10, 15, 1, 3, 5]),
|
||||
]
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn rndp(mut x: [u64; COLS], r: u64) -> [u64; COLS] {
|
||||
for i in 0..COLS {
|
||||
x[i] ^= ((i as u64) << 60) ^ r;
|
||||
}
|
||||
[
|
||||
column(&x, [0, 1, 2, 3, 4, 5, 6, 11]),
|
||||
column(&x, [1, 2, 3, 4, 5, 6, 7, 12]),
|
||||
column(&x, [2, 3, 4, 5, 6, 7, 8, 13]),
|
||||
column(&x, [3, 4, 5, 6, 7, 8, 9, 14]),
|
||||
column(&x, [4, 5, 6, 7, 8, 9, 10, 15]),
|
||||
column(&x, [5, 6, 7, 8, 9, 10, 11, 0]),
|
||||
column(&x, [6, 7, 8, 9, 10, 11, 12, 1]),
|
||||
column(&x, [7, 8, 9, 10, 11, 12, 13, 2]),
|
||||
column(&x, [8, 9, 10, 11, 12, 13, 14, 3]),
|
||||
column(&x, [9, 10, 11, 12, 13, 14, 15, 4]),
|
||||
column(&x, [10, 11, 12, 13, 14, 15, 0, 5]),
|
||||
column(&x, [11, 12, 13, 14, 15, 0, 1, 6]),
|
||||
column(&x, [12, 13, 14, 15, 0, 1, 2, 7]),
|
||||
column(&x, [13, 14, 15, 0, 1, 2, 3, 8]),
|
||||
column(&x, [14, 15, 0, 1, 2, 3, 4, 9]),
|
||||
column(&x, [15, 0, 1, 2, 3, 4, 5, 10]),
|
||||
]
|
||||
}
|
||||
|
||||
pub(crate) fn compress(h: &mut [u64; COLS], block: &Block) {
|
||||
let mut q = [0u64; COLS];
|
||||
for (chunk, v) in block.chunks_exact(8).zip(q.iter_mut()) {
|
||||
*v = u64::from_be_bytes(chunk.try_into().unwrap());
|
||||
}
|
||||
let mut p = [0u64; COLS];
|
||||
for i in 0..COLS {
|
||||
p[i] = h[i] ^ q[i];
|
||||
}
|
||||
for i in 0..ROUNDS {
|
||||
q = rndq(q, i);
|
||||
}
|
||||
for i in 0..ROUNDS {
|
||||
p = rndp(p, i << 56);
|
||||
}
|
||||
for i in 0..COLS {
|
||||
h[i] ^= q[i] ^ p[i];
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn p(h: &[u64; COLS]) -> [u64; COLS] {
|
||||
let mut p = *h;
|
||||
for i in 0..ROUNDS {
|
||||
p = rndp(p, i << 56);
|
||||
}
|
||||
for i in 0..COLS {
|
||||
p[i] ^= h[i];
|
||||
}
|
||||
p
|
||||
}
|
||||
83
groestl/src/compress512.rs
Normal file
83
groestl/src/compress512.rs
Normal file
@@ -0,0 +1,83 @@
|
||||
#![allow(clippy::needless_range_loop)]
|
||||
use crate::table::TABLE;
|
||||
use core::{convert::TryInto, u64};
|
||||
type Block = super::Block<super::GroestlShortVarCore>;
|
||||
|
||||
pub(crate) const COLS: usize = 8;
|
||||
const ROUNDS: u64 = 10;
|
||||
|
||||
#[inline(always)]
|
||||
fn column(x: &[u64; COLS], c: [usize; 8]) -> u64 {
|
||||
let mut t = 0;
|
||||
for i in 0..8 {
|
||||
let sl = 8 * (7 - i);
|
||||
let idx = ((x[c[i]] >> sl) & 0xFF) as usize;
|
||||
t ^= TABLE[i][idx];
|
||||
}
|
||||
t
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn rndq(mut x: [u64; COLS], r: u64) -> [u64; COLS] {
|
||||
for i in 0..COLS {
|
||||
x[i] ^= u64::MAX.wrapping_sub((i as u64) << 4) ^ r;
|
||||
}
|
||||
[
|
||||
column(&x, [1, 3, 5, 7, 0, 2, 4, 6]),
|
||||
column(&x, [2, 4, 6, 0, 1, 3, 5, 7]),
|
||||
column(&x, [3, 5, 7, 1, 2, 4, 6, 0]),
|
||||
column(&x, [4, 6, 0, 2, 3, 5, 7, 1]),
|
||||
column(&x, [5, 7, 1, 3, 4, 6, 0, 2]),
|
||||
column(&x, [6, 0, 2, 4, 5, 7, 1, 3]),
|
||||
column(&x, [7, 1, 3, 5, 6, 0, 2, 4]),
|
||||
column(&x, [0, 2, 4, 6, 7, 1, 3, 5]),
|
||||
]
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn rndp(mut x: [u64; COLS], r: u64) -> [u64; COLS] {
|
||||
for i in 0..COLS {
|
||||
x[i] ^= ((i as u64) << 60) ^ r;
|
||||
}
|
||||
[
|
||||
column(&x, [0, 1, 2, 3, 4, 5, 6, 7]),
|
||||
column(&x, [1, 2, 3, 4, 5, 6, 7, 0]),
|
||||
column(&x, [2, 3, 4, 5, 6, 7, 0, 1]),
|
||||
column(&x, [3, 4, 5, 6, 7, 0, 1, 2]),
|
||||
column(&x, [4, 5, 6, 7, 0, 1, 2, 3]),
|
||||
column(&x, [5, 6, 7, 0, 1, 2, 3, 4]),
|
||||
column(&x, [6, 7, 0, 1, 2, 3, 4, 5]),
|
||||
column(&x, [7, 0, 1, 2, 3, 4, 5, 6]),
|
||||
]
|
||||
}
|
||||
|
||||
pub(crate) fn compress(h: &mut [u64; COLS], block: &Block) {
|
||||
let mut q = [0u64; COLS];
|
||||
for (chunk, v) in block.chunks_exact(8).zip(q.iter_mut()) {
|
||||
*v = u64::from_be_bytes(chunk.try_into().unwrap());
|
||||
}
|
||||
let mut p = [0u64; COLS];
|
||||
for i in 0..COLS {
|
||||
p[i] = h[i] ^ q[i];
|
||||
}
|
||||
for i in 0..ROUNDS {
|
||||
q = rndq(q, i);
|
||||
}
|
||||
for i in 0..ROUNDS {
|
||||
p = rndp(p, i << 56);
|
||||
}
|
||||
for i in 0..COLS {
|
||||
h[i] ^= q[i] ^ p[i];
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn p(h: &[u64; COLS]) -> [u64; COLS] {
|
||||
let mut p = *h;
|
||||
for i in 0..ROUNDS {
|
||||
p = rndp(p, i << 56);
|
||||
}
|
||||
for i in 0..COLS {
|
||||
p[i] ^= h[i];
|
||||
}
|
||||
p
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
pub const SBOX: [u8; 256] = [
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16,
|
||||
];
|
||||
|
||||
pub const C_P: [u8; 128] = [
|
||||
0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
];
|
||||
pub const C_Q: [u8; 128] = [
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xef, 0xdf, 0xcf, 0xbf, 0xaf, 0x9f, 0x8f, 0x7f, 0x6f, 0x5f, 0x4f, 0x3f, 0x2f, 0x1f, 0x0f,
|
||||
];
|
||||
|
||||
pub const B: [[u8; 8]; 8] = [
|
||||
[2, 2, 3, 4, 5, 3, 5, 7],
|
||||
[7, 2, 2, 3, 4, 5, 3, 5],
|
||||
[5, 7, 2, 2, 3, 4, 5, 3],
|
||||
[3, 5, 7, 2, 2, 3, 4, 5],
|
||||
[5, 3, 5, 7, 2, 2, 3, 4],
|
||||
[4, 5, 3, 5, 7, 2, 2, 3],
|
||||
[3, 4, 5, 3, 5, 7, 2, 2],
|
||||
[2, 3, 4, 5, 3, 5, 7, 2],
|
||||
];
|
||||
|
||||
pub const SHIFTS_P: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 7];
|
||||
pub const SHIFTS_Q: [u8; 8] = [1, 3, 5, 7, 0, 2, 4, 6];
|
||||
pub const SHIFTS_P_WIDE: [u8; 8] = [0, 1, 2, 3, 4, 5, 6, 11];
|
||||
pub const SHIFTS_Q_WIDE: [u8; 8] = [1, 3, 5, 11, 0, 2, 4, 6];
|
||||
@@ -1,76 +0,0 @@
|
||||
use block_buffer::BlockBuffer;
|
||||
use core::ops::Div;
|
||||
use digest::generic_array::typenum::{Quot, U8};
|
||||
use digest::generic_array::{ArrayLength, GenericArray};
|
||||
|
||||
use crate::state::{xor_generic_array, GroestlState};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Groestl<BlockSize>
|
||||
where
|
||||
BlockSize: ArrayLength<u8> + Div<U8> + Default,
|
||||
BlockSize::ArrayType: Copy,
|
||||
Quot<BlockSize, U8>: ArrayLength<u8>,
|
||||
{
|
||||
buffer: BlockBuffer<BlockSize>,
|
||||
state: GroestlState<BlockSize>,
|
||||
pub output_size: usize,
|
||||
}
|
||||
|
||||
impl<BlockSize> Groestl<BlockSize>
|
||||
where
|
||||
BlockSize: ArrayLength<u8> + Div<U8> + Default,
|
||||
BlockSize::ArrayType: Copy,
|
||||
Quot<BlockSize, U8>: ArrayLength<u8>,
|
||||
Self: Clone,
|
||||
{
|
||||
pub fn new(output_size: usize) -> Result<Self, digest::InvalidOutputSize> {
|
||||
match BlockSize::to_usize() {
|
||||
128 => {
|
||||
if output_size <= 32 || output_size > 64 {
|
||||
return Err(digest::InvalidOutputSize);
|
||||
}
|
||||
}
|
||||
64 => {
|
||||
if output_size == 0 || output_size > 32 {
|
||||
return Err(digest::InvalidOutputSize);
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let state = GroestlState::new(output_size);
|
||||
Ok(Groestl {
|
||||
buffer: Default::default(),
|
||||
state,
|
||||
output_size,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn process(&mut self, input: &[u8]) {
|
||||
let s = &mut self.state;
|
||||
self.buffer.input_block(input, |b| s.compress(b));
|
||||
}
|
||||
|
||||
pub fn finalize(&mut self) -> GenericArray<u8, BlockSize> {
|
||||
let res = {
|
||||
let state = &mut self.state;
|
||||
let l = if self.buffer.remaining() <= 8 {
|
||||
state.num_blocks + 2
|
||||
} else {
|
||||
state.num_blocks + 1
|
||||
};
|
||||
self.buffer.len64_padding_be(l, |b| state.compress(b));
|
||||
xor_generic_array(&state.p(&state.state), &state.state)
|
||||
};
|
||||
|
||||
self.buffer = Default::default();
|
||||
self.state = GroestlState::new(self.output_size);
|
||||
res
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.state = GroestlState::new(self.output_size);
|
||||
self.buffer.reset();
|
||||
}
|
||||
}
|
||||
217
groestl/src/lib.rs
Executable file → Normal file
217
groestl/src/lib.rs
Executable file → Normal file
@@ -2,14 +2,7 @@
|
||||
//!
|
||||
//! # Usage
|
||||
//!
|
||||
//! Groestl can produce a digest of any size between 1 and 64 bytes inclusive.
|
||||
//! This crate defines the common digest sizes (`Groestl224`, `Groestl256`,
|
||||
//! `Groestl384`, and `Groestl512`), but allows you to specify a custom size
|
||||
//! with the `GroestlSmall` and `GroestlBig` structs. `GroestlSmall` allows you
|
||||
//! to specify a digest size between 1 and 32 inclusive, and `GroestlBig` allows
|
||||
//! you to specify a digest size between 33 and 64 inclusive.
|
||||
//!
|
||||
//! ```rust
|
||||
//! ```
|
||||
//! use groestl::{Digest, Groestl256};
|
||||
//! use hex_literal::hex;
|
||||
//!
|
||||
@@ -34,33 +27,199 @@
|
||||
|
||||
#![no_std]
|
||||
#![doc(
|
||||
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
|
||||
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg"
|
||||
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
|
||||
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
|
||||
html_root_url = "https://docs.rs/groestl/0.10.0"
|
||||
)]
|
||||
#![deny(unsafe_code)]
|
||||
#![warn(rust_2018_idioms)]
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
extern crate std;
|
||||
|
||||
pub use digest::{self, Digest};
|
||||
|
||||
mod consts;
|
||||
mod groestl;
|
||||
mod matrix;
|
||||
mod state;
|
||||
#[macro_use]
|
||||
mod macros;
|
||||
use core::fmt;
|
||||
use digest::{
|
||||
block_buffer::Eager,
|
||||
core_api::{
|
||||
AlgorithmName, Block, BlockSizeUser, Buffer, BufferKindUser, CoreWrapper,
|
||||
CtVariableCoreWrapper, OutputSizeUser, RtVariableCoreWrapper, TruncSide, UpdateCore,
|
||||
VariableOutputCore,
|
||||
},
|
||||
generic_array::typenum::{Unsigned, U128, U28, U32, U48, U64},
|
||||
HashMarker, InvalidOutputSize, Output,
|
||||
};
|
||||
|
||||
use crate::groestl::Groestl;
|
||||
use digest::consts::{U128, U28, U32, U48, U64};
|
||||
use digest::generic_array::typenum::Unsigned;
|
||||
use digest::{BlockInput, FixedOutputDirty, InvalidOutputSize, Reset, Update, VariableOutputDirty};
|
||||
mod compress1024;
|
||||
mod compress512;
|
||||
mod table;
|
||||
|
||||
impl_groestl!(Groestl512, U64, U128);
|
||||
impl_groestl!(Groestl384, U48, U128);
|
||||
impl_groestl!(Groestl256, U32, U64);
|
||||
impl_groestl!(Groestl224, U28, U64);
|
||||
/// Lowest-level core hasher state of the short Groestl variant.
|
||||
#[derive(Clone)]
|
||||
pub struct GroestlShortVarCore {
|
||||
state: [u64; compress512::COLS],
|
||||
blocks_len: u64,
|
||||
}
|
||||
|
||||
impl_variable_groestl!(GroestlBig, U128, 32, 64);
|
||||
impl_variable_groestl!(GroestlSmall, U64, 0, 32);
|
||||
impl HashMarker for GroestlShortVarCore {}
|
||||
|
||||
impl BlockSizeUser for GroestlShortVarCore {
|
||||
type BlockSize = U64;
|
||||
}
|
||||
|
||||
impl BufferKindUser for GroestlShortVarCore {
|
||||
type BufferKind = Eager;
|
||||
}
|
||||
|
||||
impl UpdateCore for GroestlShortVarCore {
|
||||
#[inline]
|
||||
fn update_blocks(&mut self, blocks: &[Block<Self>]) {
|
||||
self.blocks_len += blocks.len() as u64;
|
||||
for block in blocks {
|
||||
compress512::compress(&mut self.state, block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OutputSizeUser for GroestlShortVarCore {
|
||||
type OutputSize = U32;
|
||||
}
|
||||
|
||||
impl VariableOutputCore for GroestlShortVarCore {
|
||||
const TRUNC_SIDE: TruncSide = TruncSide::Right;
|
||||
|
||||
#[inline]
|
||||
fn new(output_size: usize) -> Result<Self, InvalidOutputSize> {
|
||||
if output_size > Self::OutputSize::USIZE {
|
||||
return Err(InvalidOutputSize);
|
||||
}
|
||||
let mut state = [0; compress512::COLS];
|
||||
state[compress512::COLS - 1] = 8 * output_size as u64;
|
||||
let blocks_len = 0;
|
||||
Ok(Self { state, blocks_len })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn finalize_variable_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
|
||||
let blocks_len = if buffer.remaining() <= 8 {
|
||||
self.blocks_len + 2
|
||||
} else {
|
||||
self.blocks_len + 1
|
||||
};
|
||||
buffer.len64_padding_be(blocks_len, |b| compress512::compress(&mut self.state, b));
|
||||
let res = compress512::p(&self.state);
|
||||
let n = compress512::COLS / 2;
|
||||
for (chunk, v) in out.chunks_exact_mut(8).zip(res[n..].iter()) {
|
||||
chunk.copy_from_slice(&v.to_be_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AlgorithmName for GroestlShortVarCore {
|
||||
#[inline]
|
||||
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("GroestlShort")
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for GroestlShortVarCore {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("GroestlShortVarCore { ... }")
|
||||
}
|
||||
}
|
||||
|
||||
/// Short Groestl variant which allows to choose output size at runtime.
|
||||
pub type GroestlShortVar = RtVariableCoreWrapper<GroestlShortVarCore>;
|
||||
/// Core hasher state of the short Groestl variant generic over output size.
|
||||
pub type GroestlShortCore<OutSize> = CtVariableCoreWrapper<GroestlShortVarCore, OutSize>;
|
||||
/// Hasher state of the short Groestl variant generic over output size.
|
||||
pub type GroestlShort<OutSize> = CoreWrapper<GroestlShortCore<OutSize>>;
|
||||
|
||||
/// Groestl-224 hasher state.
|
||||
pub type Groestl224 = CoreWrapper<GroestlShortCore<U28>>;
|
||||
/// Groestl-256 hasher state.
|
||||
pub type Groestl256 = CoreWrapper<GroestlShortCore<U32>>;
|
||||
|
||||
/// Lowest-level core hasher state of the long Groestl variant.
|
||||
#[derive(Clone)]
|
||||
pub struct GroestlLongVarCore {
|
||||
state: [u64; compress1024::COLS],
|
||||
blocks_len: u64,
|
||||
}
|
||||
|
||||
impl HashMarker for GroestlLongVarCore {}
|
||||
|
||||
impl BlockSizeUser for GroestlLongVarCore {
|
||||
type BlockSize = U128;
|
||||
}
|
||||
|
||||
impl BufferKindUser for GroestlLongVarCore {
|
||||
type BufferKind = Eager;
|
||||
}
|
||||
|
||||
impl UpdateCore for GroestlLongVarCore {
|
||||
#[inline]
|
||||
fn update_blocks(&mut self, blocks: &[Block<Self>]) {
|
||||
self.blocks_len += blocks.len() as u64;
|
||||
for block in blocks {
|
||||
compress1024::compress(&mut self.state, block);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OutputSizeUser for GroestlLongVarCore {
|
||||
type OutputSize = U64;
|
||||
}
|
||||
|
||||
impl VariableOutputCore for GroestlLongVarCore {
|
||||
const TRUNC_SIDE: TruncSide = TruncSide::Right;
|
||||
|
||||
#[inline]
|
||||
fn new(output_size: usize) -> Result<Self, InvalidOutputSize> {
|
||||
if output_size > Self::OutputSize::USIZE {
|
||||
return Err(InvalidOutputSize);
|
||||
}
|
||||
let mut state = [0; compress1024::COLS];
|
||||
state[compress1024::COLS - 1] = 8 * output_size as u64;
|
||||
let blocks_len = 0;
|
||||
Ok(Self { state, blocks_len })
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn finalize_variable_core(&mut self, buffer: &mut Buffer<Self>, out: &mut Output<Self>) {
|
||||
let blocks_len = if buffer.remaining() <= 8 {
|
||||
self.blocks_len + 2
|
||||
} else {
|
||||
self.blocks_len + 1
|
||||
};
|
||||
buffer.len64_padding_be(blocks_len, |b| compress1024::compress(&mut self.state, b));
|
||||
let res = compress1024::p(&self.state);
|
||||
let n = compress1024::COLS / 2;
|
||||
for (chunk, v) in out.chunks_exact_mut(8).zip(res[n..].iter()) {
|
||||
chunk.copy_from_slice(&v.to_be_bytes());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl AlgorithmName for GroestlLongVarCore {
|
||||
#[inline]
|
||||
fn write_alg_name(f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("GroestlLong")
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for GroestlLongVarCore {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str("GroestlLongVarCore { ... }")
|
||||
}
|
||||
}
|
||||
|
||||
/// Long Groestl variant which allows to choose output size at runtime.
|
||||
pub type GroestlLongVar = RtVariableCoreWrapper<GroestlLongVarCore>;
|
||||
/// Core hasher state of the long Groestl variant generic over output size.
|
||||
pub type GroestlLongCore<OutSize> = CtVariableCoreWrapper<GroestlLongVarCore, OutSize>;
|
||||
/// Hasher state of the long Groestl variant generic over output size.
|
||||
pub type GroestlLong<OutSize> = CoreWrapper<GroestlLongCore<OutSize>>;
|
||||
|
||||
/// Groestl-384 hasher state.
|
||||
pub type Groestl384 = CoreWrapper<GroestlLongCore<U48>>;
|
||||
/// Groestl-512 hasher state.
|
||||
pub type Groestl512 = CoreWrapper<GroestlLongCore<U64>>;
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
macro_rules! impl_groestl {
|
||||
($state:ident, $output:ident, $block:ident) => {
|
||||
#[derive(Clone)]
|
||||
pub struct $state {
|
||||
groestl: Groestl<$block>,
|
||||
}
|
||||
|
||||
impl Default for $state {
|
||||
fn default() -> Self {
|
||||
$state {
|
||||
groestl: Groestl::new($output::to_usize()).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockInput for $state {
|
||||
type BlockSize = $block;
|
||||
}
|
||||
|
||||
impl Update for $state {
|
||||
fn update(&mut self, input: impl AsRef<[u8]>) {
|
||||
let input = input.as_ref();
|
||||
self.groestl.process(input);
|
||||
}
|
||||
}
|
||||
|
||||
impl FixedOutputDirty for $state {
|
||||
type OutputSize = $output;
|
||||
|
||||
fn finalize_into_dirty(&mut self, out: &mut digest::Output<Self>) {
|
||||
let block = self.groestl.finalize();
|
||||
let n = block.len() - Self::OutputSize::to_usize();
|
||||
out.copy_from_slice(&block[n..])
|
||||
}
|
||||
}
|
||||
|
||||
impl Reset for $state {
|
||||
fn reset(&mut self) {
|
||||
self.groestl.reset()
|
||||
}
|
||||
}
|
||||
|
||||
opaque_debug::implement!($state);
|
||||
digest::impl_write!($state);
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! impl_variable_groestl {
|
||||
($state:ident, $block:ident, $min:expr, $max:expr) => {
|
||||
#[derive(Clone)]
|
||||
pub struct $state {
|
||||
groestl: Groestl<$block>,
|
||||
}
|
||||
|
||||
impl BlockInput for $state {
|
||||
type BlockSize = $block;
|
||||
}
|
||||
|
||||
impl Update for $state {
|
||||
fn update(&mut self, input: impl AsRef<[u8]>) {
|
||||
self.groestl.process(input.as_ref());
|
||||
}
|
||||
}
|
||||
|
||||
impl VariableOutputDirty for $state {
|
||||
fn new(output_size: usize) -> Result<Self, InvalidOutputSize> {
|
||||
if output_size == $min || output_size > $max {
|
||||
return Err(InvalidOutputSize);
|
||||
}
|
||||
Ok($state {
|
||||
groestl: Groestl::new(output_size).unwrap(),
|
||||
})
|
||||
}
|
||||
|
||||
fn output_size(&self) -> usize {
|
||||
self.groestl.output_size
|
||||
}
|
||||
|
||||
fn finalize_variable_dirty(&mut self, f: impl FnOnce(&[u8])) {
|
||||
let block = self.groestl.finalize();
|
||||
let n = block.len() - self.groestl.output_size;
|
||||
f(&block[n..]);
|
||||
}
|
||||
}
|
||||
|
||||
impl Reset for $state {
|
||||
fn reset(&mut self) {
|
||||
self.groestl.reset()
|
||||
}
|
||||
}
|
||||
|
||||
opaque_debug::implement!($state);
|
||||
digest::impl_write!($state);
|
||||
};
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
use core::ops::{Index, IndexMut};
|
||||
use digest::generic_array::{ArrayLength, GenericArray};
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub struct Matrix<R: ArrayLength<GenericArray<u8, C>>, C: ArrayLength<u8>> {
|
||||
pub state: GenericArray<GenericArray<u8, C>, R>,
|
||||
}
|
||||
|
||||
impl<R, C> Default for Matrix<R, C>
|
||||
where
|
||||
R: ArrayLength<GenericArray<u8, C>>,
|
||||
C: ArrayLength<u8>,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Matrix {
|
||||
state: GenericArray::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, C> Index<usize> for Matrix<R, C>
|
||||
where
|
||||
R: ArrayLength<GenericArray<u8, C>>,
|
||||
C: ArrayLength<u8>,
|
||||
{
|
||||
type Output = GenericArray<u8, C>;
|
||||
|
||||
fn index(&self, index: usize) -> &Self::Output {
|
||||
&self.state[index]
|
||||
}
|
||||
}
|
||||
|
||||
impl<R, C> IndexMut<usize> for Matrix<R, C>
|
||||
where
|
||||
R: ArrayLength<GenericArray<u8, C>>,
|
||||
C: ArrayLength<u8>,
|
||||
{
|
||||
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
|
||||
&mut self.state[index]
|
||||
}
|
||||
}
|
||||
|
||||
fn poly_mul(a: u8, b: usize) -> usize {
|
||||
let mut val = match a {
|
||||
2 => b << 1,
|
||||
3 => b ^ poly_mul(2, b),
|
||||
4 => b << 2,
|
||||
5 => b ^ poly_mul(4, b),
|
||||
7 => b ^ poly_mul(2, b) ^ poly_mul(4, b),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
if val >= 512 {
|
||||
val ^= 0x11b << 1;
|
||||
}
|
||||
if val >= 256 {
|
||||
val ^= 0x11b;
|
||||
}
|
||||
val
|
||||
}
|
||||
|
||||
impl<R, C> Matrix<R, C>
|
||||
where
|
||||
R: ArrayLength<GenericArray<u8, C>>,
|
||||
C: ArrayLength<u8>,
|
||||
{
|
||||
pub fn rows(&self) -> usize {
|
||||
R::to_usize()
|
||||
}
|
||||
|
||||
pub fn cols(&self) -> usize {
|
||||
C::to_usize()
|
||||
}
|
||||
|
||||
pub fn mul_array(&self, a: &[[u8; 8]; 8]) -> Self {
|
||||
let mut res = Matrix::default();
|
||||
for i in 0..8 {
|
||||
for j in 0..self.cols() {
|
||||
for k in 0..8 {
|
||||
res[i][j] ^= poly_mul(a[i][k], self[k][j] as usize) as u8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
}
|
||||
@@ -1,293 +0,0 @@
|
||||
use core::ops::Div;
|
||||
|
||||
use crate::consts::{B, C_P, C_Q, SBOX, SHIFTS_P, SHIFTS_P_WIDE, SHIFTS_Q, SHIFTS_Q_WIDE};
|
||||
use crate::matrix::Matrix;
|
||||
use digest::generic_array::typenum::{Quot, U8};
|
||||
use digest::generic_array::{ArrayLength, GenericArray};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct GroestlState<BlockSize>
|
||||
where
|
||||
BlockSize: ArrayLength<u8> + Div<U8>,
|
||||
BlockSize::ArrayType: Copy,
|
||||
Quot<BlockSize, U8>: ArrayLength<u8>,
|
||||
{
|
||||
pub state: GenericArray<u8, BlockSize>,
|
||||
rounds: u8,
|
||||
pub num_blocks: u64,
|
||||
}
|
||||
|
||||
pub fn xor_generic_array<L: ArrayLength<u8>>(
|
||||
a1: &GenericArray<u8, L>,
|
||||
a2: &GenericArray<u8, L>,
|
||||
) -> GenericArray<u8, L> {
|
||||
let mut res = GenericArray::default();
|
||||
for i in 0..L::to_usize() {
|
||||
res[i] = a1[i] ^ a2[i];
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
fn gcd(a: usize, b: usize) -> usize {
|
||||
if b == 0 {
|
||||
return a;
|
||||
}
|
||||
gcd(b, a % b)
|
||||
}
|
||||
|
||||
impl<BlockSize> GroestlState<BlockSize>
|
||||
where
|
||||
BlockSize: ArrayLength<u8> + Div<U8>,
|
||||
BlockSize::ArrayType: Copy,
|
||||
Quot<BlockSize, U8>: ArrayLength<u8>,
|
||||
{
|
||||
pub fn new(output_size: usize) -> Self {
|
||||
let block_bytes = BlockSize::to_usize();
|
||||
let output_bits = output_size * 8;
|
||||
|
||||
let mut state = GenericArray::default();
|
||||
let n = output_bits as u64;
|
||||
state[block_bytes - 8..].copy_from_slice(&n.to_be_bytes());
|
||||
let rounds = match block_bytes {
|
||||
128 => 14,
|
||||
64 => 10,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
GroestlState {
|
||||
state,
|
||||
rounds,
|
||||
num_blocks: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn wide(&self) -> bool {
|
||||
match BlockSize::to_usize() {
|
||||
128 => true,
|
||||
64 => false,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compress(&mut self, input_block: &GenericArray<u8, BlockSize>) {
|
||||
self.state = xor_generic_array(
|
||||
&xor_generic_array(
|
||||
&self.p(&xor_generic_array(&self.state, input_block)),
|
||||
&self.q(input_block),
|
||||
),
|
||||
&self.state,
|
||||
);
|
||||
self.num_blocks += 1;
|
||||
}
|
||||
|
||||
fn block_to_matrix(
|
||||
&self,
|
||||
block: &GenericArray<u8, BlockSize>,
|
||||
) -> Matrix<U8, Quot<BlockSize, U8>> {
|
||||
let mut matrix = Matrix::<U8, Quot<BlockSize, U8>>::default();
|
||||
|
||||
let rows = matrix.rows();
|
||||
for i in 0..matrix.cols() {
|
||||
for j in 0..rows {
|
||||
matrix[j][i] = block[i * rows + j];
|
||||
}
|
||||
}
|
||||
|
||||
matrix
|
||||
}
|
||||
|
||||
fn matrix_to_block(
|
||||
&self,
|
||||
matrix: &Matrix<U8, Quot<BlockSize, U8>>,
|
||||
) -> GenericArray<u8, BlockSize> {
|
||||
let mut block = GenericArray::default();
|
||||
|
||||
let rows = matrix.rows();
|
||||
for i in 0..matrix.cols() {
|
||||
for j in 0..rows {
|
||||
block[i * rows + j] = matrix[j][i];
|
||||
}
|
||||
}
|
||||
|
||||
block
|
||||
}
|
||||
|
||||
pub fn p(&self, block: &GenericArray<u8, BlockSize>) -> GenericArray<u8, BlockSize> {
|
||||
let shifts = if self.wide() { SHIFTS_P_WIDE } else { SHIFTS_P };
|
||||
let mut matrix = self.block_to_matrix(block);
|
||||
for round in 0..self.rounds {
|
||||
self.add_round_constant(&mut matrix, C_P, round);
|
||||
self.sub_bytes(&mut matrix);
|
||||
self.shift_bytes(&mut matrix, shifts);
|
||||
matrix = matrix.mul_array(&B);
|
||||
}
|
||||
self.matrix_to_block(&matrix)
|
||||
}
|
||||
|
||||
fn q(&self, block: &GenericArray<u8, BlockSize>) -> GenericArray<u8, BlockSize> {
|
||||
let shifts = if self.wide() { SHIFTS_Q_WIDE } else { SHIFTS_Q };
|
||||
let mut matrix = self.block_to_matrix(block);
|
||||
for round in 0..self.rounds {
|
||||
self.add_round_constant(&mut matrix, C_Q, round);
|
||||
self.sub_bytes(&mut matrix);
|
||||
self.shift_bytes(&mut matrix, shifts);
|
||||
matrix = matrix.mul_array(&B);
|
||||
}
|
||||
self.matrix_to_block(&matrix)
|
||||
}
|
||||
|
||||
fn add_round_constant(
|
||||
&self,
|
||||
matrix: &mut Matrix<U8, Quot<BlockSize, U8>>,
|
||||
c: [u8; 128],
|
||||
round: u8,
|
||||
) {
|
||||
for i in 0..matrix.rows() {
|
||||
for j in 0..matrix.cols() {
|
||||
matrix[i][j] ^= c[i * 16 + j];
|
||||
|
||||
if (c[0] == 0x00 && i == 0) || (c[0] == 0xff && i == 7) {
|
||||
matrix[i][j] ^= round;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn sub_bytes(&self, matrix: &mut Matrix<U8, Quot<BlockSize, U8>>) {
|
||||
for i in 0..matrix.rows() {
|
||||
for j in 0..matrix.cols() {
|
||||
matrix[i][j] = SBOX[matrix[i][j] as usize];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn shift_bytes(&self, matrix: &mut Matrix<U8, Quot<BlockSize, U8>>, shifts: [u8; 8]) {
|
||||
let cols = matrix.cols();
|
||||
for i in 0..matrix.rows() {
|
||||
let shift = shifts[i] as usize;
|
||||
if shift == 0 {
|
||||
continue;
|
||||
}
|
||||
let d = gcd(shift, cols);
|
||||
for j in 0..d {
|
||||
let mut k = j;
|
||||
let tmp = matrix[i][k];
|
||||
loop {
|
||||
let pos = k.wrapping_add(shift) % cols;
|
||||
if pos == j {
|
||||
break;
|
||||
}
|
||||
matrix[i][k] = matrix[i][pos];
|
||||
k = pos;
|
||||
}
|
||||
matrix[i][k] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{xor_generic_array, GroestlState};
|
||||
use crate::consts::{C_P, C_Q, SHIFTS_P};
|
||||
use digest::generic_array::typenum::U64;
|
||||
use digest::generic_array::GenericArray;
|
||||
|
||||
fn get_padding_block() -> GenericArray<u8, U64> {
|
||||
let padding_block: [u8; 64] = [
|
||||
128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1,
|
||||
];
|
||||
|
||||
GenericArray::clone_from_slice(&padding_block)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_shift_bytes() {
|
||||
let s = GroestlState::<U64>::new(32);
|
||||
let mut block = GenericArray::default();
|
||||
for i in 0..64 {
|
||||
block[i] = i as u8;
|
||||
}
|
||||
let mut matrix = s.block_to_matrix(&block);
|
||||
s.shift_bytes(&mut matrix, SHIFTS_P);
|
||||
let block = s.matrix_to_block(&matrix);
|
||||
let expected = [
|
||||
0, 9, 18, 27, 36, 45, 54, 63, 8, 17, 26, 35, 44, 53, 62, 7, 16, 25, 34, 43, 52, 61, 6,
|
||||
15, 24, 33, 42, 51, 60, 5, 14, 23, 32, 41, 50, 59, 4, 13, 22, 31, 40, 49, 58, 3, 12,
|
||||
21, 30, 39, 48, 57, 2, 11, 20, 29, 38, 47, 56, 1, 10, 19, 28, 37, 46, 55,
|
||||
];
|
||||
assert_eq!(&block[..], &expected[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_p() {
|
||||
let padding_chunk = get_padding_block();
|
||||
let s = GroestlState::<U64>::new(32);
|
||||
let block = xor_generic_array(&s.state, GenericArray::from_slice(&padding_chunk));
|
||||
|
||||
let p_block = s.p(&block);
|
||||
let expected = [
|
||||
247, 236, 141, 217, 73, 225, 112, 216, 1, 155, 85, 192, 152, 168, 174, 72, 112, 253,
|
||||
159, 53, 7, 6, 8, 115, 58, 242, 7, 115, 148, 150, 157, 25, 18, 220, 11, 5, 178, 10,
|
||||
110, 94, 44, 56, 110, 67, 107, 234, 102, 163, 243, 212, 49, 25, 46, 17, 170, 84, 5, 76,
|
||||
239, 51, 4, 107, 94, 20,
|
||||
];
|
||||
assert_eq!(&p_block[..], &expected[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_q() {
|
||||
let padding_chunk = get_padding_block();
|
||||
let s = GroestlState::<U64>::new(32);
|
||||
let q_block = s.q(GenericArray::from_slice(&padding_chunk));
|
||||
let expected = [
|
||||
189, 183, 105, 133, 208, 106, 34, 36, 82, 37, 180, 250, 229, 59, 230, 223, 215, 245,
|
||||
53, 117, 167, 139, 150, 186, 210, 17, 220, 57, 116, 134, 209, 51, 124, 108, 84, 91, 79,
|
||||
103, 148, 27, 135, 183, 144, 226, 59, 242, 87, 81, 109, 211, 84, 185, 192, 172, 88,
|
||||
210, 8, 121, 31, 242, 158, 227, 207, 13,
|
||||
];
|
||||
assert_eq!(&q_block[..], &expected[..]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_block_to_matrix() {
|
||||
let s = GroestlState::<U64>::new(32);
|
||||
let mut block1 = GenericArray::default();
|
||||
for i in 0..block1.len() {
|
||||
block1[i] = i as u8;
|
||||
}
|
||||
let m = s.block_to_matrix(&block1);
|
||||
let block2 = s.matrix_to_block(&m);
|
||||
assert_eq!(block1, block2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_add_round_constant() {
|
||||
let padding_chunk = get_padding_block();
|
||||
let s = GroestlState::<U64>::new(32);
|
||||
|
||||
let mut m = s.block_to_matrix(GenericArray::from_slice(&padding_chunk));
|
||||
s.add_round_constant(&mut m, C_P, 0);
|
||||
let b = s.matrix_to_block(&m);
|
||||
let expected = [
|
||||
128, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 0, 48, 0, 0,
|
||||
0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 80, 0, 0, 0, 0, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0,
|
||||
0, 112, 0, 0, 0, 0, 0, 0, 1,
|
||||
];
|
||||
assert_eq!(&b[..], &expected[..]);
|
||||
|
||||
let mut m = s.block_to_matrix(GenericArray::from_slice(&padding_chunk));
|
||||
s.add_round_constant(&mut m, C_Q, 0);
|
||||
let b = s.matrix_to_block(&m);
|
||||
let expected = [
|
||||
0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xef, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xcf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xbf, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xaf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x8e,
|
||||
];
|
||||
assert_eq!(&b[..], &expected[..]);
|
||||
}
|
||||
}
|
||||
11
groestl/src/table.rs
Normal file
11
groestl/src/table.rs
Normal file
File diff suppressed because one or more lines are too long
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,28 +0,0 @@
|
||||
#![no_std]
|
||||
|
||||
use digest::{dev::digest_test, new_test};
|
||||
|
||||
new_test!(
|
||||
groestl_224_main,
|
||||
"groestl224",
|
||||
groestl::Groestl224,
|
||||
digest_test
|
||||
);
|
||||
new_test!(
|
||||
groestl_256_main,
|
||||
"groestl256",
|
||||
groestl::Groestl256,
|
||||
digest_test
|
||||
);
|
||||
new_test!(
|
||||
groestl_384_main,
|
||||
"groestl384",
|
||||
groestl::Groestl384,
|
||||
digest_test
|
||||
);
|
||||
new_test!(
|
||||
groestl_512_main,
|
||||
"groestl512",
|
||||
groestl::Groestl512,
|
||||
digest_test
|
||||
);
|
||||
57
groestl/tests/mod.rs
Executable file
57
groestl/tests/mod.rs
Executable file
@@ -0,0 +1,57 @@
|
||||
use digest::dev::{feed_rand_16mib, fixed_reset_test};
|
||||
use digest::new_test;
|
||||
use groestl::{Digest, Groestl224, Groestl256, Groestl384, Groestl512};
|
||||
use hex_literal::hex;
|
||||
|
||||
new_test!(groestl_224_main, "groestl224", Groestl224, fixed_reset_test);
|
||||
new_test!(groestl_256_main, "groestl256", Groestl256, fixed_reset_test);
|
||||
new_test!(groestl_384_main, "groestl384", Groestl384, fixed_reset_test);
|
||||
new_test!(groestl_512_main, "groestl512", Groestl512, fixed_reset_test);
|
||||
|
||||
#[test]
|
||||
fn groestl224_rand() {
|
||||
let mut h = Groestl224::new();
|
||||
feed_rand_16mib(&mut h);
|
||||
assert_eq!(
|
||||
h.finalize()[..],
|
||||
hex!("2000744c2f85a7fb4733e97da8db00069dd6defa9186dac3461dfeb8")[..]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn groestl256_rand() {
|
||||
let mut h = Groestl256::new();
|
||||
feed_rand_16mib(&mut h);
|
||||
assert_eq!(
|
||||
h.finalize()[..],
|
||||
hex!("aac71c789678f627a6474605322ae98d1647e47f405d00b1461b90ee5f0cfbc4")[..]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[rustfmt::skip]
|
||||
fn groestl384_rand() {
|
||||
let mut h = Groestl384::new();
|
||||
feed_rand_16mib(&mut h);
|
||||
assert_eq!(
|
||||
h.finalize()[..],
|
||||
hex!("
|
||||
dab78eea895a6dde0c53dc02fc79c7986f5d6811618ca6e5922f01e8aca9bfeb
|
||||
20ed5eda4130bf0ab474ac0b6f0290f8
|
||||
")[..]
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[rustfmt::skip]
|
||||
fn groestl512_rand() {
|
||||
let mut h = Groestl512::new();
|
||||
feed_rand_16mib(&mut h);
|
||||
assert_eq!(
|
||||
h.finalize()[..],
|
||||
hex!("
|
||||
7e4d8257c217c7ae59331126e0f984f145e9789862de7c099675ac29e46424ef
|
||||
e93543974fa7113190d492f607f629a03db35ec5551abcb2785ae145fd3c543f
|
||||
")[..],
|
||||
);
|
||||
}
|
||||
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## 0.2.0 (2021-12-07)
|
||||
### Changed
|
||||
- Update to `digest` v0.10 ([#217])
|
||||
|
||||
[#217]: https://github.com/RustCrypto/hashes/pull/217
|
||||
|
||||
## 0.1.0 (2020-06-09)
|
||||
### Changed
|
||||
- Update to `digest` v0.9 release; MSRV 1.41+ ([#155])
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "k12"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0" # Also update html_root_url in lib.rs when bumping this
|
||||
description = "Experimental pure Rust implementation of the KangarooTwelve hash function"
|
||||
authors = ["Diggory Hardy <github1@dhardy.name>"]
|
||||
license = "Apache-2.0 OR MIT"
|
||||
@@ -12,10 +12,10 @@ keywords = ["crypto", "hash", "digest"]
|
||||
categories = ["cryptography", "no-std"]
|
||||
|
||||
[dependencies]
|
||||
digest = { version = "0.9", features = ["alloc"] }
|
||||
digest = { version = "0.10", features = ["alloc"] }
|
||||
|
||||
[dev-dependencies]
|
||||
digest = { version = "0.9", features = ["alloc", "dev"] }
|
||||
digest = { version = "0.10", features = ["alloc", "dev"] }
|
||||
hex-literal = "0.2"
|
||||
|
||||
[features]
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
#![no_std]
|
||||
#![feature(test)]
|
||||
|
||||
extern crate test;
|
||||
|
||||
use digest::Update;
|
||||
use test::Bencher;
|
||||
|
||||
digest::bench!(bench1_10, k12::KangarooTwelve, 10);
|
||||
digest::bench!(bench2_100, k12::KangarooTwelve, 100);
|
||||
digest::bench!(bench3_1000, k12::KangarooTwelve, 1000);
|
||||
digest::bench!(bench4_10000, k12::KangarooTwelve, 10000);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user