mirror of
https://github.com/rosenpass/rosenpass.git
synced 2026-02-27 22:13:12 -08:00
Compare commits
59 Commits
dev/david/
...
dev/karo/k
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
240a1f923d | ||
|
|
a538dee0c3 | ||
|
|
08ea045325 | ||
|
|
6b61823255 | ||
|
|
96ac01ff2e | ||
|
|
811c1746c1 | ||
|
|
91707cc430 | ||
|
|
73df0ceca7 | ||
|
|
9cc7a58ee7 | ||
|
|
5106ffd549 | ||
|
|
7fc6fd2f52 | ||
|
|
77b50b70b1 | ||
|
|
cf061bd0f5 | ||
|
|
196d459a2b | ||
|
|
5097d9fce1 | ||
|
|
cdf6e8369f | ||
|
|
d5eb996423 | ||
|
|
6c49f38e29 | ||
|
|
e021b9f11d | ||
|
|
49f384c380 | ||
|
|
7e590dd30e | ||
|
|
d98815fa7f | ||
|
|
dd105a4491 | ||
|
|
64ff326e14 | ||
|
|
37e71a4051 | ||
|
|
e90bc1b636 | ||
|
|
bbd7e7bb72 | ||
|
|
3d724f04d4 | ||
|
|
db9d0b642b | ||
|
|
50501f37fd | ||
|
|
39f99fbfea | ||
|
|
3ea1a824cc | ||
|
|
d496490916 | ||
|
|
740489544d | ||
|
|
22b980a61f | ||
|
|
a45812b2cd | ||
|
|
1025de2c64 | ||
|
|
b8e9519e26 | ||
|
|
c3def9744f | ||
|
|
e3d3584adb | ||
|
|
a1982e0245 | ||
|
|
4896cd6130 | ||
|
|
9aab9d2d2a | ||
|
|
108ca440fe | ||
|
|
03e408b7c2 | ||
|
|
67f387a190 | ||
|
|
745c3962bb | ||
|
|
f6971aa5ad | ||
|
|
b46cd636d2 | ||
|
|
f22f4aad7d | ||
|
|
a83589d76a | ||
|
|
508d46f2bc | ||
|
|
3fc3083a54 | ||
|
|
faa45a8540 | ||
|
|
77632d0725 | ||
|
|
7218b0a3f4 | ||
|
|
4266cbfb72 | ||
|
|
070d299329 | ||
|
|
15699710a0 |
@@ -32,9 +32,9 @@ let systems_map = {
|
||||
# aarch64-darwin
|
||||
# aarch64-linux
|
||||
|
||||
i686-linux: ubuntu-latest,
|
||||
i686-linux: ubicloud-standard-2-ubuntu-2204,
|
||||
x86_64-darwin: macos-13,
|
||||
x86_64-linux: ubuntu-latest
|
||||
x86_64-linux: ubicloud-standard-2-ubuntu-2204
|
||||
}
|
||||
|
||||
let targets = (get-attr-names ".#packages"
|
||||
@@ -61,14 +61,13 @@ mut release_workflow = {
|
||||
|
||||
let runner_setup = [
|
||||
{
|
||||
uses: "actions/checkout@v3"
|
||||
uses: "actions/checkout@v4"
|
||||
}
|
||||
{
|
||||
uses: "cachix/install-nix-action@v22",
|
||||
with: { nix_path: "nixpkgs=channel:nixos-unstable" }
|
||||
uses: "cachix/install-nix-action@v30",
|
||||
}
|
||||
{
|
||||
uses: "cachix/cachix-action@v12",
|
||||
uses: "cachix/cachix-action@v15",
|
||||
with: {
|
||||
name: rosenpass,
|
||||
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
@@ -154,7 +153,7 @@ for system in ($targets | columns) {
|
||||
}
|
||||
{
|
||||
name: Release,
|
||||
uses: "softprops/action-gh-release@v1",
|
||||
uses: "softprops/action-gh-release@v2",
|
||||
with: {
|
||||
draft: "${{ contains(github.ref_name, 'rc') }}",
|
||||
prerelease: "${{ contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') }}",
|
||||
@@ -182,7 +181,7 @@ $cachix_workflow.jobs = ($cachix_workflow.jobs | insert $"($system)---whitepaper
|
||||
}
|
||||
{
|
||||
name: "Deploy PDF artifacts",
|
||||
uses: "peaceiris/actions-gh-pages@v3",
|
||||
uses: "peaceiris/actions-gh-pages@v4",
|
||||
with: {
|
||||
github_token: "${{ secrets.GITHUB_TOKEN }}",
|
||||
publish_dir: result/,
|
||||
|
||||
103
.github/workflows/bench-primitives.yml
vendored
Normal file
103
.github/workflows/bench-primitives.yml
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
name: rosenpass-ciphers - primitives - benchmark
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
prim-benchmark:
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
system: ["x86_64-linux", "i686-linux"]
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# Install nix
|
||||
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v27 # A popular action for installing Nix
|
||||
with:
|
||||
extra_nix_config: |
|
||||
experimental-features = nix-command flakes
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Set up environment
|
||||
|
||||
- name: 🛠️ Prepare Benchmark Path
|
||||
env:
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
BRANCH_NAME: ${{ github.ref_name }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
run: |
|
||||
case "$EVENT_NAME" in
|
||||
"push")
|
||||
echo "BENCH_PATH=branch/$BRANCH_NAME" >> $GITHUB_ENV
|
||||
;;
|
||||
"pull_request")
|
||||
echo "BENCH_PATH=pull/$PR_NUMBER" >> $GITHUB_ENV
|
||||
;;
|
||||
*)
|
||||
echo "don't know benchmark path for event of type $EVENT_NAME, aborting"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
# Benchmarks ...
|
||||
|
||||
- name: 🏃🏻♀️ Benchmarks (using Nix as shell)
|
||||
working-directory: ciphers
|
||||
run: nix develop ".#devShells.${{ matrix.system }}.benchmarks" --command cargo bench -F bench --bench primitives --verbose -- --output-format bencher | tee ../bench-primitives.txt
|
||||
|
||||
- name: Extract benchmarks
|
||||
uses: cryspen/benchmark-data-extract-transform@v2
|
||||
with:
|
||||
name: rosenpass-ciphers primitives benchmarks
|
||||
tool: "cargo"
|
||||
os: ${{ matrix.system }}
|
||||
output-file-path: bench-primitives.txt
|
||||
data-out-path: bench-primitives-os.json
|
||||
|
||||
- name: Fix up 'os' label in benchmark data
|
||||
run: jq 'map(with_entries(.key |= if . == "os" then "operating system" else . end))' <bench-primitives-os.json >bench-primitives.json
|
||||
|
||||
- name: Upload benchmarks
|
||||
uses: cryspen/benchmark-upload-and-plot-action@v3
|
||||
with:
|
||||
name: Crypto Primitives Benchmarks
|
||||
group-by: "operating system,primitive,algorithm"
|
||||
schema: "operating system,primitive,algorithm,implementation,operation,length"
|
||||
input-data-path: bench-primitives.json
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# NOTE: pushes to current repository
|
||||
gh-repository: github.com/${{ github.repository }}
|
||||
auto-push: true
|
||||
fail-on-alert: true
|
||||
base-path: benchmarks/
|
||||
|
||||
ciphers-primitives-bench-status:
|
||||
if: ${{ always() }}
|
||||
needs: [prim-benchmark]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Successful
|
||||
if: ${{ !(contains(needs.*.result, 'failure')) }}
|
||||
run: exit 0
|
||||
- name: Failing
|
||||
if: ${{ (contains(needs.*.result, 'failure')) }}
|
||||
run: exit 1
|
||||
90
.github/workflows/bench-protocol.yml
vendored
Normal file
90
.github/workflows/bench-protocol.yml
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
name: rosenpass - protocol - benchmark
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
proto-benchmark:
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
system: ["x86_64-linux", "i686-linux"]
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# Install nix
|
||||
|
||||
- name: Install Nix
|
||||
uses: cachix/install-nix-action@v27 # A popular action for installing Nix
|
||||
with:
|
||||
extra_nix_config: |
|
||||
experimental-features = nix-command flakes
|
||||
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Set up environment
|
||||
|
||||
- name: 🛠️ Prepare Benchmark Path
|
||||
env:
|
||||
EVENT_NAME: ${{ github.event_name }}
|
||||
BRANCH_NAME: ${{ github.ref_name }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
run: |
|
||||
case "$EVENT_NAME" in
|
||||
"push")
|
||||
echo "BENCH_PATH=branch/$BRANCH_NAME" >> $GITHUB_ENV
|
||||
;;
|
||||
"pull_request")
|
||||
echo "BENCH_PATH=pull/$PR_NUMBER" >> $GITHUB_ENV
|
||||
;;
|
||||
*)
|
||||
echo "don't know benchmark path for event of type $EVENT_NAME, aborting"
|
||||
exit 1
|
||||
esac
|
||||
|
||||
# Benchmarks ...
|
||||
|
||||
- name: 🏃🏻♀️ Benchmarks
|
||||
run: nix develop ".#devShells.${{ matrix.system }}.benchmarks" --command cargo bench -p rosenpass --bench trace_handshake -F trace_bench --verbose >bench-protocol.json
|
||||
|
||||
- name: Upload benchmarks
|
||||
uses: cryspen/benchmark-upload-and-plot-action@v3
|
||||
with:
|
||||
name: Protocol Benchmarks
|
||||
group-by: "operating system,architecture,protocol version,run time"
|
||||
schema: "operating system,architecture,protocol version,run time,name"
|
||||
input-data-path: bench-protocol.json
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
# NOTE: pushes to current repository
|
||||
gh-repository: github.com/${{ github.repository }}
|
||||
auto-push: true
|
||||
fail-on-alert: true
|
||||
base-path: benchmarks/
|
||||
|
||||
ciphers-protocol-bench-status:
|
||||
if: ${{ always() }}
|
||||
needs: [proto-benchmark]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Successful
|
||||
if: ${{ !(contains(needs.*.result, 'failure')) }}
|
||||
run: exit 0
|
||||
- name: Failing
|
||||
if: ${{ (contains(needs.*.result, 'failure')) }}
|
||||
run: exit 1
|
||||
@@ -1,58 +0,0 @@
|
||||
name: Dependabot Vet Exemptions
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- "Cargo.toml"
|
||||
- "Cargo.lock"
|
||||
|
||||
jobs:
|
||||
dependabot-cargo-crev-exceptions:
|
||||
if: github.actor == 'dependabot[bot]' # Run only for Dependabot PRs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.head_ref }}
|
||||
token: ${{ secrets.GITHUB_TOKEN }} # Ensure push access
|
||||
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
key: cargo-vet-cache
|
||||
|
||||
- name: Install stable toolchain # Since we are running/compiling cargo-vet, we should rely on the stable toolchain.
|
||||
run: |
|
||||
rustup toolchain install stable
|
||||
rustup default stable
|
||||
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ runner.tool_cache }}/cargo-vet
|
||||
key: cargo-vet-bin
|
||||
|
||||
- name: Add the tool cache directory to the search path
|
||||
run: echo "${{ runner.tool_cache }}/cargo-vet/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Ensure that the tool cache is populated with the cargo-vet binary
|
||||
run: cargo install --root ${{ runner.tool_cache }}/cargo-vet cargo-vet
|
||||
|
||||
- name: Regenerate vet exemptions
|
||||
run: cargo vet regenerate exemptions
|
||||
|
||||
- name: Check for changes
|
||||
run: git diff --exit-code || echo "Changes detected, committing..."
|
||||
|
||||
- name: Commit and push changes
|
||||
if: success()
|
||||
run: |
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "github-actions@github.com"
|
||||
git add supply-chain./*
|
||||
git commit -m "Regenerate cargo vet exemptions"
|
||||
git push origin ${{ github.head_ref }}
|
||||
19
.github/workflows/manual-mac-pr.yaml
vendored
Normal file
19
.github/workflows/manual-mac-pr.yaml
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
name: PR Validation on Mac
|
||||
on:
|
||||
workflow_dispatch:
|
||||
permissions:
|
||||
checks: write
|
||||
contents: write
|
||||
concurrency:
|
||||
group: manual-mac-${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
jobs:
|
||||
qc:
|
||||
uses: ./.github/workflows/qc-mac.yaml
|
||||
permissions:
|
||||
checks: write
|
||||
contents: read
|
||||
nix:
|
||||
uses: ./.github/workflows/nix-mac.yaml
|
||||
permissions:
|
||||
contents: write
|
||||
1
.github/workflows/nix-mac.yaml
vendored
1
.github/workflows/nix-mac.yaml
vendored
@@ -5,6 +5,7 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_call:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
|
||||
5
.github/workflows/qc-mac.yaml
vendored
5
.github/workflows/qc-mac.yaml
vendored
@@ -1,7 +1,8 @@
|
||||
name: QC
|
||||
name: QC Mac
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_call:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@@ -12,7 +13,7 @@ permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
cargo-test:
|
||||
cargo-test-mac:
|
||||
runs-on: warp-macos-13-arm64-6x
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
46
.github/workflows/qc.yaml
vendored
46
.github/workflows/qc.yaml
vendored
@@ -30,11 +30,27 @@ jobs:
|
||||
uses: ludeeus/action-shellcheck@master
|
||||
|
||||
rustfmt:
|
||||
name: Rust Format
|
||||
name: Rust code formatting
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Run Rust Formatting Script
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
- name: Install nightly toolchain
|
||||
run: |
|
||||
rustup toolchain install nightly
|
||||
rustup override set nightly
|
||||
- run: rustup component add rustfmt
|
||||
- name: Run Cargo Fmt
|
||||
run: cargo fmt --all --check
|
||||
- name: Run Rust Markdown code block Formatting Script
|
||||
run: bash format_rust_code.sh --mode check
|
||||
|
||||
cargo-bench:
|
||||
@@ -112,12 +128,7 @@ jobs:
|
||||
- run: RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --document-private-items
|
||||
|
||||
cargo-test:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubicloud-standard-2-ubuntu-2204, warp-macos-13-arm64-6x]
|
||||
# - ubuntu is x86-64
|
||||
# - macos-13 is also x86-64 architecture
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v4
|
||||
@@ -173,7 +184,7 @@ jobs:
|
||||
- name: Install nightly toolchain
|
||||
run: |
|
||||
rustup toolchain install nightly
|
||||
rustup default nightly
|
||||
rustup override set nightly
|
||||
- name: Install cargo-fuzz
|
||||
run: cargo install cargo-fuzz
|
||||
- name: Run fuzzing
|
||||
@@ -192,9 +203,23 @@ jobs:
|
||||
|
||||
codecov:
|
||||
runs-on: ubicloud-standard-2-ubuntu-2204
|
||||
env:
|
||||
RUSTUP_TOOLCHAIN: nightly
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: rustup default nightly
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
~/.cargo/bin/
|
||||
~/.cargo/registry/index/
|
||||
~/.cargo/registry/cache/
|
||||
~/.cargo/git/db/
|
||||
target/
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
|
||||
- name: Install nightly toolchain
|
||||
run: |
|
||||
rustup toolchain install nightly
|
||||
rustup override set nightly
|
||||
- run: rustup component add llvm-tools-preview
|
||||
- run: |
|
||||
cargo install cargo-llvm-cov || true
|
||||
@@ -208,5 +233,4 @@ jobs:
|
||||
with:
|
||||
files: ./target/grcov/lcov
|
||||
verbose: true
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
28
.github/workflows/supply-chain.yml
vendored
28
.github/workflows/supply-chain.yml
vendored
@@ -28,6 +28,10 @@ jobs:
|
||||
~/.cargo/registry/cache/
|
||||
~/.cache/cargo-supply-chain/
|
||||
key: cargo-supply-chain-cache
|
||||
- name: Install stable toolchain # Cargo-supply-chain is incompatible with older versions
|
||||
run: |
|
||||
rustup toolchain install stable
|
||||
rustup default stable
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ runner.tool_cache }}/cargo-supply-chain
|
||||
@@ -35,7 +39,7 @@ jobs:
|
||||
- name: Add the tool cache directory to the search path
|
||||
run: echo "${{ runner.tool_cache }}/cargo-supply-chain/bin" >> $GITHUB_PATH
|
||||
- name: Ensure that the tool cache is populated with the cargo-supply-chain binary
|
||||
run: cargo install --root ${{ runner.tool_cache }}/cargo-supply-chain cargo-supply-chain
|
||||
run: cargo +stable install --root ${{ runner.tool_cache }}/cargo-supply-chain cargo-supply-chain
|
||||
- name: Update data for cargo-supply-chain
|
||||
run: cargo supply-chain update
|
||||
- name: Generate cargo-supply-chain report about publishers
|
||||
@@ -46,6 +50,8 @@ jobs:
|
||||
cargo-vet:
|
||||
name: Vet Dependencies
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/cache@v4
|
||||
@@ -66,6 +72,24 @@ jobs:
|
||||
- name: Add the tool cache directory to the search path
|
||||
run: echo "${{ runner.tool_cache }}/cargo-vet/bin" >> $GITHUB_PATH
|
||||
- name: Ensure that the tool cache is populated with the cargo-vet binary
|
||||
run: cargo install --root ${{ runner.tool_cache }}/cargo-vet cargo-vet
|
||||
run: cargo +stable install --root ${{ runner.tool_cache }}/cargo-vet cargo-vet
|
||||
- name: Regenerate vet exemptions for dependabot PRs
|
||||
if: github.actor == 'dependabot[bot]' # Run only for Dependabot PRs
|
||||
run: cargo vet regenerate exemptions
|
||||
- name: Check for changes in case of dependabot PR
|
||||
if: github.actor == 'dependabot[bot]' # Run only for Dependabot PRs
|
||||
run: git diff --exit-code || echo "Changes detected, committing..."
|
||||
- name: Commit and push changes for dependabot PRs
|
||||
if: success() && github.actor == 'dependabot[bot]'
|
||||
run: |
|
||||
git fetch origin ${{ github.head_ref }}
|
||||
git switch ${{ github.head_ref }}
|
||||
git config --global user.name "github-actions[bot]"
|
||||
git config --global user.email "github-actions@github.com"
|
||||
git add supply-chain/*
|
||||
git commit -m "Regenerate cargo vet exemptions"
|
||||
git push origin ${{ github.head_ref }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Invoke cargo-vet
|
||||
run: cargo vet --locked
|
||||
|
||||
32
Cargo.lock
generated
32
Cargo.lock
generated
@@ -500,9 +500,9 @@ checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b"
|
||||
|
||||
[[package]]
|
||||
name = "crossbeam-channel"
|
||||
version = "0.5.14"
|
||||
version = "0.5.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471"
|
||||
checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
@@ -1269,7 +1269,7 @@ version = "0.0.3-pre"
|
||||
source = "git+https://github.com/cryspen/libcrux.git?rev=10ce653e9476#10ce653e94761352b657b6cecdcc0c85675813df"
|
||||
dependencies = [
|
||||
"libcrux-hacl-rs",
|
||||
"libcrux-macros",
|
||||
"libcrux-macros 0.0.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1279,7 +1279,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78d522fb626847390ea4b776c7eca179ecec363c6c4730b61b0c0feb797b8d92"
|
||||
dependencies = [
|
||||
"libcrux-hacl-rs",
|
||||
"libcrux-macros",
|
||||
"libcrux-macros 0.0.2",
|
||||
"libcrux-poly1305",
|
||||
]
|
||||
|
||||
@@ -1299,7 +1299,7 @@ version = "0.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8bba0885296a72555a5d77056c39cc9b04edd9ab1afa3025ef3dbd96220705c"
|
||||
dependencies = [
|
||||
"libcrux-macros",
|
||||
"libcrux-macros 0.0.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1321,6 +1321,15 @@ dependencies = [
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-macros"
|
||||
version = "0.0.3"
|
||||
source = "git+https://github.com/cryspen/libcrux.git?rev=0ab6d2dd9c1f#0ab6d2dd9c1f39c82b1125a566d6befb38feea28"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn 2.0.98",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-ml-kem"
|
||||
version = "0.0.2-beta.3"
|
||||
@@ -1350,7 +1359,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80143d78ae14ab51ceb2c8a9514fb60af6645d42a9c951bc511792c19c974fca"
|
||||
dependencies = [
|
||||
"libcrux-hacl-rs",
|
||||
"libcrux-macros",
|
||||
"libcrux-macros 0.0.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1364,6 +1373,14 @@ dependencies = [
|
||||
"libcrux-platform",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libcrux-test-utils"
|
||||
version = "0.0.2"
|
||||
source = "git+https://github.com/cryspen/libcrux.git?rev=0ab6d2dd9c1f#0ab6d2dd9c1f39c82b1125a566d6befb38feea28"
|
||||
dependencies = [
|
||||
"libcrux-macros 0.0.3",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libfuzzer-sys"
|
||||
version = "0.4.9"
|
||||
@@ -2024,6 +2041,7 @@ dependencies = [
|
||||
"hex",
|
||||
"hex-literal",
|
||||
"home",
|
||||
"libcrux-test-utils",
|
||||
"log",
|
||||
"memoffset 0.9.1",
|
||||
"mio",
|
||||
@@ -2070,6 +2088,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"blake2",
|
||||
"chacha20poly1305",
|
||||
"criterion",
|
||||
"libcrux",
|
||||
"libcrux-blake2",
|
||||
"libcrux-chacha20poly1305",
|
||||
@@ -2153,6 +2172,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64ct",
|
||||
"libcrux-test-utils",
|
||||
"mio",
|
||||
"rustix",
|
||||
"static_assertions",
|
||||
|
||||
37
Cargo.toml
37
Cargo.toml
@@ -2,17 +2,17 @@
|
||||
resolver = "2"
|
||||
|
||||
members = [
|
||||
"rosenpass",
|
||||
"cipher-traits",
|
||||
"ciphers",
|
||||
"util",
|
||||
"constant-time",
|
||||
"oqs",
|
||||
"to",
|
||||
"fuzz",
|
||||
"secret-memory",
|
||||
"rp",
|
||||
"wireguard-broker",
|
||||
"rosenpass",
|
||||
"cipher-traits",
|
||||
"ciphers",
|
||||
"util",
|
||||
"constant-time",
|
||||
"oqs",
|
||||
"to",
|
||||
"fuzz",
|
||||
"secret-memory",
|
||||
"rp",
|
||||
"wireguard-broker",
|
||||
]
|
||||
|
||||
default-members = ["rosenpass", "rp", "wireguard-broker"]
|
||||
@@ -42,7 +42,7 @@ toml = "0.7.8"
|
||||
static_assertions = "1.1.0"
|
||||
allocator-api2 = "0.2.14"
|
||||
memsec = { git = "https://github.com/rosenpass/memsec.git", rev = "aceb9baee8aec6844125bd6612f92e9a281373df", features = [
|
||||
"alloc_ext",
|
||||
"alloc_ext",
|
||||
] }
|
||||
rand = "0.8.5"
|
||||
typenum = "1.17.0"
|
||||
@@ -55,14 +55,14 @@ arbitrary = { version = "1.4.1", features = ["derive"] }
|
||||
anyhow = { version = "1.0.95", features = ["backtrace", "std"] }
|
||||
mio = { version = "1.0.3", features = ["net", "os-poll"] }
|
||||
oqs-sys = { version = "0.9.1", default-features = false, features = [
|
||||
'classic_mceliece',
|
||||
'kyber',
|
||||
'classic_mceliece',
|
||||
'kyber',
|
||||
] }
|
||||
blake2 = "0.10.6"
|
||||
sha3 = "0.10.8"
|
||||
chacha20poly1305 = { version = "0.10.1", default-features = false, features = [
|
||||
"std",
|
||||
"heapless",
|
||||
"std",
|
||||
"heapless",
|
||||
] }
|
||||
zerocopy = { version = "0.7.35", features = ["derive"] }
|
||||
home = "=0.5.9" # 5.11 requires rustc 1.81
|
||||
@@ -72,13 +72,15 @@ postcard = { version = "1.1.1", features = ["alloc"] }
|
||||
libcrux = { version = "0.0.2-pre.2" }
|
||||
libcrux-chacha20poly1305 = { version = "0.0.2-beta.3" }
|
||||
libcrux-ml-kem = { version = "0.0.2-beta.3" }
|
||||
libcrux-blake2 = { git = "https://github.com/cryspen/libcrux.git", rev = "10ce653e9476"}
|
||||
libcrux-blake2 = { git = "https://github.com/cryspen/libcrux.git", rev = "10ce653e9476" }
|
||||
libcrux-test-utils = { git = "https://github.com/cryspen/libcrux.git", rev = "0ab6d2dd9c1f" }
|
||||
hex-literal = { version = "0.4.1" }
|
||||
hex = { version = "0.4.3" }
|
||||
heck = { version = "0.5.0" }
|
||||
libc = { version = "0.2" }
|
||||
uds = { git = "https://github.com/rosenpass/uds" }
|
||||
signal-hook = "0.3.17"
|
||||
lazy_static = "1.5"
|
||||
|
||||
#Dev dependencies
|
||||
serial_test = "3.2.0"
|
||||
@@ -90,7 +92,6 @@ criterion = "0.5.1"
|
||||
allocator-api2-tests = "0.2.15"
|
||||
procspawn = { version = "1.0.1", features = ["test-support"] }
|
||||
|
||||
|
||||
#Broker dependencies (might need cleanup or changes)
|
||||
wireguard-uapi = { version = "3.0.0", features = ["xplatform"] }
|
||||
command-fds = "0.2.3"
|
||||
|
||||
@@ -8,6 +8,7 @@ description = "Rosenpass internal traits for cryptographic primitives"
|
||||
homepage = "https://rosenpass.eu/"
|
||||
repository = "https://github.com/rosenpass/rosenpass"
|
||||
readme = "readme.md"
|
||||
rust-version = "1.77.0"
|
||||
|
||||
[dependencies]
|
||||
thiserror = { workspace = true }
|
||||
|
||||
@@ -8,21 +8,42 @@ description = "Rosenpass internal ciphers and other cryptographic primitives use
|
||||
homepage = "https://rosenpass.eu/"
|
||||
repository = "https://github.com/rosenpass/rosenpass"
|
||||
readme = "readme.md"
|
||||
rust-version = "1.77.0"
|
||||
|
||||
[features]
|
||||
experiment_libcrux_all = [
|
||||
"experiment_libcrux_blake2",
|
||||
"experiment_libcrux_chachapoly",
|
||||
"experiment_libcrux_chachapoly_test",
|
||||
"experiment_libcrux_kyber",
|
||||
]
|
||||
experiment_libcrux_blake2 = ["dep:libcrux-blake2", "dep:thiserror"]
|
||||
experiment_libcrux_chachapoly = ["dep:libcrux-chacha20poly1305"]
|
||||
# whether the types should be defined
|
||||
experiment_libcrux_define_blake2 = ["dep:libcrux-blake2", "dep:thiserror"]
|
||||
experiment_libcrux_define_kyber = ["dep:libcrux-ml-kem", "dep:rand"]
|
||||
experiment_libcrux_define_chachapoly = ["dep:libcrux-chacha20poly1305"]
|
||||
|
||||
# whether the types should be used by default
|
||||
experiment_libcrux_blake2 = ["experiment_libcrux_define_blake2"]
|
||||
experiment_libcrux_kyber = ["experiment_libcrux_define_kyber"]
|
||||
experiment_libcrux_chachapoly = ["experiment_libcrux_define_chachapoly"]
|
||||
experiment_libcrux_chachapoly_test = [
|
||||
"experiment_libcrux_chachapoly",
|
||||
"dep:libcrux",
|
||||
"experiment_libcrux_define_chachapoly",
|
||||
"dep:libcrux",
|
||||
]
|
||||
experiment_libcrux_kyber = ["dep:libcrux-ml-kem", "dep:rand"]
|
||||
|
||||
# shorthands
|
||||
experiment_libcrux_define_all = [
|
||||
"experiment_libcrux_define_blake2",
|
||||
"experiment_libcrux_define_chachapoly",
|
||||
"experiment_libcrux_define_kyber",
|
||||
]
|
||||
experiment_libcrux_all = [
|
||||
"experiment_libcrux_blake2",
|
||||
"experiment_libcrux_chachapoly",
|
||||
"experiment_libcrux_chachapoly_test",
|
||||
"experiment_libcrux_kyber",
|
||||
]
|
||||
|
||||
bench = ["experiment_libcrux_define_all"]
|
||||
|
||||
[[bench]]
|
||||
name = "primitives"
|
||||
harness = false
|
||||
required-features = ["bench"]
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
@@ -49,3 +70,4 @@ libcrux = { workspace = true, optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = { workspace = true }
|
||||
criterion = { workspace = true }
|
||||
|
||||
378
ciphers/benches/primitives.rs
Normal file
378
ciphers/benches/primitives.rs
Normal file
@@ -0,0 +1,378 @@
|
||||
criterion::criterion_main!(keyed_hash::benches, aead::benches, kem::benches);
|
||||
|
||||
fn benchid(base: KvPairs, last: KvPairs) -> String {
|
||||
format!("{base},{last}")
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct KvPair<'a>(&'a str, &'a str);
|
||||
|
||||
impl std::fmt::Display for KvPair<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{k}={v}", k = self.0, v = self.1)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
struct KvPairs<'a>(&'a [KvPair<'a>]);
|
||||
|
||||
impl std::fmt::Display for KvPairs<'_> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self.0.len() {
|
||||
0 => Ok(()),
|
||||
1 => write!(f, "{}", &self.0[0]),
|
||||
_ => {
|
||||
let mut delim = "";
|
||||
for pair in self.0 {
|
||||
write!(f, "{delim}{pair}")?;
|
||||
delim = ",";
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod kem {
|
||||
criterion::criterion_group!(
|
||||
benches,
|
||||
bench_kyber512_libcrux,
|
||||
bench_kyber512_oqs,
|
||||
bench_classicmceliece460896_oqs
|
||||
);
|
||||
|
||||
use criterion::Criterion;
|
||||
|
||||
fn bench_classicmceliece460896_oqs(c: &mut Criterion) {
|
||||
template(
|
||||
c,
|
||||
"classicmceliece460896",
|
||||
"oqs",
|
||||
rosenpass_oqs::ClassicMceliece460896,
|
||||
);
|
||||
}
|
||||
|
||||
fn bench_kyber512_libcrux(c: &mut Criterion) {
|
||||
template(
|
||||
c,
|
||||
"kyber512",
|
||||
"libcrux",
|
||||
rosenpass_ciphers::subtle::libcrux::kyber512::Kyber512,
|
||||
);
|
||||
}
|
||||
|
||||
fn bench_kyber512_oqs(c: &mut Criterion) {
|
||||
template(c, "kyber512", "oqs", rosenpass_oqs::Kyber512);
|
||||
}
|
||||
|
||||
use rosenpass_cipher_traits::primitives::Kem;
|
||||
|
||||
fn template<
|
||||
const SK_LEN: usize,
|
||||
const PK_LEN: usize,
|
||||
const CT_LEN: usize,
|
||||
const SHK_LEN: usize,
|
||||
T: Kem<SK_LEN, PK_LEN, CT_LEN, SHK_LEN>,
|
||||
>(
|
||||
c: &mut Criterion,
|
||||
alg_name: &str,
|
||||
impl_name: &str,
|
||||
scheme: T,
|
||||
) {
|
||||
use super::{benchid, KvPair, KvPairs};
|
||||
|
||||
let base = [
|
||||
KvPair("primitive", "kem"),
|
||||
KvPair("algorithm", alg_name),
|
||||
KvPair("implementation", impl_name),
|
||||
KvPair("length", "-1"),
|
||||
];
|
||||
|
||||
let kem_benchid = |op| benchid(KvPairs(&base), KvPairs(&[KvPair("operation", op)]));
|
||||
|
||||
c.bench_function(&kem_benchid("keygen"), |bench| {
|
||||
let mut sk = [0; SK_LEN];
|
||||
let mut pk = [0; PK_LEN];
|
||||
|
||||
bench.iter(|| {
|
||||
scheme.keygen(&mut sk, &mut pk).unwrap();
|
||||
});
|
||||
});
|
||||
|
||||
c.bench_function(&kem_benchid("encaps"), |bench| {
|
||||
let mut sk = [0; SK_LEN];
|
||||
let mut pk = [0; PK_LEN];
|
||||
let mut ct = [0; CT_LEN];
|
||||
let mut shk = [0; SHK_LEN];
|
||||
|
||||
scheme.keygen(&mut sk, &mut pk).unwrap();
|
||||
|
||||
bench.iter(|| {
|
||||
scheme.encaps(&mut shk, &mut ct, &pk).unwrap();
|
||||
});
|
||||
});
|
||||
|
||||
c.bench_function(&kem_benchid("decaps"), |bench| {
|
||||
let mut sk = [0; SK_LEN];
|
||||
let mut pk = [0; PK_LEN];
|
||||
let mut ct = [0; CT_LEN];
|
||||
let mut shk = [0; SHK_LEN];
|
||||
let mut shk2 = [0; SHK_LEN];
|
||||
|
||||
scheme.keygen(&mut sk, &mut pk).unwrap();
|
||||
scheme.encaps(&mut shk, &mut ct, &pk).unwrap();
|
||||
|
||||
bench.iter(|| {
|
||||
scheme.decaps(&mut shk2, &sk, &ct).unwrap();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
mod aead {
|
||||
criterion::criterion_group!(
|
||||
benches,
|
||||
bench_chachapoly_libcrux,
|
||||
bench_chachapoly_rustcrypto,
|
||||
bench_xchachapoly_rustcrypto,
|
||||
);
|
||||
|
||||
use criterion::Criterion;
|
||||
|
||||
const KEY_LEN: usize = rosenpass_ciphers::Aead::KEY_LEN;
|
||||
const TAG_LEN: usize = rosenpass_ciphers::Aead::TAG_LEN;
|
||||
|
||||
fn bench_xchachapoly_rustcrypto(c: &mut Criterion) {
|
||||
template(
|
||||
c,
|
||||
"xchacha20poly1305",
|
||||
"rustcrypto",
|
||||
rosenpass_ciphers::subtle::rust_crypto::xchacha20poly1305_ietf::XChaCha20Poly1305,
|
||||
);
|
||||
}
|
||||
|
||||
fn bench_chachapoly_rustcrypto(c: &mut Criterion) {
|
||||
template(
|
||||
c,
|
||||
"chacha20poly1305",
|
||||
"rustcrypto",
|
||||
rosenpass_ciphers::subtle::rust_crypto::chacha20poly1305_ietf::ChaCha20Poly1305,
|
||||
);
|
||||
}
|
||||
|
||||
fn bench_chachapoly_libcrux(c: &mut Criterion) {
|
||||
template(
|
||||
c,
|
||||
"chacha20poly1305",
|
||||
"libcrux",
|
||||
rosenpass_ciphers::subtle::libcrux::chacha20poly1305_ietf::ChaCha20Poly1305,
|
||||
);
|
||||
}
|
||||
|
||||
use rosenpass_cipher_traits::primitives::Aead;
|
||||
|
||||
fn template<const NONCE_LEN: usize, T: Aead<KEY_LEN, NONCE_LEN, TAG_LEN>>(
|
||||
c: &mut Criterion,
|
||||
alg_name: &str,
|
||||
impl_name: &str,
|
||||
scheme: T,
|
||||
) {
|
||||
use crate::{benchid, KvPair, KvPairs};
|
||||
|
||||
let base = [
|
||||
KvPair("primitive", "aead"),
|
||||
KvPair("algorithm", alg_name),
|
||||
KvPair("implementation", impl_name),
|
||||
];
|
||||
let aead_benchid = |op, len| {
|
||||
benchid(
|
||||
KvPairs(&base),
|
||||
KvPairs(&[KvPair("operation", op), KvPair("length", len)]),
|
||||
)
|
||||
};
|
||||
|
||||
let key = [12; KEY_LEN];
|
||||
let nonce = [23; NONCE_LEN];
|
||||
let ad = [];
|
||||
|
||||
c.bench_function(&aead_benchid("encrypt", "0byte"), |bench| {
|
||||
const DATA_LEN: usize = 0;
|
||||
|
||||
let ptxt = [];
|
||||
let mut ctxt = [0; DATA_LEN + TAG_LEN];
|
||||
|
||||
bench.iter(|| {
|
||||
scheme.encrypt(&mut ctxt, &key, &nonce, &ad, &ptxt).unwrap();
|
||||
});
|
||||
});
|
||||
|
||||
c.bench_function(&aead_benchid("decrypt", "0byte"), |bench| {
|
||||
const DATA_LEN: usize = 0;
|
||||
|
||||
let ptxt = [];
|
||||
let mut ctxt = [0; DATA_LEN + TAG_LEN];
|
||||
let mut ptxt_out = [0u8; DATA_LEN];
|
||||
|
||||
scheme.encrypt(&mut ctxt, &key, &nonce, &ad, &ptxt).unwrap();
|
||||
|
||||
bench.iter(|| {
|
||||
scheme
|
||||
.decrypt(&mut ptxt_out, &key, &nonce, &ad, &mut ctxt)
|
||||
.unwrap()
|
||||
})
|
||||
});
|
||||
|
||||
c.bench_function(&aead_benchid("encrypt", "32byte"), |bench| {
|
||||
const DATA_LEN: usize = 32;
|
||||
|
||||
let ptxt = [34u8; DATA_LEN];
|
||||
let mut ctxt = [0; DATA_LEN + TAG_LEN];
|
||||
|
||||
bench.iter(|| {
|
||||
scheme.encrypt(&mut ctxt, &key, &nonce, &ad, &ptxt).unwrap();
|
||||
});
|
||||
});
|
||||
|
||||
c.bench_function(&aead_benchid("decrypt", "32byte"), |bench| {
|
||||
const DATA_LEN: usize = 32;
|
||||
|
||||
let ptxt = [34u8; DATA_LEN];
|
||||
let mut ctxt = [0; DATA_LEN + TAG_LEN];
|
||||
let mut ptxt_out = [0u8; DATA_LEN];
|
||||
|
||||
scheme.encrypt(&mut ctxt, &key, &nonce, &ad, &ptxt).unwrap();
|
||||
|
||||
bench.iter(|| {
|
||||
scheme
|
||||
.decrypt(&mut ptxt_out, &key, &nonce, &ad, &mut ctxt)
|
||||
.unwrap()
|
||||
})
|
||||
});
|
||||
|
||||
c.bench_function(&aead_benchid("encrypt", "1024byte"), |bench| {
|
||||
const DATA_LEN: usize = 1024;
|
||||
|
||||
let ptxt = [34u8; DATA_LEN];
|
||||
let mut ctxt = [0; DATA_LEN + TAG_LEN];
|
||||
|
||||
bench.iter(|| {
|
||||
scheme.encrypt(&mut ctxt, &key, &nonce, &ad, &ptxt).unwrap();
|
||||
});
|
||||
});
|
||||
c.bench_function(&aead_benchid("decrypt", "1024byte"), |bench| {
|
||||
const DATA_LEN: usize = 1024;
|
||||
|
||||
let ptxt = [34u8; DATA_LEN];
|
||||
let mut ctxt = [0; DATA_LEN + TAG_LEN];
|
||||
let mut ptxt_out = [0u8; DATA_LEN];
|
||||
|
||||
scheme.encrypt(&mut ctxt, &key, &nonce, &ad, &ptxt).unwrap();
|
||||
|
||||
bench.iter(|| {
|
||||
scheme
|
||||
.decrypt(&mut ptxt_out, &key, &nonce, &ad, &mut ctxt)
|
||||
.unwrap()
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
mod keyed_hash {
|
||||
criterion::criterion_group!(
|
||||
benches,
|
||||
bench_blake2b_rustcrypto,
|
||||
bench_blake2b_libcrux,
|
||||
bench_shake256_rustcrypto,
|
||||
);
|
||||
|
||||
const KEY_LEN: usize = 32;
|
||||
const HASH_LEN: usize = 32;
|
||||
|
||||
use criterion::Criterion;
|
||||
|
||||
fn bench_shake256_rustcrypto(c: &mut Criterion) {
|
||||
template(
|
||||
c,
|
||||
"shake256",
|
||||
"rustcrypto",
|
||||
&rosenpass_ciphers::subtle::rust_crypto::keyed_shake256::SHAKE256Core,
|
||||
);
|
||||
}
|
||||
|
||||
fn bench_blake2b_rustcrypto(c: &mut Criterion) {
|
||||
template(
|
||||
c,
|
||||
"blake2b",
|
||||
"rustcrypto",
|
||||
&rosenpass_ciphers::subtle::rust_crypto::blake2b::Blake2b,
|
||||
);
|
||||
}
|
||||
|
||||
fn bench_blake2b_libcrux(c: &mut Criterion) {
|
||||
template(
|
||||
c,
|
||||
"blake2b",
|
||||
"libcrux",
|
||||
&rosenpass_ciphers::subtle::libcrux::blake2b::Blake2b,
|
||||
);
|
||||
}
|
||||
|
||||
use rosenpass_cipher_traits::primitives::KeyedHash;
|
||||
|
||||
fn template<H: KeyedHash<KEY_LEN, HASH_LEN>>(
|
||||
c: &mut Criterion,
|
||||
alg_name: &str,
|
||||
impl_name: &str,
|
||||
_: &H,
|
||||
) where
|
||||
H::Error: std::fmt::Debug,
|
||||
{
|
||||
use crate::{benchid, KvPair, KvPairs};
|
||||
|
||||
let key = [12u8; KEY_LEN];
|
||||
let mut out = [0u8; HASH_LEN];
|
||||
|
||||
let base = [
|
||||
KvPair("primitive", "keyedhash"),
|
||||
KvPair("algorithm", alg_name),
|
||||
KvPair("implementation", impl_name),
|
||||
KvPair("operation", "hash"),
|
||||
];
|
||||
let keyedhash_benchid = |len| benchid(KvPairs(&base), KvPairs(&[KvPair("length", len)]));
|
||||
|
||||
c.bench_function(&keyedhash_benchid("0byte"), |bench| {
|
||||
let bytes = [];
|
||||
|
||||
bench.iter(|| {
|
||||
H::keyed_hash(&key, &bytes, &mut out).unwrap();
|
||||
})
|
||||
})
|
||||
.bench_function(&keyedhash_benchid("32byte"), |bench| {
|
||||
let bytes = [34u8; 32];
|
||||
|
||||
bench.iter(|| {
|
||||
H::keyed_hash(&key, &bytes, &mut out).unwrap();
|
||||
})
|
||||
})
|
||||
.bench_function(&keyedhash_benchid("64byte"), |bench| {
|
||||
let bytes = [34u8; 64];
|
||||
|
||||
bench.iter(|| {
|
||||
H::keyed_hash(&key, &bytes, &mut out).unwrap();
|
||||
})
|
||||
})
|
||||
.bench_function(&keyedhash_benchid("128byte"), |bench| {
|
||||
let bytes = [34u8; 128];
|
||||
|
||||
bench.iter(|| {
|
||||
H::keyed_hash(&key, &bytes, &mut out).unwrap();
|
||||
})
|
||||
})
|
||||
.bench_function(&keyedhash_benchid("1024byte"), |bench| {
|
||||
let bytes = [34u8; 1024];
|
||||
|
||||
bench.iter(|| {
|
||||
H::keyed_hash(&key, &bytes, &mut out).unwrap();
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -4,11 +4,11 @@
|
||||
//!
|
||||
//! [Github](https://github.com/cryspen/libcrux)
|
||||
|
||||
#[cfg(feature = "experiment_libcrux_blake2")]
|
||||
#[cfg(feature = "experiment_libcrux_define_blake2")]
|
||||
pub mod blake2b;
|
||||
|
||||
#[cfg(feature = "experiment_libcrux_chachapoly")]
|
||||
#[cfg(feature = "experiment_libcrux_define_chachapoly")]
|
||||
pub mod chacha20poly1305_ietf;
|
||||
|
||||
#[cfg(feature = "experiment_libcrux_kyber")]
|
||||
#[cfg(feature = "experiment_libcrux_define_kyber")]
|
||||
pub mod kyber512;
|
||||
|
||||
@@ -9,8 +9,8 @@ pub mod custom;
|
||||
pub mod rust_crypto;
|
||||
|
||||
#[cfg(any(
|
||||
feature = "experiment_libcrux_blake2",
|
||||
feature = "experiment_libcrux_chachapoly",
|
||||
feature = "experiment_libcrux_kyber"
|
||||
feature = "experiment_libcrux_define_blake2",
|
||||
feature = "experiment_libcrux_define_chachapoly",
|
||||
feature = "experiment_libcrux_define_kyber",
|
||||
))]
|
||||
pub mod libcrux;
|
||||
|
||||
@@ -8,6 +8,7 @@ description = "Rosenpass internal utilities for constant time crypto implementat
|
||||
homepage = "https://rosenpass.eu/"
|
||||
repository = "https://github.com/rosenpass/rosenpass"
|
||||
readme = "readme.md"
|
||||
rust-version = "1.77.0"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
33
deny.toml
33
deny.toml
@@ -24,10 +24,7 @@ feature-depth = 1
|
||||
[advisories]
|
||||
# A list of advisory IDs to ignore. Note that ignored advisories will still
|
||||
# output a note when they are encountered.
|
||||
ignore = [
|
||||
"RUSTSEC-2024-0370",
|
||||
"RUSTSEC-2024-0436",
|
||||
]
|
||||
ignore = ["RUSTSEC-2024-0370", "RUSTSEC-2024-0436", "RUSTSEC-2023-0089"]
|
||||
# If this is true, then cargo deny will use the git executable to fetch advisory database.
|
||||
# If this is false, then it uses a built-in git library.
|
||||
# Setting this to true can be helpful if you have special authentication requirements that cargo-deny does not support.
|
||||
@@ -42,11 +39,11 @@ ignore = [
|
||||
# See https://spdx.org/licenses/ for list of possible licenses
|
||||
# [possible values: any SPDX 3.11 short identifier (+ optional exception)].
|
||||
allow = [
|
||||
"MIT",
|
||||
"Apache-2.0",
|
||||
"Apache-2.0 WITH LLVM-exception",
|
||||
"BSD-3-Clause",
|
||||
"ISC",
|
||||
"MIT",
|
||||
"Apache-2.0",
|
||||
"Apache-2.0 WITH LLVM-exception",
|
||||
"BSD-3-Clause",
|
||||
"ISC",
|
||||
]
|
||||
# The confidence threshold for detecting a license from license text.
|
||||
# The higher the value, the more closely the license text must be to the
|
||||
@@ -56,10 +53,10 @@ confidence-threshold = 0.8
|
||||
# Allow 1 or more licenses on a per-crate basis, so that particular licenses
|
||||
# aren't accepted for every possible crate as with the normal allow list
|
||||
exceptions = [
|
||||
# Each entry is the crate and version constraint, and its specific allow
|
||||
# list
|
||||
{ allow = ["Unicode-DFS-2016", "Unicode-3.0"], crate = "unicode-ident" },
|
||||
{ allow = ["NCSA"], crate = "libfuzzer-sys" },
|
||||
# Each entry is the crate and version constraint, and its specific allow
|
||||
# list
|
||||
{ allow = ["Unicode-DFS-2016", "Unicode-3.0"], crate = "unicode-ident" },
|
||||
{ allow = ["NCSA"], crate = "libfuzzer-sys" },
|
||||
|
||||
]
|
||||
|
||||
@@ -93,15 +90,11 @@ workspace-default-features = "allow"
|
||||
# on a crate-by-crate basis if desired.
|
||||
external-default-features = "allow"
|
||||
# List of crates that are allowed. Use with care!
|
||||
allow = [
|
||||
]
|
||||
allow = []
|
||||
# List of crates to deny
|
||||
deny = [
|
||||
]
|
||||
deny = []
|
||||
|
||||
skip-tree = [
|
||||
|
||||
]
|
||||
skip-tree = []
|
||||
|
||||
# This section is considered when running `cargo deny check sources`.
|
||||
# More documentation about the 'sources' section can be found here:
|
||||
|
||||
69
flake.lock
generated
69
flake.lock
generated
@@ -1,26 +1,5 @@
|
||||
{
|
||||
"nodes": {
|
||||
"fenix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1728282832,
|
||||
"narHash": "sha256-I7AbcwGggf+CHqpyd/9PiAjpIBGTGx5woYHqtwxaV7I=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "1ec71be1f4b8f3105c5d38da339cb061fefc43f4",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
@@ -77,26 +56,30 @@
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"fenix": "fenix",
|
||||
"flake-utils": "flake-utils",
|
||||
"nix-vm-test": "nix-vm-test",
|
||||
"nixpkgs": "nixpkgs"
|
||||
"nixpkgs": "nixpkgs",
|
||||
"rust-overlay": "rust-overlay",
|
||||
"treefmt-nix": "treefmt-nix"
|
||||
}
|
||||
},
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"rust-overlay": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1728249780,
|
||||
"narHash": "sha256-J269DvCI5dzBmPrXhAAtj566qt0b22TJtF3TIK+tMsI=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "2b750da1a1a2c1d2c70896108d7096089842d877",
|
||||
"lastModified": 1744513456,
|
||||
"narHash": "sha256-NLVluTmK8d01Iz+WyarQhwFcXpHEwU7m5hH3YQQFJS0=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "730fd8e82799219754418483fabe1844262fd1e2",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rust-lang",
|
||||
"ref": "nightly",
|
||||
"repo": "rust-analyzer",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
@@ -114,6 +97,26 @@
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"treefmt-nix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1743748085,
|
||||
"narHash": "sha256-uhjnlaVTWo5iD3LXics1rp9gaKgDRQj6660+gbUU3cE=",
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"rev": "815e4121d6a5d504c0f96e5be2dd7f871e4fd99d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "treefmt-nix",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
|
||||
296
flake.nix
296
flake.nix
@@ -3,41 +3,51 @@
|
||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
|
||||
# for rust nightly with llvm-tools-preview
|
||||
fenix.url = "github:nix-community/fenix";
|
||||
fenix.inputs.nixpkgs.follows = "nixpkgs";
|
||||
|
||||
nix-vm-test.url = "github:numtide/nix-vm-test";
|
||||
nix-vm-test.inputs.nixpkgs.follows = "nixpkgs";
|
||||
nix-vm-test.inputs.flake-utils.follows = "flake-utils";
|
||||
|
||||
# for rust nightly with llvm-tools-preview
|
||||
rust-overlay.url = "github:oxalica/rust-overlay";
|
||||
rust-overlay.inputs.nixpkgs.follows = "nixpkgs";
|
||||
|
||||
treefmt-nix.url = "github:numtide/treefmt-nix";
|
||||
treefmt-nix.inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, flake-utils, nix-vm-test, ... }@inputs:
|
||||
outputs =
|
||||
{
|
||||
self,
|
||||
nixpkgs,
|
||||
flake-utils,
|
||||
nix-vm-test,
|
||||
rust-overlay,
|
||||
treefmt-nix,
|
||||
...
|
||||
}@inputs:
|
||||
nixpkgs.lib.foldl (a: b: nixpkgs.lib.recursiveUpdate a b) { } [
|
||||
|
||||
|
||||
#
|
||||
### Export the overlay.nix from this flake ###
|
||||
#
|
||||
{
|
||||
overlays.default = import ./overlay.nix;
|
||||
}
|
||||
|
||||
{ overlays.default = import ./overlay.nix; }
|
||||
|
||||
#
|
||||
### Actual Rosenpass Package and Docker Container Images ###
|
||||
#
|
||||
(flake-utils.lib.eachSystem [
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
(flake-utils.lib.eachSystem
|
||||
[
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
|
||||
# unsuported best-effort
|
||||
"i686-linux"
|
||||
"x86_64-darwin"
|
||||
"aarch64-darwin"
|
||||
# "x86_64-windows"
|
||||
]
|
||||
(system:
|
||||
# unsuported best-effort
|
||||
"i686-linux"
|
||||
"x86_64-darwin"
|
||||
"aarch64-darwin"
|
||||
# "x86_64-windows"
|
||||
]
|
||||
(
|
||||
system:
|
||||
let
|
||||
# normal nixpkgs
|
||||
pkgs = import nixpkgs {
|
||||
@@ -48,129 +58,159 @@
|
||||
};
|
||||
in
|
||||
{
|
||||
packages = {
|
||||
default = pkgs.rosenpass;
|
||||
rosenpass = pkgs.rosenpass;
|
||||
rosenpass-oci-image = pkgs.rosenpass-oci-image;
|
||||
rp = pkgs.rp;
|
||||
packages =
|
||||
{
|
||||
default = pkgs.rosenpass;
|
||||
rosenpass = pkgs.rosenpass;
|
||||
rosenpass-oci-image = pkgs.rosenpass-oci-image;
|
||||
rp = pkgs.rp;
|
||||
|
||||
release-package = pkgs.release-package;
|
||||
release-package = pkgs.release-package;
|
||||
|
||||
# for good measure, we also offer to cross compile to Linux on Arm
|
||||
aarch64-linux-rosenpass-static =
|
||||
pkgs.pkgsCross.aarch64-multiplatform.pkgsStatic.rosenpass;
|
||||
aarch64-linux-rp-static = pkgs.pkgsCross.aarch64-multiplatform.pkgsStatic.rp;
|
||||
}
|
||||
//
|
||||
# We only offer static builds for linux, as this is not supported on OS X
|
||||
(nixpkgs.lib.attrsets.optionalAttrs pkgs.stdenv.isLinux {
|
||||
rosenpass-static = pkgs.pkgsStatic.rosenpass;
|
||||
rosenpass-static-oci-image = pkgs.pkgsStatic.rosenpass-oci-image;
|
||||
rp-static = pkgs.pkgsStatic.rp;
|
||||
});
|
||||
# for good measure, we also offer to cross compile to Linux on Arm
|
||||
aarch64-linux-rosenpass-static = pkgs.pkgsCross.aarch64-multiplatform.pkgsStatic.rosenpass;
|
||||
aarch64-linux-rp-static = pkgs.pkgsCross.aarch64-multiplatform.pkgsStatic.rp;
|
||||
}
|
||||
//
|
||||
# We only offer static builds for linux, as this is not supported on OS X
|
||||
(nixpkgs.lib.attrsets.optionalAttrs pkgs.stdenv.isLinux {
|
||||
rosenpass-static = pkgs.pkgsStatic.rosenpass;
|
||||
rosenpass-static-oci-image = pkgs.pkgsStatic.rosenpass-oci-image;
|
||||
rp-static = pkgs.pkgsStatic.rp;
|
||||
});
|
||||
}
|
||||
))
|
||||
|
||||
)
|
||||
)
|
||||
|
||||
#
|
||||
### Linux specifics ###
|
||||
#
|
||||
(flake-utils.lib.eachSystem [ "x86_64-linux" "aarch64-linux" ] (system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
(flake-utils.lib.eachSystem
|
||||
[
|
||||
"x86_64-linux"
|
||||
"aarch64-linux"
|
||||
"i686-linux"
|
||||
]
|
||||
(
|
||||
system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
|
||||
# apply our own overlay, overriding/inserting our packages as defined in ./pkgs
|
||||
overlays = [
|
||||
self.overlays.default
|
||||
nix-vm-test.overlays.default
|
||||
];
|
||||
};
|
||||
in
|
||||
{
|
||||
packages.package-deb = pkgs.callPackage ./pkgs/package-deb.nix {
|
||||
rosenpass = pkgs.pkgsStatic.rosenpass;
|
||||
};
|
||||
packages.package-rpm = pkgs.callPackage ./pkgs/package-rpm.nix {
|
||||
rosenpass = pkgs.pkgsStatic.rosenpass;
|
||||
};
|
||||
overlays = [
|
||||
# apply our own overlay, overriding/inserting our packages as defined in ./pkgs
|
||||
self.overlays.default
|
||||
|
||||
#
|
||||
### Reading materials ###
|
||||
#
|
||||
packages.whitepaper = pkgs.whitepaper;
|
||||
nix-vm-test.overlays.default
|
||||
|
||||
#
|
||||
### Proof and Proof Tools ###
|
||||
#
|
||||
packages.proverif-patched = pkgs.proverif-patched;
|
||||
packages.proof-proverif = pkgs.proof-proverif;
|
||||
# apply rust-overlay to get specific versions of the rust toolchain for a MSRV check
|
||||
(import rust-overlay)
|
||||
];
|
||||
};
|
||||
|
||||
treefmtEval = treefmt-nix.lib.evalModule pkgs ./treefmt.nix;
|
||||
in
|
||||
{
|
||||
packages.package-deb = pkgs.callPackage ./pkgs/package-deb.nix {
|
||||
rosenpass = pkgs.pkgsStatic.rosenpass;
|
||||
};
|
||||
packages.package-rpm = pkgs.callPackage ./pkgs/package-rpm.nix {
|
||||
rosenpass = pkgs.pkgsStatic.rosenpass;
|
||||
};
|
||||
|
||||
#
|
||||
### Devshells ###
|
||||
#
|
||||
devShells.default = pkgs.mkShell {
|
||||
inherit (pkgs.proof-proverif) CRYPTOVERIF_LIB;
|
||||
inputsFrom = [ pkgs.rosenpass ];
|
||||
nativeBuildInputs = with pkgs; [
|
||||
cargo-release
|
||||
clippy
|
||||
rustfmt
|
||||
nodePackages.prettier
|
||||
nushell # for the .ci/gen-workflow-files.nu script
|
||||
proverif-patched
|
||||
];
|
||||
};
|
||||
# TODO: Write this as a patched version of the default environment
|
||||
devShells.fullEnv = pkgs.mkShell {
|
||||
inherit (pkgs.proof-proverif) CRYPTOVERIF_LIB;
|
||||
inputsFrom = [ pkgs.rosenpass ];
|
||||
nativeBuildInputs = with pkgs; [
|
||||
cargo-audit
|
||||
cargo-release
|
||||
rustfmt
|
||||
nodePackages.prettier
|
||||
nushell # for the .ci/gen-workflow-files.nu script
|
||||
proverif-patched
|
||||
inputs.fenix.packages.${system}.complete.toolchain
|
||||
pkgs.cargo-llvm-cov
|
||||
pkgs.grcov
|
||||
];
|
||||
};
|
||||
devShells.coverage = pkgs.mkShell {
|
||||
inputsFrom = [ pkgs.rosenpass ];
|
||||
nativeBuildInputs = [
|
||||
inputs.fenix.packages.${system}.complete.toolchain
|
||||
pkgs.cargo-llvm-cov
|
||||
pkgs.grcov
|
||||
];
|
||||
};
|
||||
#
|
||||
### Reading materials ###
|
||||
#
|
||||
packages.whitepaper = pkgs.whitepaper;
|
||||
|
||||
#
|
||||
### Proof and Proof Tools ###
|
||||
#
|
||||
packages.proverif-patched = pkgs.proverif-patched;
|
||||
packages.proof-proverif = pkgs.proof-proverif;
|
||||
|
||||
checks = {
|
||||
systemd-rosenpass = pkgs.testers.runNixOSTest ./tests/systemd/rosenpass.nix;
|
||||
systemd-rp = pkgs.testers.runNixOSTest ./tests/systemd/rp.nix;
|
||||
#
|
||||
### Devshells ###
|
||||
#
|
||||
devShells.default = pkgs.mkShell {
|
||||
inherit (pkgs.proof-proverif) CRYPTOVERIF_LIB;
|
||||
inputsFrom = [ pkgs.rosenpass ];
|
||||
nativeBuildInputs = with pkgs; [
|
||||
cargo-release
|
||||
clippy
|
||||
rustfmt
|
||||
nodePackages.prettier
|
||||
nushell # for the .ci/gen-workflow-files.nu script
|
||||
proverif-patched
|
||||
];
|
||||
};
|
||||
# TODO: Write this as a patched version of the default environment
|
||||
devShells.fullEnv = pkgs.mkShell {
|
||||
inherit (pkgs.proof-proverif) CRYPTOVERIF_LIB;
|
||||
inputsFrom = [ pkgs.rosenpass ];
|
||||
nativeBuildInputs = with pkgs; [
|
||||
cargo-audit
|
||||
cargo-msrv
|
||||
cargo-release
|
||||
cargo-vet
|
||||
rustfmt
|
||||
nodePackages.prettier
|
||||
nushell # for the .ci/gen-workflow-files.nu script
|
||||
proverif-patched
|
||||
pkgs.cargo-llvm-cov
|
||||
pkgs.grcov
|
||||
pkgs.rust-bin.stable.latest.complete
|
||||
];
|
||||
};
|
||||
devShells.coverage = pkgs.mkShell {
|
||||
inputsFrom = [ pkgs.rosenpass ];
|
||||
nativeBuildInputs = [
|
||||
pkgs.cargo-llvm-cov
|
||||
pkgs.grcov
|
||||
pkgs.rustc.llvmPackages.llvm
|
||||
];
|
||||
env = {
|
||||
inherit (pkgs.cargo-llvm-cov) LLVM_COV LLVM_PROFDATA;
|
||||
};
|
||||
};
|
||||
devShells.benchmarks = pkgs.mkShell {
|
||||
inputsFrom = [ pkgs.rosenpass ];
|
||||
nativeBuildInputs = with pkgs; [
|
||||
cargo-release
|
||||
clippy
|
||||
rustfmt
|
||||
];
|
||||
};
|
||||
|
||||
cargo-fmt = pkgs.runCommand "check-cargo-fmt"
|
||||
{ inherit (self.devShells.${system}.default) nativeBuildInputs buildInputs; } ''
|
||||
cargo fmt --manifest-path=${./.}/Cargo.toml --check --all && touch $out
|
||||
'';
|
||||
nixpkgs-fmt = pkgs.runCommand "check-nixpkgs-fmt"
|
||||
{ nativeBuildInputs = [ pkgs.nixpkgs-fmt ]; } ''
|
||||
nixpkgs-fmt --check ${./.} && touch $out
|
||||
'';
|
||||
prettier-check = pkgs.runCommand "check-with-prettier"
|
||||
{ nativeBuildInputs = [ pkgs.nodePackages.prettier ]; } ''
|
||||
cd ${./.} && prettier --check . && touch $out
|
||||
'';
|
||||
} // pkgs.lib.optionalAttrs (system == "x86_64-linux") (import ./tests/legacy-distro-packaging.nix {
|
||||
inherit pkgs;
|
||||
rosenpass-deb = self.packages.${system}.package-deb;
|
||||
rosenpass-rpm = self.packages.${system}.package-rpm;
|
||||
});
|
||||
checks =
|
||||
{
|
||||
systemd-rosenpass = pkgs.testers.runNixOSTest ./tests/systemd/rosenpass.nix;
|
||||
systemd-rp = pkgs.testers.runNixOSTest ./tests/systemd/rp.nix;
|
||||
formatting = treefmtEval.config.build.check self;
|
||||
rosenpass-msrv-check =
|
||||
let
|
||||
rosenpassCargoToml = pkgs.lib.trivial.importTOML ./rosenpass/Cargo.toml;
|
||||
|
||||
formatter = pkgs.nixpkgs-fmt;
|
||||
}))
|
||||
rustToolchain = pkgs.rust-bin.stable.${rosenpassCargoToml.package.rust-version}.default;
|
||||
rustPlatform = pkgs.makeRustPlatform {
|
||||
cargo = rustToolchain;
|
||||
rustc = rustToolchain;
|
||||
};
|
||||
in
|
||||
pkgs.rosenpass.override { inherit rustPlatform; };
|
||||
}
|
||||
// pkgs.lib.optionalAttrs (system == "x86_64-linux") (
|
||||
import ./tests/legacy-distro-packaging.nix {
|
||||
inherit pkgs;
|
||||
rosenpass-deb = self.packages.${system}.package-deb;
|
||||
rosenpass-rpm = self.packages.${system}.package-rpm;
|
||||
}
|
||||
);
|
||||
|
||||
# for `nix fmt`
|
||||
formatter = treefmtEval.config.build.wrapper;
|
||||
}
|
||||
)
|
||||
)
|
||||
];
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ name = "rosenpass-fuzzing"
|
||||
version = "0.0.1"
|
||||
publish = false
|
||||
edition = "2021"
|
||||
rust-version = "1.77.0"
|
||||
|
||||
[features]
|
||||
experiment_libcrux = ["rosenpass-ciphers/experiment_libcrux_all"]
|
||||
|
||||
@@ -8,6 +8,7 @@ description = "Rosenpass internal bindings to liboqs"
|
||||
homepage = "https://rosenpass.eu/"
|
||||
repository = "https://github.com/rosenpass/rosenpass"
|
||||
readme = "readme.md"
|
||||
rust-version = "1.77.0"
|
||||
|
||||
[dependencies]
|
||||
rosenpass-cipher-traits = { workspace = true }
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
final: prev: {
|
||||
|
||||
|
||||
#
|
||||
### Actual rosenpass software ###
|
||||
#
|
||||
@@ -27,7 +26,10 @@ final: prev: {
|
||||
"marzipan(/marzipan.awk)?"
|
||||
"analysis(/.*)?"
|
||||
];
|
||||
nativeBuildInputs = [ final.proverif final.graphviz ];
|
||||
nativeBuildInputs = [
|
||||
final.proverif
|
||||
final.graphviz
|
||||
];
|
||||
CRYPTOVERIF_LIB = final.proverif-patched + "/lib/cryptoverif.pvl";
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
|
||||
@@ -196,3 +196,13 @@ Vadim Lyubashevsky and John M. Schanck and Peter Schwabe and Gregor Seiler and D
|
||||
type = {NIST Post-Quantum Cryptography Selected Algorithm},
|
||||
url = {https://pq-crystals.org/kyber/}
|
||||
}
|
||||
|
||||
|
||||
@misc{SHAKE256,
|
||||
author = "National Institute of Standards and Technology",
|
||||
title = "FIPS PUB 202: SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions",
|
||||
year = {2015},
|
||||
month = {August},
|
||||
doi = {10.6028/NIST.FIPS.202}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ abstract: |
|
||||
Rosenpass inherits most security properties from Post-Quantum WireGuard (PQWG). The security properties mentioned here are covered by the symbolic analysis in the Rosenpass repository.
|
||||
|
||||
## Secrecy
|
||||
Three key encapsulations using the keypairs `sski`/`spki`, `sskr`/`spkr`, and `eski`/`epki` provide secrecy (see Section \ref{variables} for an introduction of the variables). Their respective ciphertexts are called `scti`, `sctr`, and `ectr` and the resulting keys are called `spti`, `sptr`, `epti`. A single secure encapsulation is sufficient to provide secrecy. We use two different KEMs (Key Encapsulation Mechanisms; see section \ref{skem}): Kyber and Classic McEliece.
|
||||
Three key encapsulations using the keypairs `sski`/`spki`, `sskr`/`spkr`, and `eski`/`epki` provide secrecy (see Section \ref{variables} for an introduction of the variables). Their respective ciphertexts are called `scti`, `sctr`, and `ectr` and the resulting keys are called `spti`, `sptr`, `epti`. A single secure encapsulation is sufficient to provide secrecy. We use two different KEMs (Key Encapsulation Mechanisms; see Section \ref{skem}): Kyber and Classic McEliece.
|
||||
|
||||
## Authenticity
|
||||
|
||||
@@ -64,9 +64,12 @@ Note that while Rosenpass is secure against state disruption, using it does not
|
||||
All symmetric keys and hash values used in Rosenpass are 32 bytes long.
|
||||
|
||||
|
||||
### Hash
|
||||
### Hash {#hash}
|
||||
|
||||
A keyed hash function with one 32-byte input, one variable-size input, and one 32-byte output. As keyed hash function we use the HMAC construction [@rfc_hmac] with BLAKE2s [@rfc_blake2] as the inner hash function.
|
||||
A keyed hash function with one 32-byte input, one variable-size input, and one 32-byte output. As keyed hash function we offer two options that can be configured on a peer-basis, with Blake2s being the default:
|
||||
|
||||
1. the HMAC construction [@rfc_hmac] with BLAKE2s [@rfc_blake2] as the inner hash function.
|
||||
2. the SHAKE256 extendable output function (XOF) [@SHAKE256] truncated to a 32-byte output. The result is produced be concatenating the 32-byte input with the variable-size input in this order.
|
||||
|
||||
```pseudorust
|
||||
hash(key, data) -> key
|
||||
@@ -172,6 +175,8 @@ Rosenpass uses a cryptographic hash function for multiple purposes:
|
||||
* Key derivation during and after the handshake
|
||||
* Computing the additional data for the biscuit encryption, to provide some privacy for its contents
|
||||
|
||||
Recall from Section \ref{hash} that rosenpass supports using either BLAKE2s or SHAKE256 as hash function, which can be configured for each peer ID. However, as noted above, rosenpass uses a hash function to compute the peer ID and thus also to access the configuration for a peer ID. This is an issue when receiving an `InitHello`-message, because the correct hash function is not known when a responder receives this message and at the same the responders needs it in order to compute the peer ID and by that also identfy the hash function for that peer. The reference implementation resolves this issue by first trying to derive the peer ID using SHAKE256. If that does not work (i.e. leads to an AEAD decryption error), the reference implementation tries again with BLAKE2s. The reference implementation verifies that the hash function matches the one confgured for the peer. Similarly, if the correct peer ID is not cached when receiving an InitConf message, the reference implementation proceeds in the same manner.
|
||||
|
||||
Using one hash function for multiple purposes can cause real-world security issues and even key recovery attacks [@oraclecloning]. We choose a tree-based domain separation scheme based on a keyed hash function – the previously introduced primitive `hash` – to make sure all our hash function calls can be seen as distinct.
|
||||
|
||||
\setupimage{landscape,fullpage,label=img:HashingTree}
|
||||
@@ -179,13 +184,13 @@ Using one hash function for multiple purposes can cause real-world security issu
|
||||
|
||||
Each tree node $\circ{}$ in Figure 3 represents the application of the keyed hash function, using the previous chaining key value as first parameter. The root of the tree is the zero key. In level one, the `PROTOCOL` identifier is applied to the zero key to generate a label unique across cryptographic protocols (unless the same label is deliberately used elsewhere). In level two, purpose identifiers are applied to the protocol label to generate labels to use with each separate hash function application within the Rosenpass protocol. The following layers contain the inputs used in each separate usage of the hash function: Beneath the identifiers `"mac"`, `"cookie"`, `"peer id"`, and `"biscuit additional data"` are hash functions or message authentication codes with a small number of inputs. The second, third, and fourth column in Figure 3 cover the long sequential branch beneath the identifier `"chaining key init"` representing the entire protocol execution, one column for each message processed during the handshake. The leaves beneath `"chaining key extract"` in the left column represent pseudo-random labels for use when extracting values from the chaining key during the protocol execution. These values such as `mix >` appear as outputs in the left column, and then as inputs `< mix` in the other three columns.
|
||||
|
||||
The protocol identifier is defined as follows:
|
||||
The protocol identifier depends on the hash function used with the respective peer is defined as follows if BLAKE2s [@rfc_blake2] is used:
|
||||
|
||||
```pseudorust
|
||||
PROTOCOL = "rosenpass 1 rosenpass.eu aead=chachapoly1305 hash=blake2s ekem=kyber512 skem=mceliece460896 xaead=xchachapoly1305"
|
||||
```
|
||||
|
||||
Since every tree node represents a sequence of `hash` calls, the node beneath `"handshake encryption"` called `hs_enc` can be written as follows:
|
||||
If SHAKE256 [@SHAKE256] is used, `blake2s` is replaced by `shake256` in `PROTOCOL`. Since every tree node represents a sequence of `hash` calls, the node beneath `"handshake encryption"` called `hs_enc` can be written as follows:
|
||||
|
||||
```pseudorust
|
||||
hs_enc = hash(hash(hash(0, PROTOCOL), "chaining key extract"), "handshake encryption")
|
||||
@@ -233,6 +238,7 @@ For each peer, the server stores:
|
||||
* `psk` – The pre-shared key used with the peer
|
||||
* `spkt` – The peer's public key
|
||||
* `biscuit_used` – The `biscuit_no` from the last biscuit accepted for the peer as part of InitConf processing
|
||||
* `hash_function` – The hash function, SHAKE256 or BLAKE2s, used with the peer.
|
||||
|
||||
### Handshake State and Biscuits
|
||||
|
||||
@@ -452,14 +458,14 @@ For an initiator, Rosenpass ignores all messages when under load.
|
||||
|
||||
#### Cookie Reply Message
|
||||
|
||||
The cookie reply message is sent by the responder on receiving an InitHello message when under load. It consists of the `sidi` of the initiator, a random 24-byte bitstring `nonce` and encrypting `cookie_value` into a `cookie_encrypted` reply field which consists of the following:
|
||||
The cookie reply message is sent by the responder on receiving an InitHello message when under load. It consists of the `sidi` of the initiator, a random 24-byte bitstring `nonce` and encrypting `cookie_value` into a `cookie_encrypted` reply field, which consists of the following:
|
||||
|
||||
```pseudorust
|
||||
cookie_value = lhash("cookie-value", cookie_secret, initiator_host_info)[0..16]
|
||||
cookie_encrypted = XAEAD(lhash("cookie-key", spkm), nonce, cookie_value, mac_peer)
|
||||
```
|
||||
|
||||
where `cookie_secret` is a secret variable that changes every two minutes to a random value. `initiator_host_info` is used to identify the initiator host, and is implementation-specific for the client. This paramaters used to identify the host must be carefully chosen to ensure there is a unique mapping, especially when using IPv4 and IPv6 addresses to identify the host (such as taking care of IPv6 link-local addresses). `cookie_value` is a truncated 16 byte value from the above hash operation. `mac_peer` is the `mac` field of the peer's handshake message to which message is the reply.
|
||||
where `cookie_secret` is a secret variable that changes every two minutes to a random value. Moreover, `lhash` is always instantiated with SHAKE256 when computing `cookie_value` for compatability reasons. `initiator_host_info` is used to identify the initiator host, and is implementation-specific for the client. This paramaters used to identify the host must be carefully chosen to ensure there is a unique mapping, especially when using IPv4 and IPv6 addresses to identify the host (such as taking care of IPv6 link-local addresses). `cookie_value` is a truncated 16 byte value from the above hash operation. `mac_peer` is the `mac` field of the peer's handshake message to which message is the reply.
|
||||
|
||||
#### Envelope `mac` Field
|
||||
|
||||
@@ -495,7 +501,7 @@ However, when the responder is under load, it may reject InitHello messages with
|
||||
|
||||
This whitepaper does not mandate any specific mechanism to detect responder contention (also mentioned as the under load condition) that would trigger use of the cookie mechanism.
|
||||
|
||||
For the reference implemenation, Rosenpass has derived inspiration from the linux implementation of Wireguard. This implementation suggests that the reciever keep track of the number of messages it is processing at a given time.
|
||||
For the reference implemenation, Rosenpass has derived inspiration from the Linux implementation of Wireguard. This implementation suggests that the reciever keep track of the number of messages it is processing at a given time.
|
||||
|
||||
On receiving an incoming message, if the length of the message queue to be processed exceeds a threshold `MAX_QUEUED_INCOMING_HANDSHAKES_THRESHOLD`, the client is considered under load and its state is stored as under load. In addition, the timestamp of this instant when the client was last under load is stored. When recieving subsequent messages, if the client is still in an under load state, the client will check if the time ellpased since the client was last under load has exceeded `LAST_UNDER_LOAD_WINDOW` seconds. If this is the case, the client will update its state to normal operation, and process the message in a normal fashion.
|
||||
|
||||
@@ -526,6 +532,24 @@ When the responder is under load and it recieves an InitConf message, the messag
|
||||
|
||||
### 0.3.x
|
||||
|
||||
#### 2025-05-22 - SHAKE256 keyed hash
|
||||
\vspace{0.5em}
|
||||
|
||||
Author: David Niehues
|
||||
PR: [#653](https://github.com/rosenpass/rosenpass/pull/653)
|
||||
|
||||
\vspace{0.5em}
|
||||
|
||||
We document the support for SHAKE256 with prepended key as an alternative to BLAKE2s with HMAC.
|
||||
|
||||
Previously, BLAKE2s with HMAC was the only supported keyed hash function. Recently, SHAKE256 was added as an option. SHAKE256 is used as a keyed hash function by prepending the key to the variable-length data and then evaluating SHAKE256.
|
||||
In order to maintain compatablity without introducing an explcit version number in the protocol messages, SHAKE256 is truncated to 32 bytes. In the update to the whitepaper, we explain where and how SHAKE256 is used. That is:
|
||||
|
||||
1. We explain that SHAKE256 or BLAKE2s can be configured to be used on a peer basis.
|
||||
2. We explain under which circumstances, the reference implementation tries both hash functions for messages in order to determine the correct hash function.
|
||||
3. We document that the cookie mechanism always uses SHAKE256.
|
||||
|
||||
|
||||
#### 2024-10-30 – InitConf retransmission updates
|
||||
|
||||
\vspace{0.5em}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
{ runCommand, dpkg, rosenpass }:
|
||||
{
|
||||
runCommand,
|
||||
dpkg,
|
||||
rosenpass,
|
||||
}:
|
||||
|
||||
let
|
||||
inherit (rosenpass) version;
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
{ lib, system, runCommand, rosenpass, rpm }:
|
||||
{
|
||||
lib,
|
||||
system,
|
||||
runCommand,
|
||||
rosenpass,
|
||||
rpm,
|
||||
}:
|
||||
|
||||
let
|
||||
splitVersion = lib.strings.splitString "-" rosenpass.version;
|
||||
version = builtins.head splitVersion;
|
||||
release =
|
||||
if builtins.length splitVersion != 2
|
||||
then "release"
|
||||
else builtins.elemAt splitVersion 1;
|
||||
release = if builtins.length splitVersion != 2 then "release" else builtins.elemAt splitVersion 1;
|
||||
arch = builtins.head (builtins.split "-" system);
|
||||
in
|
||||
|
||||
|
||||
@@ -1,21 +1,24 @@
|
||||
{ lib, stdenvNoCC, runCommandNoCC, pkgsStatic, rosenpass, rosenpass-oci-image, rp } @ args:
|
||||
{
|
||||
lib,
|
||||
stdenvNoCC,
|
||||
runCommandNoCC,
|
||||
pkgsStatic,
|
||||
rosenpass,
|
||||
rosenpass-oci-image,
|
||||
rp,
|
||||
}@args:
|
||||
|
||||
let
|
||||
version = rosenpass.version;
|
||||
|
||||
# select static packages on Linux, default packages otherwise
|
||||
package =
|
||||
if stdenvNoCC.hostPlatform.isLinux then
|
||||
pkgsStatic.rosenpass
|
||||
else args.rosenpass;
|
||||
rp =
|
||||
if stdenvNoCC.hostPlatform.isLinux then
|
||||
pkgsStatic.rp
|
||||
else args.rp;
|
||||
package = if stdenvNoCC.hostPlatform.isLinux then pkgsStatic.rosenpass else args.rosenpass;
|
||||
rp = if stdenvNoCC.hostPlatform.isLinux then pkgsStatic.rp else args.rp;
|
||||
oci-image =
|
||||
if stdenvNoCC.hostPlatform.isLinux then
|
||||
pkgsStatic.rosenpass-oci-image
|
||||
else args.rosenpass-oci-image;
|
||||
else
|
||||
args.rosenpass-oci-image;
|
||||
in
|
||||
runCommandNoCC "lace-result" { } ''
|
||||
mkdir {bin,$out}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
{ dockerTools, buildEnv, rosenpass }:
|
||||
{
|
||||
dockerTools,
|
||||
buildEnv,
|
||||
rosenpass,
|
||||
}:
|
||||
|
||||
dockerTools.buildImage {
|
||||
name = rosenpass.name + "-oci";
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
{ lib, stdenv, rustPlatform, cmake, mandoc, removeReferencesTo, bash, package ? "rosenpass" }:
|
||||
{
|
||||
lib,
|
||||
stdenv,
|
||||
rustPlatform,
|
||||
cmake,
|
||||
mandoc,
|
||||
removeReferencesTo,
|
||||
bash,
|
||||
package ? "rosenpass",
|
||||
}:
|
||||
|
||||
let
|
||||
# whether we want to build a statically linked binary
|
||||
@@ -17,24 +26,30 @@ let
|
||||
"toml"
|
||||
];
|
||||
# Files to explicitly include
|
||||
files = [
|
||||
"to/README.md"
|
||||
];
|
||||
files = [ "to/README.md" ];
|
||||
|
||||
src = ../.;
|
||||
filter = (path: type: scoped rec {
|
||||
inherit (lib) any id removePrefix hasSuffix;
|
||||
anyof = (any id);
|
||||
filter = (
|
||||
path: type:
|
||||
scoped rec {
|
||||
inherit (lib)
|
||||
any
|
||||
id
|
||||
removePrefix
|
||||
hasSuffix
|
||||
;
|
||||
anyof = (any id);
|
||||
|
||||
basename = baseNameOf (toString path);
|
||||
relative = removePrefix (toString src + "/") (toString path);
|
||||
basename = baseNameOf (toString path);
|
||||
relative = removePrefix (toString src + "/") (toString path);
|
||||
|
||||
result = anyof [
|
||||
(type == "directory")
|
||||
(any (ext: hasSuffix ".${ext}" basename) extensions)
|
||||
(any (file: file == relative) files)
|
||||
];
|
||||
});
|
||||
result = anyof [
|
||||
(type == "directory")
|
||||
(any (ext: hasSuffix ".${ext}" basename) extensions)
|
||||
(any (file: file == relative) files)
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
result = lib.sources.cleanSourceWith { inherit src filter; };
|
||||
};
|
||||
@@ -47,8 +62,14 @@ rustPlatform.buildRustPackage {
|
||||
version = cargoToml.package.version;
|
||||
inherit src;
|
||||
|
||||
cargoBuildOptions = [ "--package" package ];
|
||||
cargoTestOptions = [ "--package" package ];
|
||||
cargoBuildOptions = [
|
||||
"--package"
|
||||
package
|
||||
];
|
||||
cargoTestOptions = [
|
||||
"--package"
|
||||
package
|
||||
];
|
||||
|
||||
doCheck = true;
|
||||
|
||||
@@ -58,6 +79,7 @@ rustPlatform.buildRustPackage {
|
||||
"memsec-0.6.3" = "sha256-4ri+IEqLd77cLcul3lZrmpDKj4cwuYJ8oPRAiQNGeLw=";
|
||||
"uds-0.4.2" = "sha256-qlxr/iJt2AV4WryePIvqm/8/MK/iqtzegztNliR93W8=";
|
||||
"libcrux-blake2-0.0.3-pre" = "sha256-0CLjuzwJqGooiODOHf5D8Hc8ClcG/XcGvVGyOVnLmJY=";
|
||||
"libcrux-macros-0.0.3" = "sha256-Tb5uRirwhRhoFEK8uu1LvXl89h++40pxzZ+7kXe8RAI=";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -81,7 +103,10 @@ rustPlatform.buildRustPackage {
|
||||
|
||||
meta = {
|
||||
inherit (cargoToml.package) description homepage;
|
||||
license = with lib.licenses; [ mit asl20 ];
|
||||
license = with lib.licenses; [
|
||||
mit
|
||||
asl20
|
||||
];
|
||||
maintainers = [ lib.maintainers.wucke13 ];
|
||||
platforms = lib.platforms.all;
|
||||
};
|
||||
|
||||
@@ -1,13 +1,52 @@
|
||||
{ stdenvNoCC, texlive, ncurses, python3Packages, which }:
|
||||
{
|
||||
stdenvNoCC,
|
||||
texlive,
|
||||
ncurses,
|
||||
python3Packages,
|
||||
which,
|
||||
}:
|
||||
|
||||
let
|
||||
customTexLiveSetup = (texlive.combine {
|
||||
inherit (texlive) acmart amsfonts biber biblatex biblatex-software
|
||||
biblatex-trad ccicons csquotes csvsimple doclicense eso-pic fancyvrb
|
||||
fontspec gitinfo2 gobble ifmtarg koma-script latexmk lm lualatex-math
|
||||
markdown mathtools minted noto nunito paralist pgf scheme-basic soul
|
||||
unicode-math upquote xifthen xkeyval xurl;
|
||||
});
|
||||
customTexLiveSetup = (
|
||||
texlive.combine {
|
||||
inherit (texlive)
|
||||
acmart
|
||||
amsfonts
|
||||
biber
|
||||
biblatex
|
||||
biblatex-software
|
||||
biblatex-trad
|
||||
ccicons
|
||||
csquotes
|
||||
csvsimple
|
||||
doclicense
|
||||
eso-pic
|
||||
fancyvrb
|
||||
fontspec
|
||||
gitinfo2
|
||||
gobble
|
||||
ifmtarg
|
||||
koma-script
|
||||
latexmk
|
||||
lm
|
||||
lualatex-math
|
||||
markdown
|
||||
mathtools
|
||||
minted
|
||||
noto
|
||||
nunito
|
||||
paralist
|
||||
pgf
|
||||
scheme-basic
|
||||
soul
|
||||
unicode-math
|
||||
upquote
|
||||
xifthen
|
||||
xkeyval
|
||||
xurl
|
||||
;
|
||||
}
|
||||
);
|
||||
in
|
||||
stdenvNoCC.mkDerivation {
|
||||
name = "whitepaper";
|
||||
|
||||
49
readme.md
49
readme.md
@@ -14,7 +14,7 @@ This repository contains
|
||||
|
||||
## Getting started
|
||||
|
||||
First, [install rosenpass](#Getting-Rosenpass). Then, check out the help functions of `rp` & `rosenpass`:
|
||||
First, [install rosenpass](#getting-rosenpass). Then, check out the help functions of `rp` & `rosenpass`:
|
||||
|
||||
```sh
|
||||
rp help
|
||||
@@ -64,11 +64,7 @@ The analysis is implemented according to modern software engineering principles:
|
||||
The code uses a variety of optimizations to speed up analysis such as using secret functions to model trusted/malicious setup. We split the model into two separate entry points which can be analyzed in parallel. Each is much faster than both models combined.
|
||||
A wrapper script provides instant feedback about which queries execute as expected in color: A red cross if a query fails and a green check if it succeeds.
|
||||
|
||||
[^liboqs]: https://openquantumsafe.org/liboqs/
|
||||
[^wg]: https://www.wireguard.com/
|
||||
[^pqwg]: https://eprint.iacr.org/2020/379
|
||||
[^pqwg-statedis]: Unless supplied with a pre-shared-key, but this defeats the purpose of a key exchange protocol
|
||||
[^wg-statedis]: https://lists.zx2c4.com/pipermail/wireguard/2021-August/006916.htmlA
|
||||
[^liboqs]: <https://openquantumsafe.org/liboqs/>
|
||||
|
||||
# Getting Rosenpass
|
||||
|
||||
@@ -87,6 +83,47 @@ Rosenpass is also available as prebuilt Docker images:
|
||||
|
||||
For details on how to use these images, refer to the [Docker usage guide](docker/USAGE.md).
|
||||
|
||||
## Benchmarks
|
||||
|
||||
This repository contains facilities for benchmarking both the Rosenpass
|
||||
protocol code and the implementations of the cryptographic primitives used
|
||||
by it. The primitives are benchmarked using criterion. For the protocol code
|
||||
benchmarks we use a library for instrumenting the code such that events are
|
||||
written to a trace, which is then inspected after a run.
|
||||
|
||||
Benchmarks are automatically run on CI. The measurements are visualized in the
|
||||
[Benchmark Dashboard].
|
||||
|
||||
[Benchmark Dashboard]: https://rosenpass.github.io/rosenpass/benchmarks
|
||||
|
||||
### Primitive Benchmarks
|
||||
|
||||
There are benchmarks for the functions of the traits `Kem`, `Aead` and
|
||||
`KeyedHash`. They are run for all implementations in the `primitives`
|
||||
benchmark of `rosenpass-ciphers`. Run the benchmarks and view their results using
|
||||
|
||||
```
|
||||
cargo bench -p rosenpass-ciphers --bench primitives -F bench
|
||||
```
|
||||
|
||||
Note that the `bench` feature enables the inclusion of the libcrux-backed
|
||||
trait implementations in the module tree, but does not enable them
|
||||
as default.
|
||||
|
||||
### Protocol Benchmarks
|
||||
|
||||
The trace that is being written to lives in a new module
|
||||
`trace_bench` in the util crate. A basic benchmark that
|
||||
performs some minor statistical analysis of the trace can be run using
|
||||
|
||||
```
|
||||
cargo bench -p rosenpass --bench trace_handshake -F trace_bench
|
||||
```
|
||||
|
||||
This runs the benchmarks and prints the results in machine-readable JSON.
|
||||
|
||||
---
|
||||
|
||||
# Mirrors
|
||||
|
||||
Don't want to use GitHub or only have an IPv6 connection? Rosenpass has set up two mirrors for this:
|
||||
|
||||
@@ -8,6 +8,7 @@ description = "Build post-quantum-secure VPNs with WireGuard!"
|
||||
homepage = "https://rosenpass.eu/"
|
||||
repository = "https://github.com/rosenpass/rosenpass"
|
||||
readme = "readme.md"
|
||||
rust-version = "1.77.0"
|
||||
|
||||
[[bin]]
|
||||
name = "rosenpass"
|
||||
@@ -29,11 +30,16 @@ required-features = ["experiment_api", "internal_testing"]
|
||||
[[test]]
|
||||
name = "gen-ipc-msg-types"
|
||||
required-features = [
|
||||
"experiment_api",
|
||||
"internal_testing",
|
||||
"internal_bin_gen_ipc_msg_types",
|
||||
"experiment_api",
|
||||
"internal_testing",
|
||||
"internal_bin_gen_ipc_msg_types",
|
||||
]
|
||||
|
||||
[[bench]]
|
||||
name = "trace_handshake"
|
||||
harness = false
|
||||
required-features = ["trace_bench"]
|
||||
|
||||
[[bench]]
|
||||
name = "handshake"
|
||||
harness = false
|
||||
@@ -71,6 +77,7 @@ command-fds = { workspace = true, optional = true }
|
||||
rustix = { workspace = true, optional = true }
|
||||
uds = { workspace = true, optional = true, features = ["mio_1xx"] }
|
||||
signal-hook = { workspace = true, optional = true }
|
||||
libcrux-test-utils = { workspace = true, optional = true }
|
||||
|
||||
[build-dependencies]
|
||||
anyhow = { workspace = true }
|
||||
@@ -91,20 +98,21 @@ experiment_memfd_secret = ["rosenpass-wireguard-broker/experiment_memfd_secret"]
|
||||
experiment_libcrux_all = ["rosenpass-ciphers/experiment_libcrux_all"]
|
||||
experiment_libcrux_blake2 = ["rosenpass-ciphers/experiment_libcrux_blake2"]
|
||||
experiment_libcrux_chachapoly = [
|
||||
"rosenpass-ciphers/experiment_libcrux_chachapoly",
|
||||
"rosenpass-ciphers/experiment_libcrux_chachapoly",
|
||||
]
|
||||
experiment_libcrux_kyber = ["rosenpass-ciphers/experiment_libcrux_kyber"]
|
||||
experiment_api = [
|
||||
"hex-literal",
|
||||
"uds",
|
||||
"command-fds",
|
||||
"rustix",
|
||||
"rosenpass-util/experiment_file_descriptor_passing",
|
||||
"rosenpass-wireguard-broker/experiment_api",
|
||||
"hex-literal",
|
||||
"uds",
|
||||
"command-fds",
|
||||
"rustix",
|
||||
"rosenpass-util/experiment_file_descriptor_passing",
|
||||
"rosenpass-wireguard-broker/experiment_api",
|
||||
]
|
||||
internal_signal_handling_for_coverage_reports = ["signal-hook"]
|
||||
internal_testing = []
|
||||
internal_bin_gen_ipc_msg_types = ["hex", "heck"]
|
||||
trace_bench = ["rosenpass-util/trace_bench", "dep:libcrux-test-utils"]
|
||||
|
||||
[lints.rust]
|
||||
unexpected_cfgs = { level = "allow", check-cfg = ['cfg(coverage)'] }
|
||||
|
||||
386
rosenpass/benches/trace_handshake.rs
Normal file
386
rosenpass/benches/trace_handshake.rs
Normal file
@@ -0,0 +1,386 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
hint::black_box,
|
||||
io::{self, Write},
|
||||
ops::DerefMut,
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use libcrux_test_utils::tracing::{EventType, Trace as _};
|
||||
|
||||
use rosenpass_cipher_traits::primitives::Kem;
|
||||
use rosenpass_ciphers::StaticKem;
|
||||
use rosenpass_secret_memory::secret_policy_try_use_memfd_secrets;
|
||||
use rosenpass_util::trace_bench::RpEventType;
|
||||
|
||||
use rosenpass::protocol::{
|
||||
CryptoServer, HandleMsgResult, MsgBuf, PeerPtr, ProtocolVersion, SPk, SSk, SymKey,
|
||||
};
|
||||
|
||||
const ITERATIONS: usize = 100;
|
||||
|
||||
/// Performs a full protocol run by processing a message and recursing into handling that message,
|
||||
/// until no further response is produced. Returns the keys produce by the two parties.
|
||||
///
|
||||
/// Ensures that each party produces one of the two keys.
|
||||
fn handle(
|
||||
tx: &mut CryptoServer,
|
||||
msgb: &mut MsgBuf,
|
||||
msgl: usize,
|
||||
rx: &mut CryptoServer,
|
||||
resb: &mut MsgBuf,
|
||||
) -> Result<(Option<SymKey>, Option<SymKey>)> {
|
||||
let HandleMsgResult {
|
||||
exchanged_with: xch,
|
||||
resp,
|
||||
} = rx.handle_msg(&msgb[..msgl], &mut **resb)?;
|
||||
|
||||
assert!(matches!(xch, None | Some(PeerPtr(0))));
|
||||
|
||||
let xch = xch.map(|p| rx.osk(p).unwrap());
|
||||
|
||||
let (rxk, txk) = resp
|
||||
.map(|resl| handle(rx, resb, resl, tx, msgb))
|
||||
.transpose()?
|
||||
.unwrap_or((None, None));
|
||||
|
||||
assert!(rxk.is_none() || xch.is_none());
|
||||
|
||||
Ok((txk, rxk.or(xch)))
|
||||
}
|
||||
|
||||
/// Performs the full handshake by calling `handle` with the correct values, based on just two
|
||||
/// `CryptoServer`s.
|
||||
///
|
||||
/// Ensures that both parties compute the same keys.
|
||||
fn hs(ini: &mut CryptoServer, res: &mut CryptoServer) -> Result<()> {
|
||||
let (mut inib, mut resb) = (MsgBuf::zero(), MsgBuf::zero());
|
||||
let sz = ini.initiate_handshake(PeerPtr(0), &mut *inib)?;
|
||||
let (kini, kres) = handle(ini, &mut inib, sz, res, &mut resb)?;
|
||||
assert!(kini.unwrap().secret() == kres.unwrap().secret());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Generates a new key pair.
|
||||
fn keygen() -> Result<(SSk, SPk)> {
|
||||
let (mut sk, mut pk) = (SSk::zero(), SPk::zero());
|
||||
StaticKem.keygen(sk.secret_mut(), pk.deref_mut())?;
|
||||
Ok((sk, pk))
|
||||
}
|
||||
|
||||
/// Creates two instanves of `CryptoServer`, generating key pairs for each.
|
||||
fn make_server_pair(protocol_version: ProtocolVersion) -> Result<(CryptoServer, CryptoServer)> {
|
||||
let psk = SymKey::random();
|
||||
let ((ska, pka), (skb, pkb)) = (keygen()?, keygen()?);
|
||||
let (mut a, mut b) = (
|
||||
CryptoServer::new(ska, pka.clone()),
|
||||
CryptoServer::new(skb, pkb.clone()),
|
||||
);
|
||||
a.add_peer(Some(psk.clone()), pkb, protocol_version.clone())?;
|
||||
b.add_peer(Some(psk), pka, protocol_version)?;
|
||||
Ok((a, b))
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let trace = rosenpass_util::trace_bench::trace();
|
||||
|
||||
// Attempt to use memfd_secrets for storing sensitive key material
|
||||
secret_policy_try_use_memfd_secrets();
|
||||
|
||||
// Run protocol for V02
|
||||
let (mut a_v02, mut b_v02) = make_server_pair(ProtocolVersion::V02).unwrap();
|
||||
for _ in 0..ITERATIONS {
|
||||
hs(black_box(&mut a_v02), black_box(&mut b_v02)).unwrap();
|
||||
}
|
||||
|
||||
// Emit a marker event to separate V02 and V03 trace sections
|
||||
trace.emit_on_the_fly("start-hs-v03");
|
||||
|
||||
// Run protocol for V03
|
||||
let (mut a_v03, mut b_v03) = make_server_pair(ProtocolVersion::V03).unwrap();
|
||||
for _ in 0..ITERATIONS {
|
||||
hs(black_box(&mut a_v03), black_box(&mut b_v03)).unwrap();
|
||||
}
|
||||
|
||||
// Collect the trace events generated during the handshakes
|
||||
let trace: Vec<_> = trace.clone().report();
|
||||
|
||||
// Split the trace into V02 and V03 sections based on the marker
|
||||
let (trace_v02, trace_v03) = {
|
||||
let cutoff = trace
|
||||
.iter()
|
||||
.position(|entry| entry.label == "start-hs-v03")
|
||||
.unwrap();
|
||||
// Exclude the marker itself from the V03 trace
|
||||
let (v02, v03_with_marker) = trace.split_at(cutoff);
|
||||
(v02, &v03_with_marker[1..])
|
||||
};
|
||||
|
||||
// Perform statistical analysis on both trace sections and write results as JSON
|
||||
write_json_arrays(
|
||||
&mut std::io::stdout(), // Write to standard output
|
||||
vec![
|
||||
("V02", statistical_analysis(trace_v02.to_vec())),
|
||||
("V03", statistical_analysis(trace_v03.to_vec())),
|
||||
],
|
||||
)
|
||||
.expect("error writing json data");
|
||||
}
|
||||
|
||||
/// Performs a simple statistical analysis:
|
||||
/// - bins trace events by label
|
||||
/// - extracts durations of spamns
|
||||
/// - filters out empty bins
|
||||
/// - calculates aggregate statistics (mean, std dev)
|
||||
fn statistical_analysis(trace: Vec<RpEventType>) -> Vec<(&'static str, AggregateStat<Duration>)> {
|
||||
bin_events(trace)
|
||||
.into_iter()
|
||||
.map(|(label, spans)| (label, extract_span_durations(label, spans.as_slice())))
|
||||
.filter(|(_, durations)| !durations.is_empty())
|
||||
.map(|(label, durations)| (label, AggregateStat::analyze_durations(&durations)))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Takes an iterator of ("protocol_version", iterator_of_stats) pairs and writes them
|
||||
/// as a single flat JSON array to the provided writer.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `w` - The writer to output JSON to (e.g., stdout, file).
|
||||
/// * `item_groups` - An iterator producing tuples `(version, stats): (&'static str, II)`.
|
||||
/// Here `II` is itself an iterator producing `(label, agg_stat): (&'static str, AggregateStat<Duration>)`,
|
||||
/// where the label is the label of the span, e.g. "IHI2".
|
||||
///
|
||||
/// # Type Parameters
|
||||
/// * `W` - A type that implements `std::io::Write`.
|
||||
/// * `II` - An iterator type yielding (`&'static str`, `AggregateStat<Duration>`).
|
||||
fn write_json_arrays<W: Write, II: IntoIterator<Item = (&'static str, AggregateStat<Duration>)>>(
|
||||
w: &mut W,
|
||||
item_groups: impl IntoIterator<Item = (&'static str, II)>,
|
||||
) -> io::Result<()> {
|
||||
// Flatten the groups into a single iterator of (protocol_version, label, stats)
|
||||
let iter = item_groups.into_iter().flat_map(|(version, items)| {
|
||||
items
|
||||
.into_iter()
|
||||
.map(move |(label, agg_stat)| (version, label, agg_stat))
|
||||
});
|
||||
let mut delim = ""; // Start with no delimiter
|
||||
|
||||
// Start the JSON array
|
||||
write!(w, "[")?;
|
||||
|
||||
// Write the flattened statistics as JSON objects, separated by commas.
|
||||
for (version, label, agg_stat) in iter {
|
||||
write!(w, "{delim}")?; // Write delimiter (empty for first item, "," for subsequent)
|
||||
agg_stat.write_json_ns(label, version, w)?; // Write the JSON object for the stat entry
|
||||
delim = ","; // Set delimiter for the next iteration
|
||||
}
|
||||
|
||||
// End the JSON array
|
||||
write!(w, "]")
|
||||
}
|
||||
|
||||
/// Used to group benchmark results in visualizations
|
||||
enum RunTimeGroup {
|
||||
/// For particularly long operations.
|
||||
Long,
|
||||
/// Operations of moderate duration.
|
||||
Medium,
|
||||
/// Operations expected to complete under a millisecond.
|
||||
BelowMillisec,
|
||||
/// Very fast operations, likely under a microsecond.
|
||||
BelowMicrosec,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for RunTimeGroup {
|
||||
/// Used when writing the group information to JSON output.
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let txt = match self {
|
||||
RunTimeGroup::Long => "long",
|
||||
RunTimeGroup::Medium => "medium",
|
||||
RunTimeGroup::BelowMillisec => "below 1ms",
|
||||
RunTimeGroup::BelowMicrosec => "below 1us",
|
||||
};
|
||||
write!(f, "{txt}")
|
||||
}
|
||||
}
|
||||
|
||||
/// Maps specific internal timing labels (likely from rosenpass internals)
|
||||
/// to the broader SpanGroup categories.
|
||||
fn run_time_group(label: &str) -> RunTimeGroup {
|
||||
match label {
|
||||
// Explicitly categorized labels based on expected performance characteristics
|
||||
"handle_init_hello" | "handle_resp_hello" | "RHI5" | "IHR5" => RunTimeGroup::Long,
|
||||
"RHR1" | "IHI2" | "ICR6" => RunTimeGroup::BelowMicrosec,
|
||||
"RHI6" | "ICI7" | "ICR7" | "RHR3" | "ICR3" | "IHR8" | "ICI4" | "RHI3" | "RHI4" | "RHR4"
|
||||
| "RHR7" | "ICI3" | "IHI3" | "IHI8" | "ICR2" | "ICR4" | "IHR4" | "IHR6" | "IHI4"
|
||||
| "RHI7" => RunTimeGroup::BelowMillisec,
|
||||
// Default protocol_version for any other labels
|
||||
_ => RunTimeGroup::Medium,
|
||||
}
|
||||
}
|
||||
|
||||
/// Used temporarily within `extract_span_durations` to track open spans
|
||||
/// and calculated durations.
|
||||
#[derive(Debug, Clone)]
|
||||
enum StatEntry {
|
||||
/// Represents an unmatched SpanOpen event with its timestamp.
|
||||
Start(Instant),
|
||||
/// Represents a completed span with its calculated duration.
|
||||
Duration(Duration),
|
||||
}
|
||||
|
||||
/// Takes a flat list of events and organizes them into a HashMap where keys
|
||||
/// are event labels and values are vectors of events with that label.
|
||||
fn bin_events(events: Vec<RpEventType>) -> HashMap<&'static str, Vec<RpEventType>> {
|
||||
let mut spans = HashMap::<_, Vec<_>>::new();
|
||||
for event in events {
|
||||
// Get the vector for the event's label, or create a new one
|
||||
let spans_for_label = spans.entry(event.label).or_default();
|
||||
// Add the event to the vector
|
||||
spans_for_label.push(event);
|
||||
}
|
||||
spans
|
||||
}
|
||||
|
||||
/// Processes a list of events (assumed to be for the same label), matching
|
||||
/// `SpanOpen` and `SpanClose` events to calculate the duration of each span.
|
||||
/// It handles potentially interleaved spans correctly.
|
||||
fn extract_span_durations(label: &str, events: &[RpEventType]) -> Vec<Duration> {
|
||||
let mut processing_list: Vec<StatEntry> = vec![]; // List to track open spans and final durations
|
||||
|
||||
for entry in events {
|
||||
match &entry.ty {
|
||||
EventType::SpanOpen => {
|
||||
// Record the start time of a new span
|
||||
processing_list.push(StatEntry::Start(entry.at));
|
||||
}
|
||||
EventType::SpanClose => {
|
||||
// Find the most recent unmatched 'Start' entry
|
||||
let start_index = processing_list
|
||||
.iter()
|
||||
.rposition(|span| matches!(span, StatEntry::Start(_))); // Find last Start
|
||||
|
||||
match start_index {
|
||||
Some(index) => {
|
||||
// Retrieve the start time
|
||||
let start_time = match processing_list[index] {
|
||||
StatEntry::Start(t) => t,
|
||||
_ => unreachable!(), // Should always be Start based on rposition logic
|
||||
};
|
||||
// Calculate duration and replace the 'Start' entry with 'Duration'
|
||||
processing_list[index] = StatEntry::Duration(entry.at - start_time);
|
||||
}
|
||||
None => {
|
||||
// This should not happen with well-formed traces
|
||||
eprintln!(
|
||||
"Warning: Found SpanClose without a matching SpanOpen for label '{}': {:?}",
|
||||
label, entry
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
EventType::OnTheFly => {
|
||||
// Ignore OnTheFly events for duration calculation
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Collect all calculated durations, reporting any unmatched starts
|
||||
processing_list
|
||||
.into_iter()
|
||||
.filter_map(|span| match span {
|
||||
StatEntry::Start(at) => {
|
||||
// Report error if a span was opened but never closed
|
||||
eprintln!(
|
||||
"Warning: Unmatched SpanOpen at {:?} for label '{}'",
|
||||
at, label
|
||||
);
|
||||
None // Discard unmatched starts
|
||||
}
|
||||
StatEntry::Duration(dur) => Some(dur), // Keep calculated durations
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Stores the mean, standard deviation, relative standard deviation (sd/mean),
|
||||
/// and the number of samples used for calculation.
|
||||
#[derive(Debug)]
|
||||
struct AggregateStat<T> {
|
||||
/// Average duration.
|
||||
mean_duration: T,
|
||||
/// Standard deviation of durations.
|
||||
sd_duration: T,
|
||||
/// Standard deviation as a percentage of the mean.
|
||||
sd_by_mean: String,
|
||||
/// Number of duration measurements.
|
||||
sample_size: usize,
|
||||
}
|
||||
|
||||
impl AggregateStat<Duration> {
|
||||
/// Calculates mean, variance, and standard deviation for a slice of Durations.
|
||||
fn analyze_durations(durations: &[Duration]) -> Self {
|
||||
let sample_size = durations.len();
|
||||
assert!(sample_size > 0, "Cannot analyze empty duration slice");
|
||||
|
||||
// Calculate the sum of durations
|
||||
let sum: Duration = durations.iter().sum();
|
||||
// Calculate the mean duration
|
||||
let mean = sum / (sample_size as u32);
|
||||
|
||||
// Calculate mean in nanoseconds, adding 1 to avoid potential division by zero later
|
||||
// (though highly unlikely with realistic durations)
|
||||
let mean_ns = mean.as_nanos().saturating_add(1);
|
||||
|
||||
// Calculate variance (sum of squared differences from the mean) / N
|
||||
let variance = durations
|
||||
.iter()
|
||||
.map(Duration::as_nanos)
|
||||
.map(|d_ns| d_ns.abs_diff(mean_ns).pow(2)) // (duration_ns - mean_ns)^2
|
||||
.sum::<u128>() // Sum of squares
|
||||
/ (sample_size as u128); // Divide by sample size
|
||||
|
||||
// Calculate standard deviation (sqrt of variance)
|
||||
let sd_ns = (variance as f64).sqrt() as u128;
|
||||
let sd = Duration::from_nanos(sd_ns as u64); // Convert back to Duration
|
||||
|
||||
// Calculate relative standard deviation (sd / mean) as a percentage string
|
||||
let sd_rel_permille = (10000 * sd_ns).checked_div(mean_ns).unwrap_or(0); // Calculate sd/mean * 10000
|
||||
let sd_rel_formatted = format!("{}.{:02}%", sd_rel_permille / 100, sd_rel_permille % 100);
|
||||
|
||||
AggregateStat {
|
||||
mean_duration: mean,
|
||||
sd_duration: sd,
|
||||
sd_by_mean: sd_rel_formatted,
|
||||
sample_size,
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes the statistics as a JSON object to the provided writer.
|
||||
/// Includes metadata like label, protocol_version, OS, architecture, and run time group.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `label` - The specific benchmark/span label.
|
||||
/// * `protocol_version` - Version of the protocol that is benchmarked.
|
||||
/// * `w` - The output writer (must implement `std::io::Write`).
|
||||
fn write_json_ns(
|
||||
&self,
|
||||
label: &str,
|
||||
protocol_version: &str,
|
||||
w: &mut impl io::Write,
|
||||
) -> io::Result<()> {
|
||||
// Format the JSON string using measured values and environment constants
|
||||
writeln!(
|
||||
w,
|
||||
r#"{{"name":"{name}", "unit":"ns/iter", "value":"{value}", "range":"± {range}", "protocol version":"{protocol_version}", "sample size":"{sample_size}", "operating system":"{os}", "architecture":"{arch}", "run time":"{run_time}"}}"#,
|
||||
name = label, // Benchmark name
|
||||
value = self.mean_duration.as_nanos(), // Mean duration in nanoseconds
|
||||
range = self.sd_duration.as_nanos(), // Standard deviation in nanoseconds
|
||||
sample_size = self.sample_size, // Number of samples
|
||||
os = std::env::consts::OS, // Operating system
|
||||
arch = std::env::consts::ARCH, // CPU architecture
|
||||
run_time = run_time_group(label), // Run time group category (long, medium, etc.)
|
||||
protocol_version = protocol_version // Overall protocol_version (e.g., protocol version)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,9 @@ use std::{
|
||||
};
|
||||
|
||||
use anyhow::{bail, ensure, Context, Result};
|
||||
use rand::Fill as Randomize;
|
||||
|
||||
#[cfg(feature = "trace_bench")]
|
||||
use rosenpass_util::trace_bench::Trace as _;
|
||||
|
||||
use crate::{hash_domains, msgs::*, RosenpassError};
|
||||
use memoffset::span_of;
|
||||
@@ -2259,6 +2261,7 @@ impl CryptoServer {
|
||||
&cookie_value,
|
||||
)?;
|
||||
|
||||
use rand::Fill;
|
||||
msg_out
|
||||
.padding
|
||||
.try_fill(&mut rosenpass_secret_memory::rand::rng())
|
||||
@@ -3547,47 +3550,80 @@ impl CryptoServer {
|
||||
}
|
||||
}
|
||||
|
||||
/// Marks a section of the protocol using the same identifiers as are used in the whitepaper.
|
||||
/// When building with the trace benchmarking feature enabled, this also emits span events into the
|
||||
/// trace, which allows reconstructing the run times of the individual sections for performance
|
||||
/// measurement.
|
||||
macro_rules! protocol_section {
|
||||
($label:expr, $body:block) => {{
|
||||
#[cfg(feature = "trace_bench")]
|
||||
let _span_guard = rosenpass_util::trace_bench::trace().emit_span($label);
|
||||
|
||||
#[allow(unused_braces)]
|
||||
$body
|
||||
}};
|
||||
}
|
||||
|
||||
impl CryptoServer {
|
||||
/// Core cryptographic protocol implementation: Kicks of the handshake
|
||||
/// on the initiator side, producing the InitHello message.
|
||||
pub fn handle_initiation(&mut self, peer: PeerPtr, ih: &mut InitHello) -> Result<PeerPtr> {
|
||||
#[cfg(feature = "trace_bench")]
|
||||
let _span_guard = rosenpass_util::trace_bench::trace().emit_span("handle_initiation");
|
||||
|
||||
let mut hs = InitiatorHandshake::zero_with_timestamp(
|
||||
self,
|
||||
peer.get(self).protocol_version.keyed_hash(),
|
||||
);
|
||||
|
||||
// IHI1
|
||||
hs.core.init(peer.get(self).spkt.deref())?;
|
||||
protocol_section!("IHI1", {
|
||||
hs.core.init(peer.get(self).spkt.deref())?;
|
||||
});
|
||||
|
||||
// IHI2
|
||||
hs.core.sidi.randomize();
|
||||
ih.sidi.copy_from_slice(&hs.core.sidi.value);
|
||||
protocol_section!("IHI2", {
|
||||
hs.core.sidi.randomize();
|
||||
ih.sidi.copy_from_slice(&hs.core.sidi.value);
|
||||
});
|
||||
|
||||
// IHI3
|
||||
EphemeralKem.keygen(hs.eski.secret_mut(), &mut *hs.epki)?;
|
||||
ih.epki.copy_from_slice(&hs.epki.value);
|
||||
protocol_section!("IHI3", {
|
||||
EphemeralKem.keygen(hs.eski.secret_mut(), &mut *hs.epki)?;
|
||||
ih.epki.copy_from_slice(&hs.epki.value);
|
||||
});
|
||||
|
||||
// IHI4
|
||||
hs.core.mix(ih.sidi.as_slice())?.mix(ih.epki.as_slice())?;
|
||||
protocol_section!("IHI4", {
|
||||
hs.core.mix(ih.sidi.as_slice())?.mix(ih.epki.as_slice())?;
|
||||
});
|
||||
|
||||
// IHI5
|
||||
hs.core
|
||||
.encaps_and_mix(&StaticKem, &mut ih.sctr, peer.get(self).spkt.deref())?;
|
||||
protocol_section!("IHI5", {
|
||||
hs.core
|
||||
.encaps_and_mix(&StaticKem, &mut ih.sctr, peer.get(self).spkt.deref())?;
|
||||
});
|
||||
|
||||
// IHI6
|
||||
hs.core.encrypt_and_mix(
|
||||
ih.pidic.as_mut_slice(),
|
||||
self.pidm(peer.get(self).protocol_version.keyed_hash())?
|
||||
.as_ref(),
|
||||
)?;
|
||||
protocol_section!("IHI6", {
|
||||
hs.core.encrypt_and_mix(
|
||||
ih.pidic.as_mut_slice(),
|
||||
self.pidm(peer.get(self).protocol_version.keyed_hash())?
|
||||
.as_ref(),
|
||||
)?;
|
||||
});
|
||||
|
||||
// IHI7
|
||||
hs.core
|
||||
.mix(self.spkm.deref())?
|
||||
.mix(peer.get(self).psk.secret())?;
|
||||
protocol_section!("IHI7", {
|
||||
hs.core
|
||||
.mix(self.spkm.deref())?
|
||||
.mix(peer.get(self).psk.secret())?;
|
||||
});
|
||||
|
||||
// IHI8
|
||||
hs.core.encrypt_and_mix(ih.auth.as_mut_slice(), &[])?;
|
||||
protocol_section!("IHI8", {
|
||||
hs.core.encrypt_and_mix(ih.auth.as_mut_slice(), &[])?;
|
||||
});
|
||||
|
||||
// Update the handshake hash last (not changing any state on prior error
|
||||
peer.hs().insert(self, hs)?;
|
||||
@@ -3603,53 +3639,78 @@ impl CryptoServer {
|
||||
rh: &mut RespHello,
|
||||
keyed_hash: KeyedHash,
|
||||
) -> Result<PeerPtr> {
|
||||
#[cfg(feature = "trace_bench")]
|
||||
let _span_guard = rosenpass_util::trace_bench::trace().emit_span("handle_init_hello");
|
||||
|
||||
let mut core = HandshakeState::zero(keyed_hash);
|
||||
|
||||
core.sidi = SessionId::from_slice(&ih.sidi);
|
||||
|
||||
// IHR1
|
||||
core.init(self.spkm.deref())?;
|
||||
protocol_section!("IHR1", {
|
||||
core.init(self.spkm.deref())?;
|
||||
});
|
||||
|
||||
// IHR4
|
||||
core.mix(&ih.sidi)?.mix(&ih.epki)?;
|
||||
protocol_section!("IHR4", {
|
||||
core.mix(&ih.sidi)?.mix(&ih.epki)?;
|
||||
});
|
||||
|
||||
// IHR5
|
||||
core.decaps_and_mix(&StaticKem, self.sskm.secret(), self.spkm.deref(), &ih.sctr)?;
|
||||
protocol_section!("IHR5", {
|
||||
core.decaps_and_mix(&StaticKem, self.sskm.secret(), self.spkm.deref(), &ih.sctr)?;
|
||||
});
|
||||
|
||||
// IHR6
|
||||
let peer = {
|
||||
let peer = protocol_section!("IHR6", {
|
||||
let mut peerid = PeerId::zero();
|
||||
core.decrypt_and_mix(&mut *peerid, &ih.pidic)?;
|
||||
self.find_peer(peerid)
|
||||
.with_context(|| format!("No such peer {peerid:?}."))?
|
||||
};
|
||||
});
|
||||
|
||||
// IHR7
|
||||
core.mix(peer.get(self).spkt.deref())?
|
||||
.mix(peer.get(self).psk.secret())?;
|
||||
protocol_section!("IHR7", {
|
||||
core.mix(peer.get(self).spkt.deref())?
|
||||
.mix(peer.get(self).psk.secret())?;
|
||||
});
|
||||
|
||||
// IHR8
|
||||
core.decrypt_and_mix(&mut [0u8; 0], &ih.auth)?;
|
||||
protocol_section!("IHR8", {
|
||||
core.decrypt_and_mix(&mut [0u8; 0], &ih.auth)?;
|
||||
});
|
||||
|
||||
// RHR1
|
||||
core.sidr.randomize();
|
||||
rh.sidi.copy_from_slice(core.sidi.as_ref());
|
||||
rh.sidr.copy_from_slice(core.sidr.as_ref());
|
||||
protocol_section!("RHR1", {
|
||||
core.sidr.randomize();
|
||||
rh.sidi.copy_from_slice(core.sidi.as_ref());
|
||||
rh.sidr.copy_from_slice(core.sidr.as_ref());
|
||||
});
|
||||
|
||||
// RHR3
|
||||
core.mix(&rh.sidr)?.mix(&rh.sidi)?;
|
||||
protocol_section!("RHR3", {
|
||||
core.mix(&rh.sidr)?.mix(&rh.sidi)?;
|
||||
});
|
||||
|
||||
// RHR4
|
||||
core.encaps_and_mix(&EphemeralKem, &mut rh.ecti, &ih.epki)?;
|
||||
protocol_section!("RHR4", {
|
||||
core.encaps_and_mix(&EphemeralKem, &mut rh.ecti, &ih.epki)?;
|
||||
});
|
||||
|
||||
// RHR5
|
||||
core.encaps_and_mix(&StaticKem, &mut rh.scti, peer.get(self).spkt.deref())?;
|
||||
protocol_section!("RHR5", {
|
||||
core.encaps_and_mix(&StaticKem, &mut rh.scti, peer.get(self).spkt.deref())?;
|
||||
});
|
||||
|
||||
// RHR6
|
||||
core.store_biscuit(self, peer, &mut rh.biscuit)?;
|
||||
protocol_section!("RHR6", {
|
||||
core.store_biscuit(self, peer, &mut rh.biscuit)?;
|
||||
});
|
||||
|
||||
// RHR7
|
||||
core.encrypt_and_mix(&mut rh.auth, &[])?;
|
||||
protocol_section!("RHR7", {
|
||||
core.encrypt_and_mix(&mut rh.auth, &[])?;
|
||||
});
|
||||
|
||||
Ok(peer)
|
||||
}
|
||||
@@ -3657,6 +3718,9 @@ impl CryptoServer {
|
||||
/// Core cryptographic protocol implementation: Parses an [RespHello] message and produces an
|
||||
/// [InitConf] message on the initiator side.
|
||||
pub fn handle_resp_hello(&mut self, rh: &RespHello, ic: &mut InitConf) -> Result<PeerPtr> {
|
||||
#[cfg(feature = "trace_bench")]
|
||||
let _span_guard = rosenpass_util::trace_bench::trace().emit_span("handle_resp_hello");
|
||||
|
||||
// RHI2
|
||||
let peer = self
|
||||
.lookup_handshake(SessionId::from_slice(&rh.sidi))
|
||||
@@ -3700,24 +3764,34 @@ impl CryptoServer {
|
||||
// to save us from the repetitive secret unwrapping
|
||||
|
||||
// RHI3
|
||||
core.mix(&rh.sidr)?.mix(&rh.sidi)?;
|
||||
protocol_section!("RHI3", {
|
||||
core.mix(&rh.sidr)?.mix(&rh.sidi)?;
|
||||
});
|
||||
|
||||
// RHI4
|
||||
core.decaps_and_mix(
|
||||
&EphemeralKem,
|
||||
hs!().eski.secret(),
|
||||
hs!().epki.deref(),
|
||||
&rh.ecti,
|
||||
)?;
|
||||
protocol_section!("RHI4", {
|
||||
core.decaps_and_mix(
|
||||
&EphemeralKem,
|
||||
hs!().eski.secret(),
|
||||
hs!().epki.deref(),
|
||||
&rh.ecti,
|
||||
)?;
|
||||
});
|
||||
|
||||
// RHI5
|
||||
core.decaps_and_mix(&StaticKem, self.sskm.secret(), self.spkm.deref(), &rh.scti)?;
|
||||
protocol_section!("RHI5", {
|
||||
core.decaps_and_mix(&StaticKem, self.sskm.secret(), self.spkm.deref(), &rh.scti)?;
|
||||
});
|
||||
|
||||
// RHI6
|
||||
core.mix(&rh.biscuit)?;
|
||||
protocol_section!("RHI6", {
|
||||
core.mix(&rh.biscuit)?;
|
||||
});
|
||||
|
||||
// RHI7
|
||||
core.decrypt_and_mix(&mut [0u8; 0], &rh.auth)?;
|
||||
protocol_section!("RHI7", {
|
||||
core.decrypt_and_mix(&mut [0u8; 0], &rh.auth)?;
|
||||
});
|
||||
|
||||
// TODO: We should just authenticate the entire network package up to the auth
|
||||
// tag as a pattern instead of mixing in fields separately
|
||||
@@ -3726,27 +3800,33 @@ impl CryptoServer {
|
||||
ic.sidr.copy_from_slice(&rh.sidr);
|
||||
|
||||
// ICI3
|
||||
core.mix(&ic.sidi)?.mix(&ic.sidr)?;
|
||||
ic.biscuit.copy_from_slice(&rh.biscuit);
|
||||
protocol_section!("ICI3", {
|
||||
core.mix(&ic.sidi)?.mix(&ic.sidr)?;
|
||||
ic.biscuit.copy_from_slice(&rh.biscuit);
|
||||
});
|
||||
|
||||
// ICI4
|
||||
core.encrypt_and_mix(&mut ic.auth, &[])?;
|
||||
protocol_section!("ICI4", {
|
||||
core.encrypt_and_mix(&mut ic.auth, &[])?;
|
||||
});
|
||||
|
||||
// Split() – We move the secrets into the session; we do not
|
||||
// delete the InitiatorHandshake, just clear it's secrets because
|
||||
// we still need it for InitConf message retransmission to function.
|
||||
|
||||
// ICI7
|
||||
peer.session().insert(
|
||||
self,
|
||||
core.enter_live(
|
||||
protocol_section!("ICI7", {
|
||||
peer.session().insert(
|
||||
self,
|
||||
HandshakeRole::Initiator,
|
||||
peer.get(self).protocol_version.keyed_hash(),
|
||||
)?,
|
||||
)?;
|
||||
hs_mut!().core.erase();
|
||||
hs_mut!().next = HandshakeStateMachine::RespConf;
|
||||
core.enter_live(
|
||||
self,
|
||||
HandshakeRole::Initiator,
|
||||
peer.get(self).protocol_version.keyed_hash(),
|
||||
)?,
|
||||
)?;
|
||||
hs_mut!().core.erase();
|
||||
hs_mut!().next = HandshakeStateMachine::RespConf;
|
||||
});
|
||||
|
||||
Ok(peer)
|
||||
}
|
||||
@@ -3762,24 +3842,35 @@ impl CryptoServer {
|
||||
rc: &mut EmptyData,
|
||||
keyed_hash: KeyedHash,
|
||||
) -> Result<PeerPtr> {
|
||||
#[cfg(feature = "trace_bench")]
|
||||
let _span_guard = rosenpass_util::trace_bench::trace().emit_span("handle_init_conf");
|
||||
|
||||
// (peer, bn) ← LoadBiscuit(InitConf.biscuit)
|
||||
// ICR1
|
||||
let (peer, biscuit_no, mut core) = HandshakeState::load_biscuit(
|
||||
self,
|
||||
&ic.biscuit,
|
||||
SessionId::from_slice(&ic.sidi),
|
||||
SessionId::from_slice(&ic.sidr),
|
||||
keyed_hash,
|
||||
)?;
|
||||
let (peer, biscuit_no, mut core) = protocol_section!("ICR1", {
|
||||
HandshakeState::load_biscuit(
|
||||
self,
|
||||
&ic.biscuit,
|
||||
SessionId::from_slice(&ic.sidi),
|
||||
SessionId::from_slice(&ic.sidr),
|
||||
keyed_hash,
|
||||
)?
|
||||
});
|
||||
|
||||
// ICR2
|
||||
core.encrypt_and_mix(&mut [0u8; Aead::TAG_LEN], &[])?;
|
||||
protocol_section!("ICR2", {
|
||||
core.encrypt_and_mix(&mut [0u8; Aead::TAG_LEN], &[])?;
|
||||
});
|
||||
|
||||
// ICR3
|
||||
core.mix(&ic.sidi)?.mix(&ic.sidr)?;
|
||||
protocol_section!("ICR3", {
|
||||
core.mix(&ic.sidi)?.mix(&ic.sidr)?;
|
||||
});
|
||||
|
||||
// ICR4
|
||||
core.decrypt_and_mix(&mut [0u8; 0], &ic.auth)?;
|
||||
protocol_section!("ICR4", {
|
||||
core.decrypt_and_mix(&mut [0u8; 0], &ic.auth)?;
|
||||
});
|
||||
|
||||
// ICR5
|
||||
// Defense against replay attacks; implementations may accept
|
||||
@@ -3791,20 +3882,24 @@ impl CryptoServer {
|
||||
);
|
||||
|
||||
// ICR6
|
||||
peer.get_mut(self).biscuit_used = biscuit_no;
|
||||
protocol_section!("ICR6", {
|
||||
peer.get_mut(self).biscuit_used = biscuit_no;
|
||||
});
|
||||
|
||||
// ICR7
|
||||
peer.session().insert(
|
||||
self,
|
||||
core.enter_live(
|
||||
protocol_section!("ICR7", {
|
||||
peer.session().insert(
|
||||
self,
|
||||
HandshakeRole::Responder,
|
||||
peer.get(self).protocol_version.keyed_hash(),
|
||||
)?,
|
||||
)?;
|
||||
// TODO: This should be part of the protocol specification.
|
||||
// Abort any ongoing handshake from initiator role
|
||||
peer.hs().take(self);
|
||||
core.enter_live(
|
||||
self,
|
||||
HandshakeRole::Responder,
|
||||
peer.get(self).protocol_version.keyed_hash(),
|
||||
)?,
|
||||
)?;
|
||||
// TODO: This should be part of the protocol specification.
|
||||
// Abort any ongoing handshake from initiator role
|
||||
peer.hs().take(self);
|
||||
});
|
||||
|
||||
// TODO: Implementing RP should be possible without touching the live session stuff
|
||||
// TODO: I fear that this may lead to race conditions; the acknowledgement may be
|
||||
@@ -3854,6 +3949,9 @@ impl CryptoServer {
|
||||
msg_in: &Ref<&[u8], Envelope<EmptyData>>,
|
||||
seal_broken: String,
|
||||
) -> Result<PeerPtr> {
|
||||
#[cfg(feature = "trace_bench")]
|
||||
let _span_guard = rosenpass_util::trace_bench::trace().emit_span("handle_resp_conf");
|
||||
|
||||
let rc: &EmptyData = &msg_in.payload;
|
||||
let sid = SessionId::from_slice(&rc.sid);
|
||||
let hs = self
|
||||
@@ -3907,6 +4005,9 @@ impl CryptoServer {
|
||||
///
|
||||
/// See more on DOS mitigation in Rosenpass in the [whitepaper](https://rosenpass.eu/whitepaper.pdf).
|
||||
pub fn handle_cookie_reply(&mut self, cr: &CookieReply) -> Result<PeerPtr> {
|
||||
#[cfg(feature = "trace_bench")]
|
||||
let _span_guard = rosenpass_util::trace_bench::trace().emit_span("handle_cookie_reply");
|
||||
|
||||
let peer_ptr: Option<PeerPtr> = self
|
||||
.lookup_session(Public::new(cr.inner.sid))
|
||||
.map(|v| PeerPtr(v.0))
|
||||
@@ -4030,7 +4131,7 @@ pub mod testutils {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::{borrow::BorrowMut, net::SocketAddrV4, ops::DerefMut, thread::sleep, time::Duration};
|
||||
use std::{borrow::BorrowMut, net::SocketAddrV4, ops::DerefMut};
|
||||
|
||||
use super::*;
|
||||
use serial_test::serial;
|
||||
@@ -4339,6 +4440,8 @@ mod test {
|
||||
|
||||
#[cfg(feature = "experiment_cookie_dos_mitigation")]
|
||||
fn cookie_reply_mechanism_responder_under_load(protocol_version: ProtocolVersion) {
|
||||
use std::time::Duration;
|
||||
|
||||
setup_logging();
|
||||
rosenpass_secret_memory::secret_policy_try_use_memfd_secrets();
|
||||
stacker::grow(8 * 1024 * 1024, || {
|
||||
@@ -4408,7 +4511,7 @@ mod test {
|
||||
break a.retransmit_handshake(peer, &mut *a_to_b_buf).unwrap();
|
||||
}
|
||||
PollResult::Sleep(time) => {
|
||||
sleep(Duration::from_secs_f64(time));
|
||||
std::thread::sleep(Duration::from_secs_f64(time));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ license = "MIT OR Apache-2.0"
|
||||
description = "Build post-quantum-secure VPNs with WireGuard!"
|
||||
homepage = "https://rosenpass.eu/"
|
||||
repository = "https://github.com/rosenpass/rosenpass"
|
||||
rust-version = "1.77.0"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
|
||||
2
rust-toolchain.toml
Normal file
2
rust-toolchain.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "1.77.0"
|
||||
@@ -8,6 +8,7 @@ description = "Rosenpass internal utilities for storing secrets in memory"
|
||||
homepage = "https://rosenpass.eu/"
|
||||
repository = "https://github.com/rosenpass/rosenpass"
|
||||
readme = "readme.md"
|
||||
rust-version = "1.77.0"
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
|
||||
@@ -1344,6 +1344,13 @@ criteria = "safe-to-deploy"
|
||||
delta = "0.5.13 -> 0.5.14"
|
||||
aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml"
|
||||
|
||||
[[audits.mozilla.audits.crossbeam-channel]]
|
||||
who = "Jan-Erik Rediger <jrediger@mozilla.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
delta = "0.5.14 -> 0.5.15"
|
||||
notes = "Fixes a regression from an earlier version which could lead to a double free"
|
||||
aggregated-from = "https://raw.githubusercontent.com/mozilla/glean/main/supply-chain/audits.toml"
|
||||
|
||||
[[audits.mozilla.audits.crunchy]]
|
||||
who = "Erich Gubler <erichdongubler@gmail.com>"
|
||||
criteria = "safe-to-deploy"
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
{ pkgs, rosenpass-deb, rosenpass-rpm }:
|
||||
{
|
||||
pkgs,
|
||||
rosenpass-deb,
|
||||
rosenpass-rpm,
|
||||
}:
|
||||
|
||||
let
|
||||
wg-deb = pkgs.fetchurl {
|
||||
@@ -23,31 +27,38 @@ let
|
||||
cp ${./prepare-test.sh} $out/prepare-test.sh
|
||||
'';
|
||||
|
||||
test = { tester, installPrefix, suffix, source }: (tester {
|
||||
sharedDirs.share = {
|
||||
inherit source;
|
||||
target = "/mnt/share";
|
||||
};
|
||||
testScript = ''
|
||||
vm.wait_for_unit("multi-user.target")
|
||||
vm.succeed("${installPrefix} /mnt/share/wireguard.${suffix}")
|
||||
vm.succeed("${installPrefix} /mnt/share/rosenpass.${suffix}")
|
||||
vm.succeed("bash /mnt/share/prepare-test.sh")
|
||||
test =
|
||||
{
|
||||
tester,
|
||||
installPrefix,
|
||||
suffix,
|
||||
source,
|
||||
}:
|
||||
(tester {
|
||||
sharedDirs.share = {
|
||||
inherit source;
|
||||
target = "/mnt/share";
|
||||
};
|
||||
testScript = ''
|
||||
vm.wait_for_unit("multi-user.target")
|
||||
vm.succeed("${installPrefix} /mnt/share/wireguard.${suffix}")
|
||||
vm.succeed("${installPrefix} /mnt/share/rosenpass.${suffix}")
|
||||
vm.succeed("bash /mnt/share/prepare-test.sh")
|
||||
|
||||
vm.succeed(f"systemctl start rp@server")
|
||||
vm.succeed(f"systemctl start rp@client")
|
||||
vm.succeed(f"systemctl start rp@server")
|
||||
vm.succeed(f"systemctl start rp@client")
|
||||
|
||||
vm.wait_for_unit("rp@server.service")
|
||||
vm.wait_for_unit("rp@client.service")
|
||||
vm.wait_for_unit("rp@server.service")
|
||||
vm.wait_for_unit("rp@client.service")
|
||||
|
||||
vm.wait_until_succeeds("wg show all preshared-keys | grep --invert-match none", timeout=5);
|
||||
vm.wait_until_succeeds("wg show all preshared-keys | grep --invert-match none", timeout=5);
|
||||
|
||||
psk_server = vm.succeed("wg show rp-server preshared-keys").strip().split()[-1]
|
||||
psk_client = vm.succeed("wg show rp-client preshared-keys").strip().split()[-1]
|
||||
psk_server = vm.succeed("wg show rp-server preshared-keys").strip().split()[-1]
|
||||
psk_client = vm.succeed("wg show rp-client preshared-keys").strip().split()[-1]
|
||||
|
||||
assert psk_server == psk_client, "preshared-key exchange must be successful"
|
||||
'';
|
||||
}).sandboxed;
|
||||
assert psk_server == psk_client, "preshared-key exchange must be successful"
|
||||
'';
|
||||
}).sandboxed;
|
||||
in
|
||||
{
|
||||
package-deb-debian-13 = test {
|
||||
|
||||
@@ -32,29 +32,33 @@ let
|
||||
public_key = "/etc/rosenpass/rp0/pqpk";
|
||||
secret_key = "/run/credentials/rosenpass@rp0.service/pqsk";
|
||||
verbosity = "Verbose";
|
||||
peers = [{
|
||||
device = "rp0";
|
||||
peer = client.wg.public;
|
||||
public_key = "/etc/rosenpass/rp0/peers/client/pqpk";
|
||||
}];
|
||||
peers = [
|
||||
{
|
||||
device = "rp0";
|
||||
peer = client.wg.public;
|
||||
public_key = "/etc/rosenpass/rp0/peers/client/pqpk";
|
||||
}
|
||||
];
|
||||
};
|
||||
client_config = {
|
||||
listen = [ ];
|
||||
public_key = "/etc/rosenpass/rp0/pqpk";
|
||||
secret_key = "/run/credentials/rosenpass@rp0.service/pqsk";
|
||||
verbosity = "Verbose";
|
||||
peers = [{
|
||||
device = "rp0";
|
||||
peer = server.wg.public;
|
||||
public_key = "/etc/rosenpass/rp0/peers/server/pqpk";
|
||||
endpoint = "${server.ip4}:9999";
|
||||
}];
|
||||
peers = [
|
||||
{
|
||||
device = "rp0";
|
||||
peer = server.wg.public;
|
||||
public_key = "/etc/rosenpass/rp0/peers/server/pqpk";
|
||||
endpoint = "${server.ip4}:9999";
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
config = pkgs.runCommand "config" { } ''
|
||||
mkdir -pv $out
|
||||
cp -v ${(pkgs.formats.toml {}).generate "rp0.toml" server_config} $out/server
|
||||
cp -v ${(pkgs.formats.toml {}).generate "rp0.toml" client_config} $out/client
|
||||
cp -v ${(pkgs.formats.toml { }).generate "rp0.toml" server_config} $out/server
|
||||
cp -v ${(pkgs.formats.toml { }).generate "rp0.toml" client_config} $out/client
|
||||
'';
|
||||
in
|
||||
{
|
||||
@@ -62,50 +66,71 @@ in
|
||||
|
||||
nodes =
|
||||
let
|
||||
shared = peer: { config, modulesPath, pkgs, ... }: {
|
||||
# Need to work around a problem in recent systemd changes.
|
||||
# It won't be necessary in other distros (for which the systemd file was designed), this is NixOS specific
|
||||
# https://github.com/NixOS/nixpkgs/issues/258371#issuecomment-1925672767
|
||||
# This can potentially be removed in future nixpkgs updates
|
||||
systemd.packages = [
|
||||
(pkgs.runCommand "rosenpass" { } ''
|
||||
mkdir -p $out/lib/systemd/system
|
||||
< ${pkgs.rosenpass}/lib/systemd/system/rosenpass.target > $out/lib/systemd/system/rosenpass.target
|
||||
< ${pkgs.rosenpass}/lib/systemd/system/rosenpass@.service \
|
||||
sed 's@^\(\[Service]\)$@\1\nEnvironment=PATH=${pkgs.wireguard-tools}/bin@' |
|
||||
sed 's@^ExecStartPre=envsubst @ExecStartPre='"${pkgs.envsubst}"'/bin/envsubst @' |
|
||||
sed 's@^ExecStart=rosenpass @ExecStart='"${pkgs.rosenpass}"'/bin/rosenpass @' > $out/lib/systemd/system/rosenpass@.service
|
||||
'')
|
||||
];
|
||||
networking.wireguard = {
|
||||
enable = true;
|
||||
interfaces.rp0 = {
|
||||
ips = [ "${peer.wg.ip4}/32" "${peer.wg.ip6}/128" ];
|
||||
privateKeyFile = "/etc/wireguard/wgsk";
|
||||
shared =
|
||||
peer:
|
||||
{
|
||||
config,
|
||||
modulesPath,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
# Need to work around a problem in recent systemd changes.
|
||||
# It won't be necessary in other distros (for which the systemd file was designed), this is NixOS specific
|
||||
# https://github.com/NixOS/nixpkgs/issues/258371#issuecomment-1925672767
|
||||
# This can potentially be removed in future nixpkgs updates
|
||||
systemd.packages = [
|
||||
(pkgs.runCommand "rosenpass" { } ''
|
||||
mkdir -p $out/lib/systemd/system
|
||||
< ${pkgs.rosenpass}/lib/systemd/system/rosenpass.target > $out/lib/systemd/system/rosenpass.target
|
||||
< ${pkgs.rosenpass}/lib/systemd/system/rosenpass@.service \
|
||||
sed 's@^\(\[Service]\)$@\1\nEnvironment=PATH=${pkgs.wireguard-tools}/bin@' |
|
||||
sed 's@^ExecStartPre=envsubst @ExecStartPre='"${pkgs.envsubst}"'/bin/envsubst @' |
|
||||
sed 's@^ExecStart=rosenpass @ExecStart='"${pkgs.rosenpass}"'/bin/rosenpass @' > $out/lib/systemd/system/rosenpass@.service
|
||||
'')
|
||||
];
|
||||
networking.wireguard = {
|
||||
enable = true;
|
||||
interfaces.rp0 = {
|
||||
ips = [
|
||||
"${peer.wg.ip4}/32"
|
||||
"${peer.wg.ip6}/128"
|
||||
];
|
||||
privateKeyFile = "/etc/wireguard/wgsk";
|
||||
};
|
||||
};
|
||||
environment.etc."wireguard/wgsk".text = peer.wg.secret;
|
||||
networking.interfaces.eth1 = {
|
||||
ipv4.addresses = [
|
||||
{
|
||||
address = peer.ip4;
|
||||
prefixLength = 24;
|
||||
}
|
||||
];
|
||||
ipv6.addresses = [
|
||||
{
|
||||
address = peer.ip6;
|
||||
prefixLength = 64;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
environment.etc."wireguard/wgsk".text = peer.wg.secret;
|
||||
networking.interfaces.eth1 = {
|
||||
ipv4.addresses = [{
|
||||
address = peer.ip4;
|
||||
prefixLength = 24;
|
||||
}];
|
||||
ipv6.addresses = [{
|
||||
address = peer.ip6;
|
||||
prefixLength = 64;
|
||||
}];
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
server = {
|
||||
imports = [ (shared server) ];
|
||||
networking.firewall.allowedUDPPorts = [ 9999 server.wg.listen ];
|
||||
networking.firewall.allowedUDPPorts = [
|
||||
9999
|
||||
server.wg.listen
|
||||
];
|
||||
networking.wireguard.interfaces.rp0 = {
|
||||
listenPort = server.wg.listen;
|
||||
peers = [
|
||||
{
|
||||
allowedIPs = [ client.wg.ip4 client.wg.ip6 ];
|
||||
allowedIPs = [
|
||||
client.wg.ip4
|
||||
client.wg.ip6
|
||||
];
|
||||
publicKey = client.wg.public;
|
||||
}
|
||||
];
|
||||
@@ -116,7 +141,10 @@ in
|
||||
networking.wireguard.interfaces.rp0 = {
|
||||
peers = [
|
||||
{
|
||||
allowedIPs = [ "10.23.42.0/24" "fc00::/64" ];
|
||||
allowedIPs = [
|
||||
"10.23.42.0/24"
|
||||
"fc00::/64"
|
||||
];
|
||||
publicKey = server.wg.public;
|
||||
endpoint = "${server.ip4}:${toString server.wg.listen}";
|
||||
}
|
||||
@@ -124,60 +152,62 @@ in
|
||||
};
|
||||
};
|
||||
};
|
||||
testScript = { ... }: ''
|
||||
from os import system
|
||||
rosenpass = "${pkgs.rosenpass}/bin/rosenpass"
|
||||
testScript =
|
||||
{ ... }:
|
||||
''
|
||||
from os import system
|
||||
rosenpass = "${pkgs.rosenpass}/bin/rosenpass"
|
||||
|
||||
start_all()
|
||||
|
||||
for machine in [server, client]:
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
machine.wait_for_unit("network-online.target")
|
||||
|
||||
with subtest("Key, Config, and Service Setup"):
|
||||
for name, machine, remote in [("server", server, client), ("client", client, server)]:
|
||||
# generate all the keys
|
||||
system(f"{rosenpass} gen-keys --public-key {name}-pqpk --secret-key {name}-pqsk")
|
||||
|
||||
# copy private keys to our side
|
||||
machine.copy_from_host(f"{name}-pqsk", "/etc/rosenpass/rp0/pqsk")
|
||||
machine.copy_from_host(f"{name}-pqpk", "/etc/rosenpass/rp0/pqpk")
|
||||
|
||||
# copy public keys to other side
|
||||
remote.copy_from_host(f"{name}-pqpk", f"/etc/rosenpass/rp0/peers/{name}/pqpk")
|
||||
|
||||
machine.copy_from_host(f"${config}/{name}", "/etc/rosenpass/rp0.toml")
|
||||
start_all()
|
||||
|
||||
for machine in [server, client]:
|
||||
machine.wait_for_unit("wireguard-rp0.service")
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
machine.wait_for_unit("network-online.target")
|
||||
|
||||
with subtest("wg network test"):
|
||||
client.succeed("wg show all preshared-keys | grep none", timeout=5);
|
||||
client.succeed("ping -c5 ${server.wg.ip4}")
|
||||
server.succeed("ping -c5 ${client.wg.ip6}")
|
||||
with subtest("Key, Config, and Service Setup"):
|
||||
for name, machine, remote in [("server", server, client), ("client", client, server)]:
|
||||
# generate all the keys
|
||||
system(f"{rosenpass} gen-keys --public-key {name}-pqpk --secret-key {name}-pqsk")
|
||||
|
||||
with subtest("Set up rosenpass"):
|
||||
for machine in [server, client]:
|
||||
machine.succeed("systemctl start rosenpass@rp0.service")
|
||||
# copy private keys to our side
|
||||
machine.copy_from_host(f"{name}-pqsk", "/etc/rosenpass/rp0/pqsk")
|
||||
machine.copy_from_host(f"{name}-pqpk", "/etc/rosenpass/rp0/pqpk")
|
||||
|
||||
for machine in [server, client]:
|
||||
machine.wait_for_unit("rosenpass@rp0.service")
|
||||
# copy public keys to other side
|
||||
remote.copy_from_host(f"{name}-pqpk", f"/etc/rosenpass/rp0/peers/{name}/pqpk")
|
||||
|
||||
machine.copy_from_host(f"${config}/{name}", "/etc/rosenpass/rp0.toml")
|
||||
|
||||
for machine in [server, client]:
|
||||
machine.wait_for_unit("wireguard-rp0.service")
|
||||
|
||||
with subtest("wg network test"):
|
||||
client.succeed("wg show all preshared-keys | grep none", timeout=5);
|
||||
client.succeed("ping -c5 ${server.wg.ip4}")
|
||||
server.succeed("ping -c5 ${client.wg.ip6}")
|
||||
|
||||
with subtest("Set up rosenpass"):
|
||||
for machine in [server, client]:
|
||||
machine.succeed("systemctl start rosenpass@rp0.service")
|
||||
|
||||
for machine in [server, client]:
|
||||
machine.wait_for_unit("rosenpass@rp0.service")
|
||||
|
||||
|
||||
with subtest("compare preshared keys"):
|
||||
client.wait_until_succeeds("wg show all preshared-keys | grep --invert-match none", timeout=5);
|
||||
server.wait_until_succeeds("wg show all preshared-keys | grep --invert-match none", timeout=5);
|
||||
with subtest("compare preshared keys"):
|
||||
client.wait_until_succeeds("wg show all preshared-keys | grep --invert-match none", timeout=5);
|
||||
server.wait_until_succeeds("wg show all preshared-keys | grep --invert-match none", timeout=5);
|
||||
|
||||
def get_psk(m):
|
||||
psk = m.succeed("wg show rp0 preshared-keys | awk '{print $2}'")
|
||||
psk = psk.strip()
|
||||
assert len(psk.split()) == 1, "Only one PSK"
|
||||
return psk
|
||||
def get_psk(m):
|
||||
psk = m.succeed("wg show rp0 preshared-keys | awk '{print $2}'")
|
||||
psk = psk.strip()
|
||||
assert len(psk.split()) == 1, "Only one PSK"
|
||||
return psk
|
||||
|
||||
assert get_psk(client) == get_psk(server), "preshared keys need to match"
|
||||
assert get_psk(client) == get_psk(server), "preshared keys need to match"
|
||||
|
||||
with subtest("rosenpass network test"):
|
||||
client.succeed("ping -c5 ${server.wg.ip4}")
|
||||
server.succeed("ping -c5 ${client.wg.ip6}")
|
||||
'';
|
||||
with subtest("rosenpass network test"):
|
||||
client.succeed("ping -c5 ${server.wg.ip4}")
|
||||
server.succeed("ping -c5 ${client.wg.ip6}")
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -24,27 +24,31 @@ let
|
||||
verbose = true;
|
||||
dev = "test-rp-device0";
|
||||
ip = "fc00::1/64";
|
||||
peers = [{
|
||||
public_keys_dir = "/etc/rosenpass/test-rp-device0/peers/client";
|
||||
allowed_ips = "fc00::2";
|
||||
}];
|
||||
peers = [
|
||||
{
|
||||
public_keys_dir = "/etc/rosenpass/test-rp-device0/peers/client";
|
||||
allowed_ips = "fc00::2";
|
||||
}
|
||||
];
|
||||
};
|
||||
client_config = {
|
||||
private_keys_dir = "/run/credentials/rp@test-rp-device0.service";
|
||||
verbose = true;
|
||||
dev = "test-rp-device0";
|
||||
ip = "fc00::2/128";
|
||||
peers = [{
|
||||
public_keys_dir = "/etc/rosenpass/test-rp-device0/peers/server";
|
||||
endpoint = "${server.ip4}:9999";
|
||||
allowed_ips = "fc00::/64";
|
||||
}];
|
||||
peers = [
|
||||
{
|
||||
public_keys_dir = "/etc/rosenpass/test-rp-device0/peers/server";
|
||||
endpoint = "${server.ip4}:9999";
|
||||
allowed_ips = "fc00::/64";
|
||||
}
|
||||
];
|
||||
};
|
||||
|
||||
config = pkgs.runCommand "config" { } ''
|
||||
mkdir -pv $out
|
||||
cp -v ${(pkgs.formats.toml {}).generate "test-rp-device0.toml" server_config} $out/server
|
||||
cp -v ${(pkgs.formats.toml {}).generate "test-rp-device0.toml" client_config} $out/client
|
||||
cp -v ${(pkgs.formats.toml { }).generate "test-rp-device0.toml" server_config} $out/server
|
||||
cp -v ${(pkgs.formats.toml { }).generate "test-rp-device0.toml" client_config} $out/client
|
||||
'';
|
||||
in
|
||||
{
|
||||
@@ -52,88 +56,105 @@ in
|
||||
|
||||
nodes =
|
||||
let
|
||||
shared = peer: { config, modulesPath, pkgs, ... }: {
|
||||
# Need to work around a problem in recent systemd changes.
|
||||
# It won't be necessary in other distros (for which the systemd file was designed), this is NixOS specific
|
||||
# https://github.com/NixOS/nixpkgs/issues/258371#issuecomment-1925672767
|
||||
# This can potentially be removed in future nixpkgs updates
|
||||
systemd.packages = [
|
||||
(pkgs.runCommand "rp@.service" { } ''
|
||||
mkdir -p $out/lib/systemd/system
|
||||
< ${pkgs.rosenpass}/lib/systemd/system/rosenpass.target > $out/lib/systemd/system/rosenpass.target
|
||||
< ${pkgs.rosenpass}/lib/systemd/system/rp@.service \
|
||||
sed 's@^\(\[Service]\)$@\1\nEnvironment=PATH=${pkgs.iproute2}/bin:${pkgs.wireguard-tools}/bin@' |
|
||||
sed 's@^ExecStartPre=envsubst @ExecStartPre='"${pkgs.envsubst}"'/bin/envsubst @' |
|
||||
sed 's@^ExecStart=rp @ExecStart='"${pkgs.rosenpass}"'/bin/rp @' > $out/lib/systemd/system/rp@.service
|
||||
'')
|
||||
];
|
||||
environment.systemPackages = [ pkgs.wireguard-tools ];
|
||||
networking.interfaces.eth1 = {
|
||||
ipv4.addresses = [{
|
||||
address = peer.ip4;
|
||||
prefixLength = 24;
|
||||
}];
|
||||
ipv6.addresses = [{
|
||||
address = peer.ip6;
|
||||
prefixLength = 64;
|
||||
}];
|
||||
shared =
|
||||
peer:
|
||||
{
|
||||
config,
|
||||
modulesPath,
|
||||
pkgs,
|
||||
...
|
||||
}:
|
||||
{
|
||||
# Need to work around a problem in recent systemd changes.
|
||||
# It won't be necessary in other distros (for which the systemd file was designed), this is NixOS specific
|
||||
# https://github.com/NixOS/nixpkgs/issues/258371#issuecomment-1925672767
|
||||
# This can potentially be removed in future nixpkgs updates
|
||||
systemd.packages = [
|
||||
(pkgs.runCommand "rp@.service" { } ''
|
||||
mkdir -p $out/lib/systemd/system
|
||||
< ${pkgs.rosenpass}/lib/systemd/system/rosenpass.target > $out/lib/systemd/system/rosenpass.target
|
||||
< ${pkgs.rosenpass}/lib/systemd/system/rp@.service \
|
||||
sed 's@^\(\[Service]\)$@\1\nEnvironment=PATH=${pkgs.iproute2}/bin:${pkgs.wireguard-tools}/bin@' |
|
||||
sed 's@^ExecStartPre=envsubst @ExecStartPre='"${pkgs.envsubst}"'/bin/envsubst @' |
|
||||
sed 's@^ExecStart=rp @ExecStart='"${pkgs.rosenpass}"'/bin/rp @' > $out/lib/systemd/system/rp@.service
|
||||
'')
|
||||
];
|
||||
environment.systemPackages = [ pkgs.wireguard-tools ];
|
||||
networking.interfaces.eth1 = {
|
||||
ipv4.addresses = [
|
||||
{
|
||||
address = peer.ip4;
|
||||
prefixLength = 24;
|
||||
}
|
||||
];
|
||||
ipv6.addresses = [
|
||||
{
|
||||
address = peer.ip6;
|
||||
prefixLength = 64;
|
||||
}
|
||||
];
|
||||
};
|
||||
};
|
||||
};
|
||||
in
|
||||
{
|
||||
server = {
|
||||
imports = [ (shared server) ];
|
||||
networking.firewall.allowedUDPPorts = [ 9999 server.wg.listen ];
|
||||
networking.firewall.allowedUDPPorts = [
|
||||
9999
|
||||
server.wg.listen
|
||||
];
|
||||
};
|
||||
client = {
|
||||
imports = [ (shared client) ];
|
||||
};
|
||||
};
|
||||
testScript = { ... }: ''
|
||||
from os import system
|
||||
rp = "${pkgs.rosenpass}/bin/rp"
|
||||
testScript =
|
||||
{ ... }:
|
||||
''
|
||||
from os import system
|
||||
rp = "${pkgs.rosenpass}/bin/rp"
|
||||
|
||||
start_all()
|
||||
|
||||
for machine in [server, client]:
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
machine.wait_for_unit("network-online.target")
|
||||
|
||||
with subtest("Key, Config, and Service Setup"):
|
||||
for name, machine, remote in [("server", server, client), ("client", client, server)]:
|
||||
# create all the keys
|
||||
system(f"{rp} genkey {name}-sk")
|
||||
system(f"{rp} pubkey {name}-sk {name}-pk")
|
||||
|
||||
# copy secret keys to our side
|
||||
for file in ["pqpk", "pqsk", "wgsk"]:
|
||||
machine.copy_from_host(f"{name}-sk/{file}", f"/etc/rosenpass/test-rp-device0/{file}")
|
||||
# copy public keys to other side
|
||||
for file in ["pqpk", "wgpk"]:
|
||||
remote.copy_from_host(f"{name}-pk/{file}", f"/etc/rosenpass/test-rp-device0/peers/{name}/{file}")
|
||||
|
||||
machine.copy_from_host(f"${config}/{name}", "/etc/rosenpass/test-rp-device0.toml")
|
||||
start_all()
|
||||
|
||||
for machine in [server, client]:
|
||||
machine.succeed("systemctl start rp@test-rp-device0.service")
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
machine.wait_for_unit("network-online.target")
|
||||
|
||||
for machine in [server, client]:
|
||||
machine.wait_for_unit("rp@test-rp-device0.service")
|
||||
with subtest("Key, Config, and Service Setup"):
|
||||
for name, machine, remote in [("server", server, client), ("client", client, server)]:
|
||||
# create all the keys
|
||||
system(f"{rp} genkey {name}-sk")
|
||||
system(f"{rp} pubkey {name}-sk {name}-pk")
|
||||
|
||||
with subtest("compare preshared keys"):
|
||||
client.wait_until_succeeds("wg show all preshared-keys | grep --invert-match none", timeout=5);
|
||||
server.wait_until_succeeds("wg show all preshared-keys | grep --invert-match none", timeout=5);
|
||||
# copy secret keys to our side
|
||||
for file in ["pqpk", "pqsk", "wgsk"]:
|
||||
machine.copy_from_host(f"{name}-sk/{file}", f"/etc/rosenpass/test-rp-device0/{file}")
|
||||
# copy public keys to other side
|
||||
for file in ["pqpk", "wgpk"]:
|
||||
remote.copy_from_host(f"{name}-pk/{file}", f"/etc/rosenpass/test-rp-device0/peers/{name}/{file}")
|
||||
|
||||
def get_psk(m):
|
||||
psk = m.succeed("wg show test-rp-device0 preshared-keys | awk '{print $2}'")
|
||||
psk = psk.strip()
|
||||
assert len(psk.split()) == 1, "Only one PSK"
|
||||
return psk
|
||||
machine.copy_from_host(f"${config}/{name}", "/etc/rosenpass/test-rp-device0.toml")
|
||||
|
||||
assert get_psk(client) == get_psk(server), "preshared keys need to match"
|
||||
for machine in [server, client]:
|
||||
machine.succeed("systemctl start rp@test-rp-device0.service")
|
||||
|
||||
with subtest("network test"):
|
||||
client.succeed("ping -c5 ${server.wg.ip6}")
|
||||
server.succeed("ping -c5 ${client.wg.ip6}")
|
||||
'';
|
||||
for machine in [server, client]:
|
||||
machine.wait_for_unit("rp@test-rp-device0.service")
|
||||
|
||||
with subtest("compare preshared keys"):
|
||||
client.wait_until_succeeds("wg show all preshared-keys | grep --invert-match none", timeout=5);
|
||||
server.wait_until_succeeds("wg show all preshared-keys | grep --invert-match none", timeout=5);
|
||||
|
||||
def get_psk(m):
|
||||
psk = m.succeed("wg show test-rp-device0 preshared-keys | awk '{print $2}'")
|
||||
psk = psk.strip()
|
||||
assert len(psk.split()) == 1, "Only one PSK"
|
||||
return psk
|
||||
|
||||
assert get_psk(client) == get_psk(server), "preshared keys need to match"
|
||||
|
||||
with subtest("network test"):
|
||||
client.succeed("ping -c5 ${server.wg.ip6}")
|
||||
server.succeed("ping -c5 ${client.wg.ip6}")
|
||||
'';
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ description = "Flexible destination parameters"
|
||||
homepage = "https://rosenpass.eu/"
|
||||
repository = "https://github.com/rosenpass/rosenpass"
|
||||
readme = "readme.md"
|
||||
rust-version = "1.77.0"
|
||||
|
||||
[dev-dependencies]
|
||||
doc-comment = { workspace = true }
|
||||
|
||||
28
treefmt.nix
Normal file
28
treefmt.nix
Normal file
@@ -0,0 +1,28 @@
|
||||
{ pkgs, ... }:
|
||||
{
|
||||
# Used to find the project root
|
||||
projectRootFile = "flake.nix";
|
||||
programs.nixfmt.enable = true;
|
||||
programs.prettier = {
|
||||
enable = true;
|
||||
includes = [
|
||||
"*.css"
|
||||
"*.html"
|
||||
"*.js"
|
||||
"*.json"
|
||||
"*.json5"
|
||||
"*.md"
|
||||
"*.mdx"
|
||||
"*.toml"
|
||||
"*.yaml"
|
||||
"*.yml"
|
||||
];
|
||||
excludes = [ "supply-chain/*" ];
|
||||
settings = {
|
||||
plugins = [
|
||||
"${pkgs.nodePackages.prettier-plugin-toml}/lib/node_modules/prettier-plugin-toml/lib/index.js"
|
||||
];
|
||||
};
|
||||
};
|
||||
programs.rustfmt.enable = true;
|
||||
}
|
||||
@@ -8,6 +8,7 @@ description = "Rosenpass internal utilities"
|
||||
homepage = "https://rosenpass.eu/"
|
||||
repository = "https://github.com/rosenpass/rosenpass"
|
||||
readme = "readme.md"
|
||||
rust-version = "1.77.0"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -23,7 +24,8 @@ thiserror = { workspace = true }
|
||||
mio = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
uds = { workspace = true, optional = true, features = ["mio_1xx"] }
|
||||
|
||||
libcrux-test-utils = { workspace = true, optional = true }
|
||||
|
||||
[features]
|
||||
experiment_file_descriptor_passing = ["uds"]
|
||||
trace_bench = ["dep:libcrux-test-utils"]
|
||||
|
||||
@@ -30,6 +30,9 @@ pub mod option;
|
||||
pub mod result;
|
||||
/// Time and duration utilities.
|
||||
pub mod time;
|
||||
/// Trace benchmarking utilities
|
||||
#[cfg(feature = "trace_bench")]
|
||||
pub mod trace_bench;
|
||||
/// Type-level numbers and arithmetic.
|
||||
pub mod typenum;
|
||||
/// Zero-copy serialization utilities.
|
||||
|
||||
@@ -13,7 +13,7 @@ use std::time::Instant;
|
||||
///
|
||||
/// let timebase = Timebase::default();
|
||||
/// let now = timebase.now();
|
||||
/// assert!(now > 0.0);
|
||||
/// assert!(now >= 0.0);
|
||||
/// ```
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
||||
23
util/src/trace_bench.rs
Normal file
23
util/src/trace_bench.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
use std::sync::OnceLock;
|
||||
use std::time::Instant;
|
||||
|
||||
use libcrux_test_utils::tracing;
|
||||
|
||||
/// The trace value used in all Rosepass crates.
|
||||
static TRACE: OnceLock<RpTrace> = OnceLock::new();
|
||||
|
||||
/// The trace type used to trace Rosenpass for performance measurement.
|
||||
pub type RpTrace = tracing::MutexTrace<&'static str, Instant>;
|
||||
|
||||
/// The trace event type used to trace Rosenpass for performance measurement.
|
||||
pub type RpEventType = tracing::TraceEvent<&'static str, Instant>;
|
||||
|
||||
// Re-export to make functionality available and callers don't need to also directly depend on
|
||||
// [`libcrux_test_utils`].
|
||||
pub use libcrux_test_utils::tracing::trace_span;
|
||||
pub use tracing::Trace;
|
||||
|
||||
/// Returns a reference to the trace and lazily initializes it.
|
||||
pub fn trace() -> &'static tracing::MutexTrace<&'static str, Instant> {
|
||||
TRACE.get_or_init(tracing::MutexTrace::default)
|
||||
}
|
||||
@@ -8,6 +8,7 @@ description = "Rosenpass internal broker that runs as root and supplies exchange
|
||||
homepage = "https://rosenpass.eu/"
|
||||
repository = "https://github.com/rosenpass/rosenpass"
|
||||
readme = "readme.md"
|
||||
rust-version = "1.77.0"
|
||||
|
||||
[dependencies]
|
||||
thiserror = { workspace = true }
|
||||
|
||||
Reference in New Issue
Block a user