Compare commits

..

4 Commits

Author SHA1 Message Date
Karolin Varner
caf91c84f0 chore: Remove unused warning in api integration test 2024-12-18 13:45:38 +01:00
Karolin Varner
f5b4c17011 fix: Disable asserts that rely on timing characteristics during coverage testing 2024-12-18 13:45:38 +01:00
Karolin Varner
12506e5f95 chore: Final improvements on the to crate API doc 2024-12-18 13:45:38 +01:00
David Niehues
965600212d docs+doctest(to): Add tests, examples and documentation to the to-crate 2024-12-18 13:45:38 +01:00
240 changed files with 8152 additions and 19657 deletions

View File

@@ -3,6 +3,11 @@ secret_key = "rp-a-secret-key"
listen = ["127.0.0.1:9999"]
verbosity = "Verbose"
[api]
listen_path = []
listen_fd = []
stream_fd = []
[[peers]]
public_key = "rp-b-public-key"
endpoint = "127.0.0.1:9998"

View File

@@ -3,6 +3,11 @@ secret_key = "rp-b-secret-key"
listen = ["127.0.0.1:9998"]
verbosity = "Verbose"
[api]
listen_path = []
listen_fd = []
stream_fd = []
[[peers]]
public_key = "rp-a-public-key"
endpoint = "127.0.0.1:9999"

View File

@@ -32,9 +32,9 @@ let systems_map = {
# aarch64-darwin
# aarch64-linux
i686-linux: ubicloud-standard-2-ubuntu-2204,
i686-linux: ubuntu-latest,
x86_64-darwin: macos-13,
x86_64-linux: ubicloud-standard-2-ubuntu-2204
x86_64-linux: ubuntu-latest
}
let targets = (get-attr-names ".#packages"
@@ -61,13 +61,14 @@ mut release_workflow = {
let runner_setup = [
{
uses: "actions/checkout@v4"
uses: "actions/checkout@v3"
}
{
uses: "cachix/install-nix-action@v30",
uses: "cachix/install-nix-action@v22",
with: { nix_path: "nixpkgs=channel:nixos-unstable" }
}
{
uses: "cachix/cachix-action@v15",
uses: "cachix/cachix-action@v12",
with: {
name: rosenpass,
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
@@ -153,7 +154,7 @@ for system in ($targets | columns) {
}
{
name: Release,
uses: "softprops/action-gh-release@v2",
uses: "softprops/action-gh-release@v1",
with: {
draft: "${{ contains(github.ref_name, 'rc') }}",
prerelease: "${{ contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') }}",
@@ -181,7 +182,7 @@ $cachix_workflow.jobs = ($cachix_workflow.jobs | insert $"($system)---whitepaper
}
{
name: "Deploy PDF artifacts",
uses: "peaceiris/actions-gh-pages@v4",
uses: "peaceiris/actions-gh-pages@v3",
with: {
github_token: "${{ secrets.GITHUB_TOKEN }}",
publish_dir: result/,

View File

@@ -1 +0,0 @@
.gitignore

View File

@@ -1,103 +0,0 @@
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: ubicloud-standard-2
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v5
# 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: ubicloud-standard-2
steps:
- name: Successful
if: ${{ !(contains(needs.*.result, 'failure')) }}
run: exit 0
- name: Failing
if: ${{ (contains(needs.*.result, 'failure')) }}
run: exit 1

View File

@@ -1,90 +0,0 @@
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: ubicloud-standard-2
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v5
# 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: ubicloud-standard-2
steps:
- name: Successful
if: ${{ !(contains(needs.*.result, 'failure')) }}
run: exit 0
- name: Failing
if: ${{ (contains(needs.*.result, 'failure')) }}
run: exit 1

View File

@@ -13,10 +13,10 @@ jobs:
steps:
- name: Checkout code
uses: actions/checkout@v5
uses: actions/checkout@v4
- name: Clone rosenpass-website repository
uses: actions/checkout@v5
uses: actions/checkout@v4
with:
repository: rosenpass/rosenpass-website
ref: main

View File

@@ -1,288 +0,0 @@
name: Build Docker Images
# Run this job on all non-pull-request events,
# or if Docker-related files are changed in a pull request.
on:
push:
branches:
- "main"
tags:
- "v*"
pull_request:
paths:
- "docker/Dockerfile"
- ".github/workflows/docker.yaml"
branches:
- "main"
permissions:
contents: read
packages: write
jobs:
# --------------------------------
# 1. BUILD & TEST
# --------------------------------
build-and-test-rp:
strategy:
matrix:
arch: [amd64, arm64]
runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build (no push) and Load
id: build
uses: docker/build-push-action@v6
with:
context: .
file: docker/Dockerfile
# no pushing here, so we can test locally
push: false
# load the built image into the local Docker daemon on the runner
load: true
target: rosenpass
tags: rosenpass:test
platforms: linux/${{ matrix.arch }}
- name: Integration Test - Standalone Key Exchange
run: |
# Create separate workdirs
mkdir -p workdir-server workdir-client
# Create a Docker network
docker network create -d bridge rp
echo "=== GENERATE SERVER KEYS ==="
docker run --rm \
-v $PWD/workdir-server:/workdir \
rosenpass:test gen-keys \
--public-key=workdir/server-public \
--secret-key=workdir/server-secret
echo "=== GENERATE CLIENT KEYS ==="
docker run --rm \
-v $PWD/workdir-client:/workdir \
rosenpass:test gen-keys \
--public-key=workdir/client-public \
--secret-key=workdir/client-secret
echo "=== SHARE PUBLIC KEYS ==="
cp workdir-client/client-public workdir-server/client-public
cp workdir-server/server-public workdir-client/server-public
echo "=== START SERVER CONTAINER ==="
docker run -d --rm \
--name rpserver \
--network rp \
-v $PWD/workdir-server:/workdir \
rosenpass:test exchange \
private-key workdir/server-secret \
public-key workdir/server-public \
listen 0.0.0.0:9999 \
peer public-key workdir/client-public \
outfile workdir/server-sharedkey
# Get the container IP of the server
SERVER_IP=$(docker inspect --format='{{.NetworkSettings.Networks.rp.IPAddress}}' rpserver)
echo "SERVER_IP=$SERVER_IP"
echo "=== START CLIENT CONTAINER ==="
docker run -d --rm \
--name rpclient \
--network rp \
-v $PWD/workdir-client:/workdir \
rosenpass:test exchange \
private-key workdir/client-secret \
public-key workdir/client-public \
peer public-key workdir/server-public \
endpoint ${SERVER_IP}:9999 \
outfile workdir/client-sharedkey
echo "=== COMPARE SHARED KEYS ==="
echo "Waiting up to 30 seconds for the server to generate 'server-sharedkey'..."
for i in $(seq 1 30); do
if [ -f "workdir-server/server-sharedkey" ]; then
echo "server-sharedkey found!"
break
fi
sleep 1
done
sudo cmp workdir-server/server-sharedkey workdir-client/client-sharedkey
echo "Standalone Key Exchange test OK."
# --------------------------------
# 2. PUSH (only if tests pass)
# --------------------------------
docker-image-rp:
needs:
- build-and-test-rp
# Skip if this is not a PR. Then we want to push this image.
if: ${{ github.event_name != 'pull_request' }}
# Use a matrix to build for both AMD64 and ARM64
strategy:
matrix:
arch: [amd64, arm64]
# Switch the runner based on the architecture
runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository_owner }}/rp
labels: |
maintainer=Karolin Varner <karo@cupdev.net>, wucke13 <wucke13@gmail.com>
org.opencontainers.image.authors=Karolin Varner <karo@cupdev.net>, wucke13 <wucke13@gmail.com>
org.opencontainers.image.title=Rosenpass
org.opencontainers.image.description=The rp command-line integrates Rosenpass and WireGuard to help you create a VPN
org.opencontainers.image.vendor=Rosenpass e.V.
org.opencontainers.image.licenses=MIT OR Apache-2.0
org.opencontainers.image.url=https://rosenpass.eu
org.opencontainers.image.documentation=https://rosenpass.eu/docs/
org.opencontainers.image.source=https://github.com/rosenpass/rosenpass
- name: Log in to registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push by digest
id: build
uses: docker/build-push-action@v6
with:
context: .
file: docker/Dockerfile
push: ${{ github.event_name != 'pull_request' }}
labels: ${{ steps.meta.outputs.labels }}
tags: ghcr.io/${{ github.repository_owner }}/rp
target: rp
platforms: linux/${{ matrix.arch }}
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
- name: Export digest
run: |
mkdir -p ${{ runner.temp }}/digests
digest="${{ steps.build.outputs.digest }}"
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-rp-${{ matrix.arch }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
docker-image-rosenpass:
needs:
- build-and-test-rp
# Skip if this is not a PR. Then we want to push this image.
if: ${{ github.event_name != 'pull_request' }}
# Use a matrix to build for both AMD64 and ARM64
strategy:
matrix:
arch: [amd64, arm64]
# Switch the runner based on the architecture
runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
steps:
- name: Checkout
uses: actions/checkout@v5
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository_owner }}/rosenpass
labels: |
maintainer=Karolin Varner <karo@cupdev.net>, wucke13 <wucke13@gmail.com>
org.opencontainers.image.authors=Karolin Varner <karo@cupdev.net>, wucke13 <wucke13@gmail.com>
org.opencontainers.image.title=Rosenpass
org.opencontainers.image.description=Reference implementation of the protocol rosenpass protocol
org.opencontainers.image.vendor=Rosenpass e.V.
org.opencontainers.image.licenses=MIT OR Apache-2.0
org.opencontainers.image.url=https://rosenpass.eu
org.opencontainers.image.documentation=https://rosenpass.eu/docs/
org.opencontainers.image.source=https://github.com/rosenpass/rosenpass
- name: Log in to registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Build and push by digest
id: build
uses: docker/build-push-action@v6
with:
context: .
file: docker/Dockerfile
push: ${{ github.event_name != 'pull_request' }}
labels: ${{ steps.meta.outputs.labels }}
tags: ghcr.io/${{ github.repository_owner }}/rosenpass
target: rosenpass
platforms: linux/${{ matrix.arch }}
outputs: type=image,push-by-digest=true,name-canonical=true,push=true
- name: Export digest
run: |
mkdir -p ${{ runner.temp }}/digests
digest="${{ steps.build.outputs.digest }}"
touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@v4
with:
name: digests-rosenpass-${{ matrix.arch }}
path: ${{ runner.temp }}/digests/*
if-no-files-found: error
retention-days: 1
merge-digests:
runs-on: ubuntu-latest
needs:
- docker-image-rosenpass
- docker-image-rp
if: ${{ github.event_name != 'pull_request' }}
strategy:
matrix:
target: [rp, rosenpass]
steps:
- name: Download digests
uses: actions/download-artifact@v5
with:
path: ${{ runner.temp }}/digests
pattern: digests-${{ matrix.target }}-*
merge-multiple: true
- name: Log in to registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.repository_owner }} --password-stdin
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository_owner }}/${{ matrix.target }}
tags: |
type=edge,branch=main
type=sha,branch=main
type=semver,pattern={{version}}
- name: Create manifest list and push
working-directory: ${{ runner.temp }}/digests
run: |
docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf 'ghcr.io/${{ github.repository_owner }}/${{ matrix.target }}@sha256:%s ' *)
- name: Inspect image
run: |
docker buildx imagetools inspect ghcr.io/${{ github.repository_owner }}/${{ matrix.target }}:${{ steps.meta.outputs.version }}

View File

@@ -1,166 +0,0 @@
name: Integration Tests
on:
pull_request:
push:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
integration-tests-x86_64-linux:
name: Integration tests x86_64-linux
runs-on:
- ubicloud-standard-2-ubuntu-2204
steps:
- uses: actions/checkout@v5
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v15
with:
name: rosenpass
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
- name: Extract the reference of before and after for the integration tests.
run: |
EVENT_NAME="${{ github.event_name }}"
REF_BEFORE=""
REF_AFTER="path:../../"
if [[ "$EVENT_NAME" == "pull_request" ]]; then
echo "This CI run was triggered in the context of a pull request."
REF_BEFORE="github:rosenpass/rosenpass/main"
git checkout -B pr-${{ github.event.pull_request.number }}
REF_AFTER="git+file://../../../?ref=pr-${{ github.event.pull_request.number }}"
elif [[ "$EVENT_NAME" == "push" ]]; then
echo "This CI run was triggered in the context of a push."
REF_BEFORE="github:rosenpass/rosenpass/${{ github.event.before }}"
REF_AFTER="github:rosenpass/rosenpass/${{ github.event.after }}"
else
echo "ERROR: This CI run was not triggered in the context of a pull request or a push. Exiting with error."
exit 1
fi
echo "REF_BEFORE=$REF_BEFORE" >> $GITHUB_ENV
echo "REF_AFTER=$REF_AFTER" >> $GITHUB_ENV
- name: Check
run: |
cd ./tests/integration
nix flake check --print-build-logs --system x86_64-linux --override-input rosenpass-old $REF_BEFORE --override-input rosenpass-new $REF_AFTER
# THE FOLLOWING TEST IS DISABLED FOR THE TIME BENG UNTIL WE GET AN ARM64 RUNNER THAT SUPPORTS KVM
#integration-tests-aarch64-linux:
# name: Integration tests aarch64-linux
# runs-on:
# - ubicloud-standard-2-arm-ubuntu-2204
# steps:
# - uses: actions/checkout@v5
# - uses: cachix/install-nix-action@v30
# with:
# nix_path: nixpkgs=channel:nixos-unstable
# - uses: cachix/cachix-action@v15
# with:
# name: rosenpass
# authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
# - name: Extract the reference of before and after for the integration tests.
# run: |
# EVENT_NAME="${{ github.event_name }}"
# REF_BEFORE=""
# REF_AFTER="path:../../"
# if [[ "$EVENT_NAME" == "pull_request" ]]; then
# echo "This CI run was triggered in the context of a pull request."
# REF_BEFORE="github:rosenpass/rosenpass/main"
# #git checkout -B pr-${{ github.event.pull_request.number }}
# REF_AFTER="git+file://../../../?ref=pr-${{ github.event.pull_request.number }}"
# elif [[ "$EVENT_NAME" == "push" ]]; then
# echo "This CI run was triggered in the context of a push."
# REF_BEFORE="github:rosenpass/rosenpass/${{ github.event.before }}"
# REF_AFTER="github:rosenpass/rosenpass/${{ github.event.after }}"
# #git checkout -B ${{ github.ref_name }}
# else
# echo "ERROR: This CI run was not triggered in the context of a pull request or a push. Exiting with error."
# exit 1
# fi
# echo "REF_BEFORE=$REF_BEFORE" >> $GITHUB_ENV
# echo "REF_AFTER=$REF_AFTER" >> $GITHUB_ENV
# - name: Check
# run: |
# cd ./tests/integration
# # export QEMU_OPTS="-machine virt -cpu cortex-a57"
# nix flake check --print-build-logs --system aarch64-linux --override-input rosenpass-old $REF_BEFORE --override-input rosenpass-new $REF_AFTER
#integration-tests-i686-linux:
# name: Integration tests i686-linux
# timeout-minutes: 144000
# runs-on:
# - ubicloud-standard-8-ubuntu-2204
# steps:
# - uses: actions/checkout@v5
# - uses: cachix/install-nix-action@v30
# with:
# nix_path: nixpkgs=channel:nixos-unstable
# - uses: cachix/cachix-action@v15
# with:
# name: rosenpass
# authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
# - name: Extract the reference of before and after for the integration tests.
# run: |
# EVENT_NAME="${{ github.event_name }}"
# REF_BEFORE=""
# REF_AFTER="path:../../"
# if [[ "$EVENT_NAME" == "pull_request" ]]; then
# echo "This CI run was triggered in the context of a pull request."
# REF_BEFORE="github:rosenpass/rosenpass/main"
# git checkout -B pr-${{ github.event.pull_request.number }}
# REF_AFTER="git+file://../../../?ref=pr-${{ github.event.pull_request.number }}"
# elif [[ "$EVENT_NAME" == "push" ]]; then
# echo "This CI run was triggered in the context of a push."
# REF_BEFORE="github:rosenpass/rosenpass/${{ github.event.before }}"
# REF_AFTER="github:rosenpass/rosenpass/${{ github.event.after }}"
# else
# echo "ERROR: This CI run was not triggered in the context of a pull request or a push. Exiting with error."
# exit 1
# fi
# echo "REF_BEFORE=$REF_BEFORE" >> $GITHUB_ENV
# echo "REF_AFTER=$REF_AFTER" >> $GITHUB_ENV
# - name: Check
# run: |
# cd ./tests/integration
# nix flake check --print-build-logs --system i686-linux --override-input rosenpass-old $REF_BEFORE --override-input rosenpass-new $REF_AFTER
# THE FOLLOWING TEST IS DISABLED FOR THE TIME BENG UNTIL THIS ISSUE WITH NIXOS TESTS ON DARWIN GETS RESOLVED: https://github.com/NixOS/nixpkgs/issues/294725
#integration-tests-aarch64-darwin:
# name: Integration tests aarch64-darwin
# runs-on:
# - warp-macos-13-arm64-6x
# steps:
# - uses: actions/checkout@v5
# - uses: cachix/install-nix-action@v30
# with:
# nix_path: nixpkgs=channel:nixos-unstable
# - uses: cachix/cachix-action@v15
# with:
# name: rosenpass
# authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
# - name: Extract the reference of before and after for the integration tests.
# run: |
# EVENT_NAME="${{ github.event_name }}"
# REF_BEFORE=""
# REF_AFTER="path:../../"
# if [[ "$EVENT_NAME" == "pull_request" ]]; then
# echo "This CI run was triggered in the context of a pull request."
# REF_BEFORE="github:rosenpass/rosenpass/main"
# git checkout -B pr-${{ github.event.pull_request.number }}
# REF_AFTER="git+file://../../../?ref=pr-${{ github.event.pull_request.number }}"
# elif [[ "$EVENT_NAME" == "push" ]]; then
# echo "This CI run was triggered in the context of a push."
# REF_BEFORE="github:rosenpass/rosenpass/${{ github.event.before }}"
# REF_AFTER="github:rosenpass/rosenpass/${{ github.event.after }}"
# else
# echo "ERROR: This CI run was not triggered in the context of a pull request or a push. Exiting with error."
# exit 1
# fi
# echo "REF_BEFORE=$REF_BEFORE" >> $GITHUB_ENV
# echo "REF_AFTER=$REF_AFTER" >> $GITHUB_ENV
# - name: Check
# run: |
# cd ./tests/integration
# nix flake check --print-build-logs --system aarch64-darwin --override-input rosenpass-old $REF_BEFORE --override-input rosenpass-new $REF_AFTER

View File

@@ -1,19 +0,0 @@
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

View File

@@ -1,114 +0,0 @@
name: Nix on Mac
permissions:
contents: write
on:
push:
branches:
- main
workflow_call:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
aarch64-darwin---default:
name: Build aarch64-darwin.default
runs-on:
- warp-macos-13-arm64-6x
needs:
- aarch64-darwin---rosenpass
steps:
- uses: actions/checkout@v5
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v15
with:
name: rosenpass
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
- name: Build
run: nix build .#packages.aarch64-darwin.default --print-build-logs
aarch64-darwin---release-package:
name: Build aarch64-darwin.release-package
runs-on:
- warp-macos-13-arm64-6x
needs:
- aarch64-darwin---rosenpass
- aarch64-darwin---rp
- aarch64-darwin---rosenpass-oci-image
steps:
- uses: actions/checkout@v5
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v15
with:
name: rosenpass
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
- name: Build
run: nix build .#packages.aarch64-darwin.release-package --print-build-logs
aarch64-darwin---rosenpass:
name: Build aarch64-darwin.rosenpass
runs-on:
- warp-macos-13-arm64-6x
needs: []
steps:
- uses: actions/checkout@v5
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v15
with:
name: rosenpass
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
- name: Build
run: nix build .#packages.aarch64-darwin.rosenpass --print-build-logs
aarch64-darwin---rp:
name: Build aarch64-darwin.rp
runs-on:
- warp-macos-13-arm64-6x
needs: []
steps:
- uses: actions/checkout@v5
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v15
with:
name: rosenpass
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
- name: Build
run: nix build .#packages.aarch64-darwin.rp --print-build-logs
aarch64-darwin---rosenpass-oci-image:
name: Build aarch64-darwin.rosenpass-oci-image
runs-on:
- warp-macos-13-arm64-6x
needs:
- aarch64-darwin---rosenpass
steps:
- uses: actions/checkout@v5
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v15
with:
name: rosenpass
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
- name: Build
run: nix build .#packages.aarch64-darwin.rosenpass-oci-image --print-build-logs
aarch64-darwin---check:
name: Run Nix checks on aarch64-darwin
runs-on:
- warp-macos-13-arm64-6x
steps:
- uses: actions/checkout@v5
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v15
with:
name: rosenpass
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
- name: Check
run: nix flake check . --print-build-logs

View File

@@ -15,11 +15,11 @@ jobs:
i686-linux---default:
name: Build i686-linux.default
runs-on:
- ubicloud-standard-2-ubuntu-2204
- ubuntu-latest
needs:
- i686-linux---rosenpass
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
@@ -32,10 +32,10 @@ jobs:
i686-linux---rosenpass:
name: Build i686-linux.rosenpass
runs-on:
- ubicloud-standard-2-ubuntu-2204
- ubuntu-latest
needs: []
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
@@ -48,11 +48,11 @@ jobs:
i686-linux---rosenpass-oci-image:
name: Build i686-linux.rosenpass-oci-image
runs-on:
- ubicloud-standard-2-ubuntu-2204
- ubuntu-latest
needs:
- i686-linux---rosenpass
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
@@ -65,9 +65,9 @@ jobs:
i686-linux---check:
name: Run Nix checks on i686-linux
runs-on:
- ubicloud-standard-2-ubuntu-2204
- ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
@@ -76,16 +76,115 @@ jobs:
name: rosenpass
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
- name: Check
run: |
nix flake check . --print-build-logs
run: nix flake check . --print-build-logs
x86_64-darwin---default:
name: Build x86_64-darwin.default
runs-on:
- macos-13
needs:
- x86_64-darwin---rosenpass
steps:
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v15
with:
name: rosenpass
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
- name: Build
run: nix build .#packages.x86_64-darwin.default --print-build-logs
x86_64-darwin---release-package:
name: Build x86_64-darwin.release-package
runs-on:
- macos-13
needs:
- x86_64-darwin---rosenpass
- x86_64-darwin---rp
- x86_64-darwin---rosenpass-oci-image
steps:
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v15
with:
name: rosenpass
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
- name: Build
run: nix build .#packages.x86_64-darwin.release-package --print-build-logs
x86_64-darwin---rosenpass:
name: Build x86_64-darwin.rosenpass
runs-on:
- macos-13
needs: []
steps:
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v15
with:
name: rosenpass
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
- name: Build
run: nix build .#packages.x86_64-darwin.rosenpass --print-build-logs
x86_64-darwin---rp:
name: Build x86_64-darwin.rp
runs-on:
- macos-13
needs: []
steps:
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v15
with:
name: rosenpass
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
- name: Build
run: nix build .#packages.x86_64-darwin.rp --print-build-logs
x86_64-darwin---rosenpass-oci-image:
name: Build x86_64-darwin.rosenpass-oci-image
runs-on:
- macos-13
needs:
- x86_64-darwin---rosenpass
steps:
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v15
with:
name: rosenpass
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
- name: Build
run: nix build .#packages.x86_64-darwin.rosenpass-oci-image --print-build-logs
x86_64-darwin---check:
name: Run Nix checks on x86_64-darwin
runs-on:
- macos-13
steps:
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v15
with:
name: rosenpass
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
- name: Check
run: nix flake check . --print-build-logs
x86_64-linux---default:
name: Build x86_64-linux.default
runs-on:
- ubicloud-standard-2-ubuntu-2204
- ubuntu-latest
needs:
- x86_64-linux---rosenpass
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
@@ -98,11 +197,11 @@ jobs:
x86_64-linux---proof-proverif:
name: Build x86_64-linux.proof-proverif
runs-on:
- ubicloud-standard-2-ubuntu-2204
- ubuntu-latest
needs:
- x86_64-linux---proverif-patched
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
@@ -115,10 +214,10 @@ jobs:
x86_64-linux---proverif-patched:
name: Build x86_64-linux.proverif-patched
runs-on:
- ubicloud-standard-2-ubuntu-2204
- ubuntu-latest
needs: []
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
@@ -131,13 +230,13 @@ jobs:
x86_64-linux---release-package:
name: Build x86_64-linux.release-package
runs-on:
- ubicloud-standard-2-ubuntu-2204
- ubuntu-latest
needs:
- x86_64-linux---rosenpass-static
- x86_64-linux---rosenpass-static-oci-image
- x86_64-linux---rp-static
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
@@ -150,7 +249,7 @@ jobs:
# aarch64-linux---release-package:
# name: Build aarch64-linux.release-package
# runs-on:
# - ubicloud-standard-2-arm-ubuntu-2204
# - ubuntu-latest
# needs:
# - aarch64-linux---rosenpass-oci-image
# - aarch64-linux---rosenpass
@@ -159,7 +258,7 @@ jobs:
# - run: |
# DEBIAN_FRONTEND=noninteractive
# sudo apt-get update -q -y && sudo apt-get install -q -y qemu-system-aarch64 qemu-efi binfmt-support qemu-user-static
# - uses: actions/checkout@v5
# - uses: actions/checkout@v4
# - uses: cachix/install-nix-action@v30
# with:
# nix_path: nixpkgs=channel:nixos-unstable
@@ -174,10 +273,10 @@ jobs:
x86_64-linux---rosenpass:
name: Build x86_64-linux.rosenpass
runs-on:
- ubicloud-standard-2-ubuntu-2204
- ubuntu-latest
needs: []
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
@@ -190,13 +289,13 @@ jobs:
aarch64-linux---rosenpass:
name: Build aarch64-linux.rosenpass
runs-on:
- ubicloud-standard-2-arm-ubuntu-2204
- ubuntu-latest
needs: []
steps:
- run: |
DEBIAN_FRONTEND=noninteractive
sudo apt-get update -q -y && sudo apt-get install -q -y qemu-system-aarch64 qemu-efi-aarch64 binfmt-support qemu-user-static
- uses: actions/checkout@v5
sudo apt-get update -q -y && sudo apt-get install -q -y qemu-system-aarch64 qemu-efi binfmt-support qemu-user-static
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
@@ -211,13 +310,13 @@ jobs:
aarch64-linux---rp:
name: Build aarch64-linux.rp
runs-on:
- ubicloud-standard-2-arm-ubuntu-2204
- ubuntu-latest
needs: []
steps:
- run: |
DEBIAN_FRONTEND=noninteractive
sudo apt-get update -q -y && sudo apt-get install -q -y qemu-system-aarch64 qemu-efi-aarch64 binfmt-support qemu-user-static
- uses: actions/checkout@v5
sudo apt-get update -q -y && sudo apt-get install -q -y qemu-system-aarch64 qemu-efi binfmt-support qemu-user-static
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
@@ -232,11 +331,11 @@ jobs:
x86_64-linux---rosenpass-oci-image:
name: Build x86_64-linux.rosenpass-oci-image
runs-on:
- ubicloud-standard-2-ubuntu-2204
- ubuntu-latest
needs:
- x86_64-linux---rosenpass
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
@@ -249,14 +348,14 @@ jobs:
aarch64-linux---rosenpass-oci-image:
name: Build aarch64-linux.rosenpass-oci-image
runs-on:
- ubicloud-standard-2-arm-ubuntu-2204
- ubuntu-latest
needs:
- aarch64-linux---rosenpass
steps:
- run: |
DEBIAN_FRONTEND=noninteractive
sudo apt-get update -q -y && sudo apt-get install -q -y qemu-system-aarch64 qemu-efi-aarch64 binfmt-support qemu-user-static
- uses: actions/checkout@v5
sudo apt-get update -q -y && sudo apt-get install -q -y qemu-system-aarch64 qemu-efi binfmt-support qemu-user-static
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
@@ -271,10 +370,10 @@ jobs:
x86_64-linux---rosenpass-static:
name: Build x86_64-linux.rosenpass-static
runs-on:
- ubicloud-standard-2-ubuntu-2204
- ubuntu-latest
needs: []
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
@@ -287,10 +386,10 @@ jobs:
x86_64-linux---rp-static:
name: Build x86_64-linux.rp-static
runs-on:
- ubicloud-standard-2-ubuntu-2204
- ubuntu-latest
needs: []
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
@@ -303,11 +402,11 @@ jobs:
x86_64-linux---rosenpass-static-oci-image:
name: Build x86_64-linux.rosenpass-static-oci-image
runs-on:
- ubicloud-standard-2-ubuntu-2204
- ubuntu-latest
needs:
- x86_64-linux---rosenpass-static
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
@@ -320,10 +419,10 @@ jobs:
x86_64-linux---whitepaper:
name: Build x86_64-linux.whitepaper
runs-on:
- ubicloud-standard-2-ubuntu-2204
- ubuntu-latest
needs: []
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
@@ -336,9 +435,9 @@ jobs:
x86_64-linux---check:
name: Run Nix checks on x86_64-linux
runs-on:
- ubicloud-standard-2-ubuntu-2204
- ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
@@ -350,10 +449,10 @@ jobs:
run: nix flake check . --print-build-logs
x86_64-linux---whitepaper-upload:
name: Upload whitepaper x86_64-linux
runs-on: ubicloud-standard-2-ubuntu-2204
runs-on: ubuntu-latest
if: ${{ github.ref == 'refs/heads/main' }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable

View File

@@ -1,32 +0,0 @@
name: QC Mac
on:
push:
branches: [main]
workflow_call:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
permissions:
checks: write
contents: read
jobs:
cargo-test-mac:
runs-on: warp-macos-13-arm64-6x
steps:
- uses: actions/checkout@v5
- 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') }}
# liboqs requires quite a lot of stack memory, thus we adjust
# the default stack size picked for new threads (which is used
# by `cargo test`) to be _big enough_. Setting it to 8 MiB
- run: RUST_MIN_STACK=8388608 cargo test --workspace --all-features

View File

@@ -14,49 +14,33 @@ permissions:
jobs:
prettier:
runs-on: ubicloud-standard-2-ubuntu-2204
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: actionsx/prettier@v3
with:
args: --check .
shellcheck:
name: Shellcheck
runs-on: ubicloud-standard-2-ubuntu-2204
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- name: Run ShellCheck
uses: ludeeus/action-shellcheck@master
rustfmt:
name: Rust code formatting
runs-on: ubicloud-standard-2-ubuntu-2204
name: Rust Format
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- 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
- uses: actions/checkout@v4
- name: Run Rust Formatting Script
run: bash format_rust_code.sh --mode check
cargo-bench:
runs-on: ubicloud-standard-2-ubuntu-2204
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: actions/cache@v4
with:
path: |
@@ -73,26 +57,26 @@ jobs:
mandoc:
name: mandoc
runs-on: ubicloud-standard-2-ubuntu-2204
runs-on: ubuntu-latest
steps:
- name: Install mandoc
run: sudo apt-get install -y mandoc
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- name: Check rp.1
run: doc/check.sh doc/rp.1
cargo-audit:
runs-on: ubicloud-standard-2-ubuntu-2204
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: actions-rs/audit-check@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
cargo-clippy:
runs-on: ubicloud-standard-2-ubuntu-2204
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: actions/cache@v4
with:
path: |
@@ -109,9 +93,9 @@ jobs:
args: --all-features
cargo-doc:
runs-on: ubicloud-standard-2-ubuntu-2204
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: actions/cache@v4
with:
path: |
@@ -128,9 +112,14 @@ jobs:
- run: RUSTDOCFLAGS="-D warnings" cargo doc --no-deps --document-private-items
cargo-test:
runs-on: ubicloud-standard-2-ubuntu-2204
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-13]
# - ubuntu is x86-64
# - macos-13 is also x86-64 architecture
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: actions/cache@v4
with:
path: |
@@ -147,9 +136,9 @@ jobs:
cargo-test-nix-devshell-x86_64-linux:
runs-on:
- ubicloud-standard-2-ubuntu-2204
- ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: actions/cache@v4
with:
path: |
@@ -169,9 +158,9 @@ jobs:
- run: nix develop --command cargo test --workspace --all-features
cargo-fuzz:
runs-on: ubicloud-standard-2-ubuntu-2204
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: actions/cache@v4
with:
path: |
@@ -184,7 +173,7 @@ jobs:
- name: Install nightly toolchain
run: |
rustup toolchain install nightly
rustup override set nightly
rustup default nightly
- name: Install cargo-fuzz
run: cargo install cargo-fuzz
- name: Run fuzzing
@@ -202,24 +191,10 @@ jobs:
cargo fuzz run fuzz_vec_secret_alloc_memfdsec_mallocfb -- -max_total_time=5
codecov:
runs-on: ubicloud-standard-2-ubuntu-2204
env:
RUSTUP_TOOLCHAIN: nightly
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- 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
- uses: actions/checkout@v4
- run: rustup default nightly
- run: rustup component add llvm-tools-preview
- run: |
cargo install cargo-llvm-cov || true
@@ -233,4 +208,5 @@ jobs:
with:
files: ./target/grcov/lcov
verbose: true
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

View File

@@ -14,9 +14,9 @@ permissions:
jobs:
multi-peer:
runs-on: ubicloud-standard-2-ubuntu-2204
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- run: cargo build --bin rosenpass --release
- run: python misc/generate_configs.py
- run: chmod +x .ci/run-regression.sh
@@ -25,9 +25,9 @@ jobs:
[ $(ls -1 output/ate/out | wc -l) -eq 100 ]
boot-race:
runs-on: ubicloud-standard-2-ubuntu-2204
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- run: cargo build --bin rosenpass --release
- run: chmod +x .ci/boot_race/run.sh
- run: cargo run --release --bin rosenpass gen-keys .ci/boot_race/a.toml

View File

@@ -11,8 +11,10 @@ jobs:
runs-on:
- ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v15
with:
name: rosenpass
@@ -30,8 +32,10 @@ jobs:
runs-on:
- macos-13
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
- uses: cachix/cachix-action@v15
with:
name: rosenpass
@@ -49,7 +53,7 @@ jobs:
runs-on:
- ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30
with:
nix_path: nixpkgs=channel:nixos-unstable
@@ -65,24 +69,3 @@ jobs:
draft: ${{ contains(github.ref_name, 'rc') }}
prerelease: ${{ contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') }}
files: result/*
linux-packages:
name: Build and upload DEB and RPM packages
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: cachix/install-nix-action@v30
- uses: cachix/cachix-action@v15
with:
name: rosenpass
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
- name: Build DEB & RPM package
run: |
mkdir packages
for f in $(nix build .#package-deb .#package-rpm --print-out-paths); do cp "$f" "packages/${f#*-}"; done
- name: Release
uses: softprops/action-gh-release@v2
with:
draft: ${{ contains(github.ref_name, 'rc') }}
prerelease: ${{ contains(github.ref_name, 'alpha') || contains(github.ref_name, 'beta') }}
files: |
packages/*

View File

@@ -1,177 +0,0 @@
name: Supply-Chain
on:
pull_request:
push:
branches: [main]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
cargo-deny:
name: Deny dependencies with vulnerabilities or incompatible licenses
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: EmbarkStudios/cargo-deny-action@v2
cargo-supply-chain:
name: Supply Chain Report
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
~/.cache/cargo-supply-chain/
key: cargo-supply-chain-cache
- name: Install nightly toolchain
run: |
rustup toolchain install nightly
rustup override set nightly
- uses: actions/cache@v4
with:
path: ${{ runner.tool_cache }}/cargo-supply-chain
key: cargo-supply-chain-bin
- 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
- name: Update data for cargo-supply-chain
run: cargo supply-chain update
- name: Generate cargo-supply-chain report about publishers
run: cargo supply-chain publishers
- name: Generate cargo-supply-chain report about crates
run: cargo supply-chain crates
# The setup for cargo-vet follows the recommendations in the cargo-vet documentation: https://mozilla.github.io/cargo-vet/configuring-ci.html
cargo-vet:
name: Vet Dependencies
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v5
with:
token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/cache@v4
with:
path: |
~/.cargo/bin/
~/.cargo/registry/index/
~/.cargo/registry/cache/
key: cargo-vet-cache
- name: Install nightly toolchain
run: |
rustup toolchain install nightly
rustup override set nightly
- 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: Check which event triggered this CI run, a push or a pull request.
run: |
EVENT_NAME="${{ github.event_name }}"
IS_PR="false"
IS_PUSH="false"
if [[ "$EVENT_NAME" == "pull_request" ]]; then
echo "This CI run was triggered in the context of a pull request."
IS_PR="true"
elif [[ "$EVENT_NAME" == "push" ]]; then
echo "This CI run was triggered in the context of a push."
IS_PUSH="true"
else
echo "ERROR: This CI run was not triggered in the context of a pull request or a push. Exiting with error."
exit 1
fi
echo "IS_PR=$IS_PR" >> $GITHUB_ENV
echo "IS_PUSH=$IS_PUSH" >> $GITHUB_ENV
shell: bash
- name: Check if last commit was by Dependabot
run: |
# Depending on the trigger for, the relevant commit has to be deduced differently.
if [[ "$IS_PR" == true ]]; then
# This is the commit ID for the last commit to the head branch of the pull request.
# If we used github.sha here instead, it would point to a merge commit between the PR and the main branch, which is only created for the CI run.
SHA="${{ github.event.pull_request.head.sha }}"
REF="${{ github.head_ref }}"
elif [[ "$IS_PUSH" == "true" ]]; then
SHA="${{ github.sha }}" # This is the last commit to the branch.
REF=${GITHUB_REF#refs/heads/}
else
echo "ERROR: This action only supports pull requests and push events as triggers. Exiting with error."
exit 1
fi
echo "Commit SHA is $SHA"
echo "Branch is $REF"
echo "REF=$REF" >> $GITHUB_ENV
COMMIT_AUTHOR=$(gh api repos/${{ github.repository }}/commits/$SHA --jq .author.login) # .author.login might be null, but for dependabot it will always be there and cannot be spoofed in contrast to .commit.author.name
echo "The author of the last commit is $COMMIT_AUTHOR"
if [[ "$COMMIT_AUTHOR" == "dependabot[bot]" ]]; then
echo "The last commit was made by dependabot"
LAST_COMMIT_IS_BY_DEPENDABOT=true
else
echo "The last commit was made by $COMMIT_AUTHOR not by dependabot"
LAST_COMMIT_IS_BY_DEPENDABOT=false
fi
echo "LAST_COMMIT_IS_BY_DEPENDABOT=$LAST_COMMIT_IS_BY_DEPENDABOT" >> $GITHUB_ENV
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
shell: bash
- name: Check if the last commit's message ends in "--regenerate-exemptions"
run: |
# Get commit message
COMMIT_MESSAGE=$(git log -1 --pretty=format:"%s")
if [[ "$COMMIT_MESSAGE" == *"--regenerate-exemptions" ]]; then
echo "The last commit message ends in --regenerate-exemptions"
REGEN_EXEMP=true
else
echo "The last commit message does not end in --regenerate-exemptions"
REGEN_EXEMP=false
fi
echo "REGEN_EXEMP=$REGEN_EXEMP" >> $GITHUB_ENV
shell: bash
- name: Check if the CI run happens in the context of a dependabot PR # Even if a PR is created by dependabot, the last commit can, and often should be, the regeneration of the cargo vet exemptions. It could also be from an individual making manual changes.
run: |
IN_DEPENDABOT_PR_CONTEXT="false"
if [[ $IS_PR == "true" && "${{ github.event.pull_request.user.login }}" == "dependabot[bot]" ]]; then
IN_DEPENDABOT_PR_CONTEXT="true"
echo "This CI run is in the context of PR by dependabot."
else
echo "This CI run is NOT in the context of PR by dependabot."
IN_DEPENDABOT_PR_CONTEXT="false"
fi
echo "IN_DEPENDABOT_PR_CONTEXT=$IN_DEPENDABOT_PR_CONTEXT" >> $GITHUB_ENV
shell: bash
- uses: actions/checkout@v5
if: env.IN_DEPENDABOT_PR_CONTEXT == 'true'
with:
token: ${{ secrets.CI_BOT_PAT }}
- name: In case of a dependabot PR, ensure that we are not in a detached HEAD state
if: env.IN_DEPENDABOT_PR_CONTEXT == 'true'
run: |
git fetch origin $REF # ensure that we are up to date.
git switch $REF # ensure that we are NOT in a detached HEAD state. This is important for the commit action in the end
shell: bash
- name: Regenerate cargo vet exemptions if we are in the context of a PR created by dependabot and the last commit is by dependabot or a regeneration of cargo vet exemptions was explicitly requested.
if: env.IN_DEPENDABOT_PR_CONTEXT == 'true' && (env.LAST_COMMIT_IS_BY_DEPENDABOT == 'true' || env.REGEN_EXEMP=='true') # Run only for Dependabot PRs or if specifically requested
run: cargo vet regenerate exemptions
- name: Commit and push changes if we are in the context of a PR created by dependabot and the last commit is by dependabot or a regeneration of cargo vet exemptions was explicitly requested.
if: env.IN_DEPENDABOT_PR_CONTEXT == 'true' && (env.LAST_COMMIT_IS_BY_DEPENDABOT == 'true' || env.REGEN_EXEMP=='true')
uses: stefanzweifel/git-auto-commit-action@v6
with:
commit_message: Regenerate cargo vet exemptions
commit_user_name: rosenpass-ci-bot[bot]
commit_user_email: noreply@rosenpass.eu
commit_author: Rosenpass CI Bot <noreply@rosenpass.eu>
env:
GITHUB_TOKEN: ${{ secrets.CI_BOT_PAT }}
- name: Invoke cargo-vet
run: cargo vet --locked

1
.gitignore vendored
View File

@@ -25,4 +25,3 @@ _markdown_*
.vscode
/output
.nixos-test-history

1117
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -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,64 +42,52 @@ 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"
log = { version = "0.4.27" }
log = { version = "0.4.22" }
clap = { version = "4.5.23", features = ["derive"] }
clap_mangen = "0.2.29"
clap_mangen = "0.2.24"
clap_complete = "4.5.40"
serde = { version = "1.0.217", features = ["derive"] }
serde = { version = "1.0.216", features = ["derive"] }
arbitrary = { version = "1.4.1", features = ["derive"] }
anyhow = { version = "1.0.98", features = ["backtrace", "std"] }
anyhow = { version = "1.0.94", features = ["backtrace", "std"] }
mio = { version = "1.0.3", features = ["net", "os-poll"] }
signal-hook-mio = { version = "0.2.4", features = ["support-v1_0"] }
signal-hook = "0.3.17"
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
home = "0.5.9"
derive_builder = "0.20.1"
tokio = { version = "1.46", features = ["macros", "rt-multi-thread"] }
tokio = { version = "1.42", features = ["macros", "rt-multi-thread"] }
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-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" }
lazy_static = "1.5"
signal-hook = "0.3.17"
#Dev dependencies
assert_tv = { version = "0.6.4" }
base64 = { version = "0.22.1" }
serial_test = "3.2.0"
tempfile = "3"
stacker = "0.1.21"
stacker = "0.1.17"
libfuzzer-sys = "0.4"
test_bin = "0.4.0"
criterion = "0.5.1"
criterion = "0.4.0"
allocator-api2-tests = "0.2.15"
procspawn = { version = "1.0.1", features = ["test-support"] }
serde_json = { version = "1.0.140" }
#Broker dependencies (might need cleanup or changes)
wireguard-uapi = { version = "3.0.0", features = ["xplatform"] }
command-fds = "0.2.3"
rustix = { version = "0.38.42", features = ["net", "fs", "process"] }
futures = "0.3"
futures-util = "0.3"
x25519-dalek = "2"

View File

@@ -0,0 +1,25 @@
#define INITIATOR_TEST 1
#include "rosenpass/03_identity_hiding.mpv"
// nounif a:Atom, s:seed, a2:Atom;
// ConsumeSeed(a, s, a2) / 6300[conclusion].
nounif v:seed_prec; attacker(prepare_seed(trusted_seed( v )))/6217[hypothesis].
nounif v:seed; attacker(prepare_seed( v ))/6216[hypothesis].
nounif v:seed; attacker(rng_kem_sk( v ))/6215[hypothesis].
nounif v:seed; attacker(rng_key( v ))/6214[hypothesis].
nounif v:key_prec; attacker(prepare_key(trusted_key( v )))/6213[hypothesis].
nounif v:kem_sk_prec; attacker(prepare_kem_sk(trusted_kem_sk( v )))/6212[hypothesis].
nounif v:key; attacker(prepare_key( v ))/6211[hypothesis].
nounif v:kem_sk; attacker(prepare_kem_sk( v ))/6210[hypothesis].
nounif Spk:kem_sk_tmpl;
attacker(Creveal_kem_pk(Spk))/6110[conclusion].
nounif sid:SessionId, Ssskm:kem_sk_tmpl, Spsk:key_tmpl, Sspkt:kem_sk_tmpl, Seski:seed_tmpl, Ssptr:seed_tmpl;
attacker(Cinitiator( *sid, *Ssskm, *Spsk, *Sspkt, *Seski, *Ssptr ))/6109[conclusion].
nounif sid:SessionId, biscuit_no:Atom, Ssskm:kem_sk_tmpl, Spsk:key_tmpl, Sspkt:kem_sk_tmpl, Septi:seed_tmpl, Sspti:seed_tmpl, ih:InitHello_t;
attacker(Cinit_hello( *sid, *biscuit_no, *Ssskm, *Spsk, *Sspkt, *Septi, *Sspti, *ih ))/6108[conclusion].
nounif rh:RespHello_t;
attacker(Cresp_hello( *rh ))/6107[conclusion].
nounif Ssskm:kem_sk_tmpl, Spsk:key_tmpl, Sspkt:kem_sk_tmpl, ic:InitConf_t;
attacker(Cinit_conf( *Ssskm, *Spsk, *Sspkt, *ic ))/6106[conclusion].

View File

@@ -0,0 +1,96 @@
#define RESPONDER_TEST 1
#include "rosenpass/03_identity_hiding.mpv"
// select k:kem_pk,ih: InitHello_t; attacker(prf(prf(prf(prf(key0, PROTOCOL), MAC), kem_pk2b(k) ), IH2b(ih))) phase 1/6300[hypothesis].
// select epki:kem_pk, sctr:bits, pidiC:bits, auth:bits, epki2:kem_pk, sctr2:bits, pidiC2:bits, auth2:bits;
// mess(D, prf(prf(prf(prf(key0,PROTOCOL),MAC),kem_pk2b(kem_pub(trusted_kem_sk(responder1)))),
// IH2b(InitHello(secure_sidi, *epki, *sctr, *pidiC, *auth)))
// ) [hypothesis, conclusion].
// select epki:kem_pk, sctr:bits, pidiC:bits, auth:bits, epki2:kem_pk, sctr2:bits, pidiC2:bits, auth2:bits;
// attacker(choice[prf(prf(prf(prf(key0,PROTOCOL),MAC),kem_pk2b(kem_pub(trusted_kem_sk(responder1)))),
// IH2b(InitHello(secure_sidi, *epki, *sctr, *pidiC, *auth))),
// prf(prf(prf(prf(key0,PROTOCOL),MAC),kem_pk2b(kem_pub(trusted_kem_sk(responder2)))),
// IH2b(InitHello(secure_sidi, *epki2, *sctr2, *pidiC2, *auth2)))]
// ) [hypothesis, conclusion].
// select
// attacker(prf(prf(key0,PROTOCOL),MAC)) [hypothesis, conclusion].
// select
// attacker(prf(key0,PROTOCOL)) [conclusion].
// select
// attacker(key0) [conclusion].
// select
// attacker(PROTOCOL) [conclusion].
// select
// attacker(kem_pub(trusted_kem_sk(responder1))) /9999 [hypothesis, conclusion].
// select
// attacker(kem_pub(trusted_kem_sk(responder2))) /9999 [hypothesis, conclusion].
// nounif ih:InitHello_t;
// attacker(ih) / 9999 [hypothesis].
// nounif rh:RespHello_t;
// attacker(rh) / 9999 [hypothesis].
// nounif ic:InitConf_t;
// attacker(ic) / 9999 [hypothesis].
// nounif k:key;
// attacker(ck_hs_enc( *k )) [hypothesis, conclusion].
// nounif k:key;
// attacker(ck_hs_enc( *k )) phase 1 [hypothesis, conclusion].
// nounif k:key, b:bits;
// attacker(ck_mix( *k , *b )) [hypothesis, conclusion].
// nounif k:key, b:bits;
// attacker(ck_mix( *k , *b ))phase 1 [hypothesis, conclusion].
// // select k:kem_pk, epki2:kem_pk, sctr2:bits, pidiC2:bits, auth2:bits, epki:kem_pk, sctr:bits, pidiC:bits, auth:bits;
// // attacker(choice[Envelope(prf(prf(prf(prf(key0,PROTOCOL),MAC),kem_pub(trusted_kem_sk(responder1))),
// // InitHello(secure_sidi, *epki2, *sctr2, *pidiC2, *auth2)
// // ), InitHello(secure_sidi, *epki2, *sctr2, *pidiC2, *auth2))
// // Envelope(prf(prf(prf(prf(key0,PROTOCOL),MAC),kem_pub(trusted_kem_sk(responder2))),
// // InitHello(secure_sidi, *epki, *sctr, *pidiC, *auth)),
// // InitHello(secure_sidi, *epki, *sctr, *pidiC, *auth))
// // ]) / 9999[hypothesis, conclusion].
// nounif k:key, b1:bits, b2:bits;
// attacker(xaead_enc( *k, *b1, *b2)) / 9999[hypothesis,conclusion].
// nounif pk:kem_pk, k:key;
// attacker(kem_enc( *pk , *k )) / 9999[hypothesis,conclusion].
// nounif sid:SessionId, biscuit_no:Atom, Ssskm:kem_sk_tmpl, Spsk:key_tmpl, Sspkt:kem_sk_tmpl, Septi:seed_tmpl, Sspti:seed_tmpl, ih:InitHello_t;
// attacker(Cinit_hello( *sid, *biscuit_no, *Ssskm, *Spsk, *Sspkt, *Septi, *Sspti, *ih ))/9999[hypothesis, conclusion].
// nounif Ssskm:kem_sk_tmpl, Spsk:key_tmpl, Sspkt:kem_sk_tmpl, ic:InitConf_t;
// attacker(Cinit_conf( *Ssskm, *Spsk, *Sspkt, *ic ))/9999[hypothesis, conclusion].
// nounif sid:SessionId, Ssskm:kem_sk_tmpl, Spsk:key_tmpl, Sspkt:kem_sk_tmpl, Seski:seed_tmpl, Ssptr:seed_tmpl;
// attacker(Cinitiator( *sid, *Ssskm, *Spsk, *Sspkt, *Seski, *Ssptr )) /9999 [hypothesis, conclusion].
// nounif sid:SessionId, biscuit_no:Atom, Ssskm:kem_sk_tmpl, Spsk:key_tmpl, Sspkt:kem_sk_tmpl, Septi:seed_tmpl, Sspti:seed_tmpl, ih:InitHello_t;
// mess(C, Cinit_hello( *sid, *biscuit_no, *Ssskm, *Spsk, *Sspkt, *Septi, *Sspti, *ih ))/9999[hypothesis, conclusion].
// nounif Ssskm:kem_sk_tmpl, Spsk:key_tmpl, Sspkt:kem_sk_tmpl, ic:InitConf_t;
// mess(C, Cinit_conf( *Ssskm, *Spsk, *Sspkt, *ic ))/9999[hypothesis, conclusion].
// nounif sid:SessionId, Ssskm:kem_sk_tmpl, Spsk:key_tmpl, Sspkt:kem_sk_tmpl, Seski:seed_tmpl, Ssptr:seed_tmpl;
// mess(C, Cinitiator( *sid, *Ssskm, *Spsk, *Sspkt, *Seski, *Ssptr )) /9999 [hypothesis, conclusion].
// nounif rh:RespHello_t;
// attacker(Cresp_hello( *rh ))[conclusion].
// nounif v:seed_prec; attacker(prepare_seed(trusted_seed( v )))/6217[hypothesis].
// nounif v:seed; attacker(prepare_seed( v ))/6216[hypothesis].
// nounif v:seed; attacker(rng_kem_sk( v ))/6215[hypothesis].
// nounif v:seed; attacker(rng_key( v ))/6214[hypothesis].
// nounif v:key_prec; attacker(prepare_key(trusted_key( v )))/6213[hypothesis].
// nounif v:kem_sk_prec; attacker(prepare_kem_sk(trusted_kem_sk( v )))/6212[hypothesis].
// nounif v:key; attacker(prepare_key( v ))/6211[hypothesis].
// nounif v:kem_sk; attacker(prepare_kem_sk( v ))/6210[hypothesis].

View File

@@ -0,0 +1,29 @@
#define INITIATOR_TEST 1
#define CUSTOM_MAIN 1
#include "rosenpass/03_identity_hiding.mpv"
let Oinitiator_bad_actor_inner(sk_tmp:kem_sk_prec) =
in(C, Cinitiator(sidi, Ssskm, Spsk, Sspkt, Seski, Ssptr));
#if RANDOMIZED_CALL_IDS
new call:Atom;
#else
call <- Cinitiator(sidi, Ssskm, Spsk, Sspkt, Seski, Ssptr);
#endif
in(C, last_cookie:key);
tmpl <- make_trusted_kem_sk(sk_tmp);
out(C, setup_kem_sk(tmpl));
Oinitiator_inner(sidi, Ssskm, Spsk, tmpl, Seski, Ssptr, last_cookie, C, call).
let Oinitiator_bad_actor() =
Oinitiator_bad_actor_inner(responder1) | Oinitiator_bad_actor_inner(responder2) | Oinitiator_bad_actor_inner(initiator1) | Oinitiator_bad_actor_inner(initiator2).
let identity_hiding_main2() =
0 | Oinitiator_bad_actor() | rosenpass_main2() | participants_communication() | phase 1; secretCommunication().
let main = identity_hiding_main2.

View File

@@ -0,0 +1,136 @@
#define CHAINING_KEY_EVENTS 1
#define MESSAGE_TRANSMISSION_EVENTS 0
#define SESSION_START_EVENTS 0
#define RANDOMIZED_CALL_IDS 0
#define COOKIE_EVENTS 1
#define KEM_EVENTS 1
#include "config.mpv"
#include "prelude/basic.mpv"
#include "crypto/key.mpv"
#include "crypto/kem.mpv"
#include "rosenpass/handshake_state.mpv"
/* The cookie data structure is implemented based on the WireGuard protocol.
* The ip and port is based purely on the public key and the implementation of the private cookie key is intended to mirror the biscuit key.
* The code tests the response to a possible DOS attack by setting up alternative branches for the protocol
* processes: Oinit_conf, Oinit_hello and resp_hello to simulate what happens when the responder or initiator is overloaded.
* When under heavy load a valid cookie is required. When such a cookie is not present a cookie message is sent as a response.
* Queries then test to make sure that expensive KEM operations are only conducted after a cookie has been successfully validated.
*/
type CookieMsg_t.
fun CookieMsg(
SessionId, // sender
bits, // nonce
bits // cookie
) : CookieMsg_t [data].
#define COOKIE_EVENTS(eventLbl) \
COOKIE_EV(event MCAT(eventLbl, _UnderLoadEV) (SessionId, SessionId, Atom).) \
COOKIE_EV(event MCAT(eventLbl, _CookieValidated) (SessionId, SessionId, Atom).) \
COOKIE_EV(event MCAT(eventLbl, _CookieSent) (SessionId, SessionId, Atom, CookieMsg_t).)
fun cookie_key(kem_sk) : key [private].
fun ip_and_port(kem_pk):bits.
letfun create_mac2_key(sskm:kem_sk, spkt:kem_pk) = prf(cookie_key(sskm), ip_and_port(spkt)).
letfun create_cookie(sskm:kem_sk, spkm:kem_pk, spkt:kem_pk, nonce:bits, msg:bits) = xaead_enc(lprf2(COOKIE, kem_pk2b(spkm), nonce),
k2b(create_mac2_key(sskm, spkm)), msg).
#define COOKIE_PROCESS(eventLbl, innerFunc) \
new nonce:bits; \
in(C, Ccookie(mac1, mac2)); \
COOKIE_EV(event MCAT(eventLbl, _UnderLoadEV) (sidi, sidr, call);) \
msgB <- Envelope(mac1, msg); \
mac2_key <- create_mac2_key(sskm, spkt); \
if k2b(create_mac2(mac2_key, msgB)) = mac2 then \
COOKIE_EV(event MCAT(eventLbl, _CookieValidated) (sidi, sidr, call);) \
innerFunc \
else \
cookie <- create_cookie(sskm, spkm, spkt, nonce, msg); \
cookie_msg <- CookieMsg(sidi, nonce, cookie); \
COOKIE_EV(event MCAT(eventLbl, _CookieSent) (sidi, sidr, call, cookie_msg);) \
out(C, cookie_msg). \
#include "rosenpass/oracles.mpv"
#include "rosenpass/responder.macro"
COOKIE_EVENTS(Oinit_conf)
let Oinit_conf_underLoad() =
in(C, Cinit_conf(Ssskm, Spsk, Sspkt, ic));
in(C, last_cookie:bits);
msg <- IC2b(ic);
let InitConf(sidi, sidr, biscuit, auth) = ic in
new call:Atom;
SETUP_HANDSHAKE_STATE()
COOKIE_PROCESS(Oinit_conf, Oinit_conf_inner(Ssskm, Spsk, Sspkt, ic, call))
#include "rosenpass/responder.macro"
COOKIE_EVENTS(Oinit_hello)
let Oinit_hello_underLoad() =
in(C, Cinit_hello(sidr, biscuit_no, Ssskm, Spsk, Sspkt, Septi, Sspti, ih));
in(C, Oinit_hello_last_cookie:key);
new call:Atom;
msg <- IH2b(ih);
let InitHello(sidi, epki, sctr, pidic, auth) = ih in
SETUP_HANDSHAKE_STATE()
COOKIE_PROCESS(Oinit_hello, Oinit_hello_inner(sidr, biscuit_no, Ssskm, Spsk, Sspkt, Septi, Sspti, ih, Oinit_hello_last_cookie, C, call))
let rosenpass_dos_main() = 0
| !Oreveal_kem_pk
| REP(INITIATOR_BOUND, Oinitiator)
| REP(RESPONDER_BOUND, Oinit_hello)
| REP(RESPONDER_BOUND, Oinit_conf)
| REP(RESPONDER_BOUND, Oinit_hello_underLoad)
| REP(RESPONDER_BOUND, Oinit_conf_underLoad).
let main = rosenpass_dos_main.
select cookie:CookieMsg_t; attacker(cookie)/6220[hypothesis].
nounif v:key; attacker(prepare_key( v ))/6217[hypothesis].
nounif v:seed; attacker(prepare_seed( v ))/6216[hypothesis].
nounif v:seed; attacker(prepare_seed( v ))/6216[hypothesis].
nounif v:seed; attacker(rng_kem_sk( v ))/6215[hypothesis].
nounif v:seed; attacker(rng_key( v ))/6214[hypothesis].
nounif v:kem_sk; attacker(prepare_kem_sk( v ))/6210[hypothesis].
// nounif Spk:kem_sk_tmpl;
// attacker(Creveal_kem_pk(Spk))/6110[conclusion].
// nounif sid:SessionId, Ssskm:kem_sk_tmpl, Spsk:key_tmpl, Sspkt:kem_sk_tmpl, Seski:seed_tmpl, Ssptr:seed_tmpl;
// attacker(Cinitiator( *sid, *Ssskm, *Spsk, *Sspkt, *Seski, *Ssptr ))/6109[conclusion].
// nounif sid:SessionId, biscuit_no:Atom, Ssskm:kem_sk_tmpl, Spsk:key_tmpl, Sspkt:kem_sk_tmpl, Septi:seed_tmpl, Sspti:seed_tmpl, ih:InitHello_t;
// attacker(Cinit_hello( *sid, *biscuit_no, *Ssskm, *Spsk, *Sspkt, *Septi, *Sspti, *ih ))/6108[conclusion].
nounif rh:RespHello_t;
attacker(Cresp_hello( *rh ))/6107[conclusion].
nounif Ssskm:kem_sk_tmpl, Spsk:key_tmpl, Sspkt:kem_sk_tmpl, ic:InitConf_t;
attacker(Cinit_conf( *Ssskm, *Spsk, *Sspkt, *ic ))/6106[conclusion].
@reachable "DOS protection: cookie sent"
query sidi:SessionId, sidr:SessionId, call:Atom, cookieMsg:CookieMsg_t;
event (Oinit_hello_CookieSent(sidi, sidr, call, cookieMsg)).
@lemma "DOS protection: Oinit_hello kem use when under load implies validated cookie"
lemma sidi:SessionId, sidr:SessionId, call:Atom;
event(Oinit_hello_UnderLoadEV(sidi, sidr, call))
&& event(Oinit_hello_KemUse(sidi, sidr, call))
==> event(Oinit_hello_CookieValidated(sidi, sidr, call)).
@lemma "DOS protection: Oinit_conf kem use when under load implies validated cookie"
lemma sidi:SessionId, sidr:SessionId, call:Atom;
event(Oinit_conf_UnderLoadEV(sidi, sidr, call))
&& event(Oinit_conf_KemUse(sidi, sidr, call))
==> event(Oinit_conf_CookieValidated(sidi, sidr, call)).
@lemma "DOS protection: Oresp_hello kem use when under load implies validated cookie"
lemma sidi:SessionId, sidr:SessionId, call:Atom;
event(Oresp_hello_UnderLoadEV(sidi, sidr, call))
&& event(Oresp_hello_KemUse(sidi, sidr, call))
==> event(Oresp_hello_CookieValidated(sidi, sidr, call)).

View File

@@ -58,7 +58,7 @@ let secure_init_hello(initiator: kem_sk_tmpl, sidi : SessionId, psk: key_tmpl, r
new epkit:kem_pk; // epki
new sctrt:bits; // sctr
new pidi_ct:bits; // pidi_ct
new pidiCt:bits; // pidiC
new autht:bits; // auth
NEW_TRUSTED_SEED(seski_trusted_seed)
@@ -70,9 +70,9 @@ let secure_init_hello(initiator: kem_sk_tmpl, sidi : SessionId, psk: key_tmpl, r
let secure_resp_hello(initiator: kem_sk_tmpl, responder: kem_sk_tmpl, sidi:SessionId, sidr:SessionId, biscuit_no:Atom, psk:key_tmpl) =
in(D, InitHello(=secure_sidi, epki, sctr, pidi_ct, auth));
in(D, InitHello(=secure_sidi, epki, sctr, pidiC, auth));
ih <- InitHello(sidi, epki, sctr, pidi_ct, auth);
ih <- InitHello(sidi, epki, sctr, pidiC, auth);
NEW_TRUSTED_SEED(septi_trusted_seed)
NEW_TRUSTED_SEED(sspti_trusted_seed)
new last_cookie:key;

View File

@@ -19,7 +19,7 @@ fun CookieMsg(
COOKIE_EV(event MCAT(eventLbl, _UnderLoadEV) (spkm, spkt, last_cookie);) \
msgB <- Envelope(mac1, RH2b(rh)); \
mac2_key <- create_mac2_key(sskm, spkt) \
let RespHello(sidi, sidr, ecti, scti, biscuit_ct, auth) = rh in \
let RespHello(sidi, sidr, ecti, scti, biscuit, auth) = rh in \
if Envelope(mac2_key, msgB) = mac2 then \
COOKIE_EV(event MCAT(eventLbl, _CookieValidated) (spkm, last_cookie);) \
innerFunc \

View File

@@ -143,10 +143,10 @@ letfun ENCRYPT_AND_MIX(ct, pt) \
// TODO: Migrate kems to use binary ciphertexts directly
#define ENCAPS_AND_MIX(ct, pk, shk) \
ct <- kem_enc(pk, shk); \
MIX3(kem_pk2b(pk), k2b(shk), ct)
MIX3(kem_pk2b(pk), ct, k2b(shk))
#define DECAPS_AND_MIX(sk, pk, ct) \
DUMMY(shk) <- kem_dec(sk, ct); \
MIX3(kem_pk2b(pk), k2b(DUMMY(shk)), ct)
MIX3(kem_pk2b(pk), ct, k2b(DUMMY(shk)))
// biscuits

View File

@@ -86,8 +86,8 @@ MTX_EV( event RHRjct(RespHello_t, key, kem_sk, kem_pk). )
MTX_EV( event ICSent(RespHello_t, InitConf_t, key, kem_sk, kem_pk). )
SES_EV( event InitiatorSession(RespHello_t, key). )
let Oresp_hello(HS_DECL_ARGS) =
in(C, Cresp_hello(RespHello(sidr, =sidi, ecti, scti, biscuit_ct, auth)));
rh <- RespHello(sidr, sidi, ecti, scti, biscuit_ct, auth);
in(C, Cresp_hello(RespHello(sidr, =sidi, ecti, scti, biscuit, auth)));
rh <- RespHello(sidr, sidi, ecti, scti, biscuit, auth);
/* try */ let ic = (
ck_ini <- ck;
RESPHELLO_CONSUME()
@@ -124,7 +124,7 @@ let Oinit_hello() =
call <- Cinit_hello(sidr, biscuit_no, Ssskm, Spsk, Sspkt, Septi, Sspti, ih);
#endif
// TODO: This is ugly
let InitHello(sidi, epki, sctr, pidi_ct, auth) = ih in
let InitHello(sidi, epki, sctr, pidiC, auth) = ih in
SETUP_HANDSHAKE_STATE()
eski <- kem_sk0;
epti <- rng_key(setup_seed(Septi)); // RHR4

View File

@@ -7,7 +7,7 @@ fun InitHello(
SessionId, // sidi
kem_pk, // epki
bits, // sctr
bits, // pidi_ct
bits, // pidiC
bits // auth
) : InitHello_t [data].
@@ -17,16 +17,16 @@ fun InitHello(
/* not handled here */ /* IHI3 */ \
MIX2(sid2b(sidi), kem_pk2b(epki)) /* IHI4 */ \
ENCAPS_AND_MIX(sctr, spkr, sptr) /* IHI5 */ \
ENCRYPT_AND_MIX(pidi_ct, pidi) /* IHI6 */ \
ENCRYPT_AND_MIX(pidiC, pidi) /* IHI6 */ \
MIX2(kem_pk2b(spki), k2b(psk)) /* IHI7 */ \
ENCRYPT_AND_MIX(auth, empty) /* IHI8 */ \
ih <- InitHello(sidi, epki, sctr, pidi_ct, auth);
ih <- InitHello(sidi, epki, sctr, pidiC, auth);
#define INITHELLO_CONSUME() \
ck <- lprf1(CK_INIT, kem_pk2b(spkr)); /* IHR1 */ \
MIX2(sid2b(sidi), kem_pk2b(epki)) /* IHR4 */ \
DECAPS_AND_MIX(sskr, spkr, sctr) /* IHR5 */ \
DECRYPT_AND_MIX(pid, pidi_ct) /* IHR6 */ \
DECRYPT_AND_MIX(pid, pidiC) /* IHR6 */ \
LOOKUP_SENDER(pid) /* IHR6 */ \
MIX2(kem_pk2b(spki), k2b(psk)) /* IHR7 */ \
DECRYPT_AND_MIX(DUMMY(empty), auth)
@@ -46,17 +46,17 @@ fun RespHello(
MIX2(sid2b(sidr), sid2b(sidi)) /* RHR3 */ \
ENCAPS_AND_MIX(ecti, epki, epti) /* RHR4 */ \
ENCAPS_AND_MIX(scti, spki, spti) /* RHR5 */ \
STORE_BISCUIT(biscuit_ct) /* RHR6 */ \
STORE_BISCUIT(biscuit) /* RHR6 */ \
ENCRYPT_AND_MIX(auth, empty) /* RHR7 */ \
rh <- RespHello(sidr, sidi, ecti, scti, biscuit_ct, auth);
rh <- RespHello(sidr, sidi, ecti, scti, biscuit, auth);
#define RESPHELLO_CONSUME() \
let RespHello(sidr, sidi, ecti, scti, biscuit_ct, auth) = rh in \
let RespHello(sidr, sidi, ecti, scti, biscuit, auth) = rh in \
/* not handled here */ /* RHI2 */ \
MIX2(sid2b(sidr), sid2b(sidi)) /* RHI3 */ \
DECAPS_AND_MIX(eski, epki, ecti) /* RHI4 */ \
DECAPS_AND_MIX(sski, spki, scti) /* RHI5 */ \
MIX(biscuit_ct) /* RHI6 */ \
MIX(biscuit) /* RHI6 */ \
DECRYPT_AND_MIX(DUMMY(empty), auth) /* RHI7 */
type InitConf_t.
@@ -70,11 +70,11 @@ fun InitConf(
#define INITCONF_PRODUCE() \
MIX2(sid2b(sidi), sid2b(sidr)) /* ICI3 */ \
ENCRYPT_AND_MIX(auth, empty) /* ICI4 */ \
ic <- InitConf(sidi, sidr, biscuit_ct, auth);
ic <- InitConf(sidi, sidr, biscuit, auth);
#define INITCONF_CONSUME() \
let InitConf(sidi, sidr, biscuit_ct, auth) = ic in \
LOAD_BISCUIT(biscuit_no, biscuit_ct)/* ICR1 */ \
let InitConf(sidi, sidr, biscuit, auth) = ic in \
LOAD_BISCUIT(biscuit_no, biscuit) /* ICR1 */ \
ENCRYPT_AND_MIX(rh_auth, empty) /* ICIR */ \
ck_rh <- ck; /* ---- */ /* TODO: Move into oracles.mpv */ \
MIX2(sid2b(sidi), sid2b(sidr)) /* ICR3 */ \

View File

@@ -8,13 +8,10 @@ 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 }
rosenpass-to = { workspace = true }
[dev-dependencies]
rosenpass-oqs = { workspace = true }
rosenpass-secret-memory = { workspace = true }
anyhow = { workspace = true }
anyhow = {workspace = true}

View File

@@ -1,137 +0,0 @@
//! This module contains the traits for all the cryptographic algorithms used throughout Rosenpass.
//! These traits are marker traits that signal intent. They can also be used for trait objects.
/// Constants and trait for the Incorrect HMAC over Blake2b, with 256 key and hash length.
pub mod keyed_hash_incorrect_hmac_blake2b {
use crate::primitives::keyed_hash::*;
// These constants describe how they are used here, not what the algorithm defines.
/// The key length used in [`KeyedHashIncorrectHmacBlake2b`].
pub const KEY_LEN: usize = 32;
/// The hash length used in [`KeyedHashIncorrectHmacBlake2b`].
pub const HASH_LEN: usize = 32;
/// A [`KeyedHash`] that is an incorrect HMAC over Blake2 (a custom Rosenpass construction)
pub trait KeyedHashIncorrectHmacBlake2b: KeyedHash<KEY_LEN, HASH_LEN> {}
}
/// Constants and trait for Blake2b, with 256 key and hash length.
pub mod keyed_hash_blake2b {
use crate::primitives::keyed_hash::*;
// These constants describe how they are used here, not what the algorithm defines.
/// The key length used in [`KeyedHashBlake2b`].
pub const KEY_LEN: usize = 32;
/// The hash length used in [`KeyedHashBlake2b`].
pub const HASH_LEN: usize = 32;
/// A [`KeyedHash`] that is Blake2b
pub trait KeyedHashBlake2b: KeyedHash<KEY_LEN, HASH_LEN> {}
}
/// Constants and trait for SHAKE256, with 256 key and hash length.
pub mod keyed_hash_shake256 {
use crate::primitives::keyed_hash::*;
// These constants describe how they are used here, not what the algorithm defines.
/// The key length used in [`KeyedHashShake256`].
pub const KEY_LEN: usize = 32;
/// The hash length used in [`KeyedHashShake256`].
pub const HASH_LEN: usize = 32;
/// A [`KeyedHash`] that is SHAKE256.
pub trait KeyedHashShake256: KeyedHash<KEY_LEN, HASH_LEN> {}
}
/// Constants and trait for the ChaCha20Poly1305 AEAD
pub mod aead_chacha20poly1305 {
use crate::primitives::aead::*;
// See https://datatracker.ietf.org/doc/html/rfc7539#section-2.8
/// The key length used in [`AeadChaCha20Poly1305`].
pub const KEY_LEN: usize = 32;
/// The nonce length used in [`AeadChaCha20Poly1305`].
pub const NONCE_LEN: usize = 12;
/// The tag length used in [`AeadChaCha20Poly1305`].
pub const TAG_LEN: usize = 16;
/// An [`Aead`] that is ChaCha20Poly1305.
pub trait AeadChaCha20Poly1305: Aead<KEY_LEN, NONCE_LEN, TAG_LEN> {}
}
/// Constants and trait for the XChaCha20Poly1305 AEAD (i.e. ChaCha20Poly1305 with extended nonce
/// lengths)
pub mod aead_xchacha20poly1305 {
use crate::primitives::aead::*;
// See https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha-03
/// The key length used in [`AeadXChaCha20Poly1305`].
pub const KEY_LEN: usize = 32;
/// The nonce length used in [`AeadXChaCha20Poly1305`].
pub const NONCE_LEN: usize = 24;
/// The tag length used in [`AeadXChaCha20Poly1305`].
pub const TAG_LEN: usize = 16;
/// An [`Aead`] that is XChaCha20Poly1305.
pub trait AeadXChaCha20Poly1305: Aead<KEY_LEN, NONCE_LEN, TAG_LEN> {}
}
/// Constants and trait for the Kyber512 KEM
pub mod kem_kyber512 {
use crate::primitives::kem::*;
// page 39 of https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf
// (which is ml-kem instead of kyber, but it's the same)
/// The secret key length used in [`KemKyber512`].
pub const SK_LEN: usize = 1632;
/// The public key length used in [`KemKyber512`].
pub const PK_LEN: usize = 800;
/// The ciphertext length used in [`KemKyber512`].
pub const CT_LEN: usize = 768;
/// The shared key length used in [`KemKyber512`].
pub const SHK_LEN: usize = 32;
/// A [`Kem`] that is Kyber512.
pub trait KemKyber512: Kem<SK_LEN, PK_LEN, CT_LEN, SHK_LEN> {}
}
/// Constants and trait for the Classic McEliece 460896 KEM
pub mod kem_classic_mceliece460896 {
use crate::primitives::kem::*;
// page 6 of https://classic.mceliece.org/mceliece-impl-20221023.pdf
/// The secret key length used in [`KemClassicMceliece460896`].
pub const SK_LEN: usize = 13608;
/// The public key length used in [`KemClassicMceliece460896`].
pub const PK_LEN: usize = 524160;
/// The ciphertext length used in [`KemClassicMceliece460896`].
pub const CT_LEN: usize = 156;
/// The shared key length used in [`KemClassicMceliece460896`].
pub const SHK_LEN: usize = 32;
/// A [`Kem`] that is ClassicMceliece460896.
pub trait KemClassicMceliece460896: Kem<SK_LEN, PK_LEN, CT_LEN, SHK_LEN> {}
}
pub use aead_chacha20poly1305::AeadChaCha20Poly1305;
pub use aead_xchacha20poly1305::AeadXChaCha20Poly1305;
pub use kem_classic_mceliece460896::KemClassicMceliece460896;
pub use kem_kyber512::KemKyber512;
pub use keyed_hash_blake2b::KeyedHashBlake2b;
pub use keyed_hash_incorrect_hmac_blake2b::KeyedHashIncorrectHmacBlake2b;
pub use keyed_hash_shake256::KeyedHashShake256;

View File

@@ -1,5 +1,2 @@
//! This trait contains traits, constants and wrappers that provid= the interface between Rosenpass
//! as a consumer of cryptographic libraries and the implementations of cryptographic algorithms.
pub mod algorithms;
pub mod primitives;
mod kem;
pub use kem::Kem;

View File

@@ -1,10 +0,0 @@
//! Traits for cryptographic primitives used in Rosenpass, specifically KEM, AEAD and keyed
//! hashing.
pub(crate) mod aead;
pub(crate) mod kem;
pub(crate) mod keyed_hash;
pub use aead::{Aead, AeadWithNonceInCiphertext, Error as AeadError};
pub use kem::{Error as KemError, Kem};
pub use keyed_hash::*;

View File

@@ -1,175 +0,0 @@
use rosenpass_to::{ops::copy_slice, To as _};
use thiserror::Error;
/// Models authenticated encryption with assiciated data (AEAD) functionality.
///
/// The methods of this trait take a `&self` argument as a receiver. This has two reasons:
/// 1. It makes type inference a lot smoother
/// 2. It allows to use the functionality through a trait object or having an enum that has
/// variants for multiple options (like e.g. the `KeyedHash` enum in `rosenpass-ciphers`).
///
/// Since the caller needs an instance of the type to use the functionality, implementors are
/// adviced to implement the [`Default`] trait where possible.
///
/// Example for encrypting a message with a specific [`Aead`] instance:
/// ```
/// use rosenpass_cipher_traits::primitives::Aead;
///
/// const KEY_LEN: usize = 32;
/// const NONCE_LEN: usize = 12;
/// const TAG_LEN: usize = 16;
///
/// fn encrypt_message_given_an_aead<AeadImpl>(
/// aead: &AeadImpl,
/// msg: &str,
/// nonce: &[u8; NONCE_LEN],
/// encrypted: &mut [u8]
/// ) where AeadImpl: Aead<KEY_LEN, NONCE_LEN, TAG_LEN> {
/// let key = [0u8; KEY_LEN]; // This is not a secure key!
/// let ad = b""; // we don't need associated data here
/// aead.encrypt(encrypted, &key, nonce, ad, msg.as_bytes()).unwrap();
/// }
/// ```
///
/// If only the type (but no instance) is available, then we can still encrypt, as long as the type
/// also is [`Default`]:
/// ```
/// use rosenpass_cipher_traits::primitives::Aead;
///
/// const KEY_LEN: usize = 32;
/// const NONCE_LEN: usize = 12;
/// const TAG_LEN: usize = 16;
///
/// fn encrypt_message_without_aead<AeadImpl>(
/// msg: &str,
/// nonce: &[u8; NONCE_LEN],
/// encrypted: &mut [u8]
/// ) where AeadImpl: Default + Aead<KEY_LEN, NONCE_LEN, TAG_LEN> {
/// let key = [0u8; KEY_LEN]; // This is not a secure key!
/// let ad = b""; // we don't need associated data here
/// AeadImpl::default().encrypt(encrypted, &key, nonce, ad, msg.as_bytes()).unwrap();
/// }
/// ```
pub trait Aead<const KEY_LEN: usize, const NONCE_LEN: usize, const TAG_LEN: usize> {
const KEY_LEN: usize = KEY_LEN;
const NONCE_LEN: usize = NONCE_LEN;
const TAG_LEN: usize = TAG_LEN;
/// Encrypts `plaintext` using the given `key` and `nonce`, taking into account the additional
/// data `ad` and writes the result into `ciphertext`.
///
/// `ciphertext` must be exactly `TAG_LEN` longer than `plaintext`.
fn encrypt(
&self,
ciphertext: &mut [u8],
key: &[u8; KEY_LEN],
nonce: &[u8; NONCE_LEN],
ad: &[u8],
plaintext: &[u8],
) -> Result<(), Error>;
/// Decrypts `ciphertexttext` using the given `key` and `nonce`, taking into account the additional
/// data `ad` and writes the result into `plaintext`.
///
/// `ciphertext` must be exactly `TAG_LEN` longer than `plaintext`.
fn decrypt(
&self,
plaintext: &mut [u8],
key: &[u8; KEY_LEN],
nonce: &[u8; NONCE_LEN],
ad: &[u8],
ciphertext: &[u8],
) -> Result<(), Error>;
}
/// Provides an AEAD API where the nonce is part of the ciphertext.
///
/// The old xaead API had the ciphertext begin with the `nonce`. In order to not having to change
/// the calling code too much, we add a wrapper trait that provides this API and implement it for
/// all AEAD.
pub trait AeadWithNonceInCiphertext<
const KEY_LEN: usize,
const NONCE_LEN: usize,
const TAG_LEN: usize,
>: Aead<KEY_LEN, NONCE_LEN, TAG_LEN>
{
/// Encrypts `plaintext` using the given `key` and `nonce`, taking into account the additional
/// data `ad` and writes the result into `ciphertext`.
///
/// `ciphertext` must be exactly `TAG_LEN` + `NONCE_LEN` longer than `plaintext`.
fn encrypt_with_nonce_in_ctxt(
&self,
ciphertext: &mut [u8],
key: &[u8; KEY_LEN],
nonce: &[u8; NONCE_LEN],
ad: &[u8],
plaintext: &[u8],
) -> Result<(), Error> {
// The comparison looks complicated, but we need to do it this way to prevent
// over/underflows.
if ciphertext.len() < NONCE_LEN + TAG_LEN
|| ciphertext.len() - TAG_LEN - NONCE_LEN < plaintext.len()
{
return Err(Error::InvalidLengths);
}
let (n, rest) = ciphertext.split_at_mut(NONCE_LEN);
copy_slice(nonce).to(n);
self.encrypt(rest, key, nonce, ad, plaintext)
}
/// Decrypts `ciphertexttext` using the given `key` and `nonce`, taking into account the additional
/// data `ad` and writes the result into `plaintext`.
///
/// `ciphertext` must be exactly `TAG_LEN` + `NONCE_LEN` longer than `plaintext`.
fn decrypt_with_nonce_in_ctxt(
&self,
plaintext: &mut [u8],
key: &[u8; KEY_LEN],
ad: &[u8],
ciphertext: &[u8],
) -> Result<(), Error> {
// The comparison looks complicated, but we need to do it this way to prevent
// over/underflows.
if ciphertext.len() < NONCE_LEN + TAG_LEN
|| ciphertext.len() - TAG_LEN - NONCE_LEN < plaintext.len()
{
return Err(Error::InvalidLengths);
}
let (nonce, rest) = ciphertext.split_at(NONCE_LEN);
// We know this should be the right length (we just split it), and everything else would be
// very unexpected.
let nonce = nonce.try_into().map_err(|_| Error::InternalError)?;
self.decrypt(plaintext, key, nonce, ad, rest)
}
}
impl<
const KEY_LEN: usize,
const NONCE_LEN: usize,
const TAG_LEN: usize,
T: Aead<KEY_LEN, NONCE_LEN, TAG_LEN>,
> AeadWithNonceInCiphertext<KEY_LEN, NONCE_LEN, TAG_LEN> for T
{
}
/// The error returned by AEAD operations
#[derive(Debug, Error)]
pub enum Error {
/// An internal error occurred. This should never be happen and indicates an error in the
/// AEAD implementation.
#[error("internal error")]
InternalError,
/// Could not decrypt a message because the message is not a valid ciphertext for the given
/// key.
#[error("decryption error")]
DecryptError,
/// The provided buffers have the wrong lengths.
#[error("buffers have invalid length")]
InvalidLengths,
}

View File

@@ -1,212 +0,0 @@
//! Traits and implementations for Key Encapsulation Mechanisms (KEMs)
//!
//! KEMs are the interface provided by almost all post-quantum
//! secure key exchange mechanisms.
//!
//! Conceptually KEMs are akin to public-key encryption, but instead of encrypting
//! arbitrary data, KEMs are limited to the transmission of keys, randomly chosen during
//! encapsulation.
//!
//! The [Kem] Trait describes the basic API offered by a Key Encapsulation
//! Mechanism. Two implementations for it are provided:
//! [Kyber512](../../rosenpass_oqs/kyber_512/enum.Kyber512.html) and
//! [ClassicMceliece460896](../../rosenpass_oqs/classic_mceliece_460896/enum.ClassicMceliece460896.html).
//!
//! An example where Alice generates a keypair and gives her public key to Bob, for Bob to
//! encapsulate a symmetric key and Alice to decapsulate it would look as follows.
//! In the example, we are using Kyber512, but any KEM that correctly implements the [Kem]
//! trait could be used as well.
//!```rust
//! use rosenpass_cipher_traits::primitives::Kem;
//! use rosenpass_oqs::Kyber512;
//! # use rosenpass_secret_memory::{secret_policy_use_only_malloc_secrets, Secret};
//!
//! type MyKem = Kyber512;
//! secret_policy_use_only_malloc_secrets();
//! let mut alice_sk: Secret<{ MyKem::SK_LEN }> = Secret::zero();
//! let mut alice_pk: [u8; MyKem::PK_LEN] = [0; MyKem::PK_LEN];
//! MyKem::default().keygen(alice_sk.secret_mut(), &mut alice_pk)?;
//!
//! let mut bob_shk: Secret<{ MyKem::SHK_LEN }> = Secret::zero();
//! let mut bob_ct: [u8; MyKem::CT_LEN] = [0; MyKem::CT_LEN];
//! MyKem::default().encaps(bob_shk.secret_mut(), &mut bob_ct, &mut alice_pk)?;
//!
//! let mut alice_shk: Secret<{ MyKem::SHK_LEN }> = Secret::zero();
//! MyKem::default().decaps(alice_shk.secret_mut(), alice_sk.secret_mut(), &mut bob_ct)?;
//!
//! # assert_eq!(alice_shk.secret(), bob_shk.secret());
//! # Ok::<(), anyhow::Error>(())
//!```
//!
//! Implementing the [Kem]-trait for a KEM is easy. Mostly, you must format the KEM's
//! keys, and ciphertext as `u8` slices. Below, we provide an example for how the trait can
//! be implemented using a **HORRIBLY INSECURE** DummyKem that only uses static values for keys
//! and ciphertexts as an example.
//!```rust
//!# use rosenpass_cipher_traits::primitives::{Kem, KemError as Error};
//!
//! struct DummyKem {}
//! impl Kem<1,1,1,1> for DummyKem {
//!
//! // For this DummyKem, we will use a single `u8` for everything
//! const SK_LEN: usize = 1;
//! const PK_LEN: usize = 1;
//! const CT_LEN: usize = 1;
//! const SHK_LEN: usize = 1;
//!
//! fn keygen(&self, sk: &mut [u8;1], pk: &mut [u8;1]) -> Result<(), Error> {
//! sk[0] = 42;
//! pk[0] = 21;
//! Ok(())
//! }
//!
//! fn encaps(&self, shk: &mut [u8;1], ct: &mut [u8;1], pk: &[u8;1]) -> Result<(), Error> {
//! if pk[0] != 21 {
//! return Err(Error::InvalidArgument);
//! }
//! ct[0] = 7;
//! shk[0] = 17;
//! Ok(())
//! }
//!
//! fn decaps(&self, shk: &mut [u8;1 ], sk: &[u8;1], ct: &[u8;1]) -> Result<(), Error> {
//! if sk[0] != 42 {
//! return Err(Error::InvalidArgument);
//! }
//! if ct[0] != 7 {
//! return Err(Error::InvalidArgument);
//! }
//! shk[0] = 17;
//! Ok(())
//! }
//! }
//!
//! impl Default for DummyKem {
//! fn default() -> Self {
//! Self{}
//! }
//! }
//! # use rosenpass_secret_memory::{secret_policy_use_only_malloc_secrets, Secret};
//! #
//! # type MyKem = DummyKem;
//! # secret_policy_use_only_malloc_secrets();
//! # let mut alice_sk: Secret<{ MyKem::SK_LEN }> = Secret::zero();
//! # let mut alice_pk: [u8; MyKem::PK_LEN] = [0; MyKem::PK_LEN];
//! # MyKem::default().keygen(alice_sk.secret_mut(), &mut alice_pk)?;
//!
//! # let mut bob_shk: Secret<{ MyKem::SHK_LEN }> = Secret::zero();
//! # let mut bob_ct: [u8; MyKem::CT_LEN] = [0; MyKem::CT_LEN];
//! # MyKem::default().encaps(bob_shk.secret_mut(), &mut bob_ct, &mut alice_pk)?;
//! #
//! # let mut alice_shk: Secret<{ MyKem::SHK_LEN }> = Secret::zero();
//! # MyKem::default().decaps(alice_shk.secret_mut(), alice_sk.secret_mut(), &mut bob_ct)?;
//! #
//! # assert_eq!(alice_shk.secret(), bob_shk.secret());
//! #
//! # Ok::<(), Error>(())
//!```
//!
use thiserror::Error;
/// Key Encapsulation Mechanism
///
/// The KEM interface defines three operations: Key generation, key encapsulation and key
/// decapsulation. The parameters are made available as associated constants for convenience.
///
/// The methods of this trait take a `&self` argument as a receiver. This has two reasons:
/// 1. It makes type inference a lot smoother
/// 2. It allows to use the functionality through a trait object or having an enum that has
/// variants for multiple options (like e.g. the `KeyedHash` enum in `rosenpass-ciphers`).
///
/// Since the caller needs an instance of the type to use the functionality, implementors are
/// adviced to implement the [`Default`] trait where possible.
///
/// Example for encrypting a message with a specific [`Kem`] instance:
/// ```
/// use rosenpass_cipher_traits::primitives::Kem;
///
/// const SK_LEN: usize = 1632;
/// const PK_LEN: usize = 800;
/// const CT_LEN: usize = 768;
/// const SHK_LEN: usize = 32;
///
/// fn encaps_given_a_kem<KemImpl>(
/// kem: &KemImpl,
/// pk: &[u8; PK_LEN],
/// ct: &mut [u8; CT_LEN]
/// ) -> [u8; SHK_LEN] where KemImpl: Kem<SK_LEN, PK_LEN, CT_LEN, SHK_LEN>{
/// let mut shk = [0u8; SHK_LEN];
/// kem.encaps(&mut shk, ct, pk).unwrap();
/// shk
/// }
/// ```
///
/// If only the type (but no instance) is available, then we can still use the trait, as long as
/// the type also is [`Default`]:
/// ```
/// use rosenpass_cipher_traits::primitives::Kem;
///
/// const SK_LEN: usize = 1632;
/// const PK_LEN: usize = 800;
/// const CT_LEN: usize = 768;
/// const SHK_LEN: usize = 32;
///
/// fn encaps_without_kem<KemImpl>(
/// pk: &[u8; PK_LEN],
/// ct: &mut [u8; CT_LEN]
/// ) -> [u8; SHK_LEN]
/// where KemImpl: Default + Kem<SK_LEN, PK_LEN, CT_LEN, SHK_LEN> {
/// let mut shk = [0u8; SHK_LEN];
/// KemImpl::default().encaps(&mut shk, ct, pk).unwrap();
/// shk
/// }
/// ```
pub trait Kem<const SK_LEN: usize, const PK_LEN: usize, const CT_LEN: usize, const SHK_LEN: usize> {
/// The length of the secret (decapsulation) key.
const SK_LEN: usize = SK_LEN;
/// The length of the public (encapsulation) key.
const PK_LEN: usize = PK_LEN;
/// The length of the ciphertext.
const CT_LEN: usize = CT_LEN;
/// The legnth of the resulting shared key.
const SHK_LEN: usize = SHK_LEN;
/// Generate a keypair consisting of secret key (`sk`) and public key (`pk`)
///
/// `keygen() -> sk, pk`
fn keygen(&self, sk: &mut [u8; SK_LEN], pk: &mut [u8; PK_LEN]) -> Result<(), Error>;
/// From a public key (`pk`), generate a shared key (`shk`, for local use)
/// and a cipher text (`ct`, to be sent to the owner of the `pk`).
///
/// `encaps(pk) -> shk, ct`
fn encaps(
&self,
shk: &mut [u8; SHK_LEN],
ct: &mut [u8; CT_LEN],
pk: &[u8; PK_LEN],
) -> Result<(), Error>;
/// From a secret key (`sk`) and a cipher text (`ct`) derive a shared key
/// (`shk`)
///
/// `decaps(sk, ct) -> shk`
fn decaps(
&self,
shk: &mut [u8; SHK_LEN],
sk: &[u8; SK_LEN],
ct: &[u8; CT_LEN],
) -> Result<(), Error>;
}
#[derive(Debug, Error)]
pub enum Error {
#[error("invalid argument")]
InvalidArgument,
#[error("internal error")]
InternalError,
}

View File

@@ -1,159 +0,0 @@
use std::marker::PhantomData;
/// Models a keyed hash function using an associated function (i.e. without `&self` receiver).
pub trait KeyedHash<const KEY_LEN: usize, const HASH_LEN: usize> {
/// The error type used to signal what went wrong.
type Error;
/// Performs a keyed hash using `key` and `data` and writes the output to `out`
fn keyed_hash(
key: &[u8; KEY_LEN],
data: &[u8],
out: &mut [u8; HASH_LEN],
) -> Result<(), Self::Error>;
}
/// Models a keyed hash function using a method (i.e. with a `&self` receiver).
///
/// This makes type inference easier, but also requires having a [`KeyedHashInstance`] value,
/// instead of just the [`KeyedHash`] type.
pub trait KeyedHashInstance<const KEY_LEN: usize, const HASH_LEN: usize> {
/// The error type used to signal what went wrong.
type Error;
/// Performs a keyed hash using `key` and `data` and writes the output to `out`
fn keyed_hash(
&self,
key: &[u8; KEY_LEN],
data: &[u8],
out: &mut [u8; HASH_LEN],
) -> Result<(), Self::Error>;
}
/// This is a helper to allow for type parameter inference when calling functions
/// that need a [KeyedHash].
///
/// Really just binds the [KeyedHash] trait to a dummy variable, so the type of this dummy variable
/// can be used for type inference. Less typing work.
#[derive(Debug, PartialEq, Eq)]
pub struct InferKeyedHash<Static, const KEY_LEN: usize, const HASH_LEN: usize>
where
Static: KeyedHash<KEY_LEN, HASH_LEN>,
{
pub _phantom_keyed_hasher: PhantomData<Static>,
}
impl<Static, const KEY_LEN: usize, const HASH_LEN: usize> InferKeyedHash<Static, KEY_LEN, HASH_LEN>
where
Static: KeyedHash<KEY_LEN, HASH_LEN>,
{
pub const KEY_LEN: usize = KEY_LEN;
pub const HASH_LEN: usize = HASH_LEN;
pub const fn new() -> Self {
Self {
_phantom_keyed_hasher: PhantomData,
}
}
/// This just forwards to [KeyedHash::keyed_hash] of the type parameter `Static`
fn keyed_hash_internal<'a>(
&self,
key: &'a [u8; KEY_LEN],
data: &'a [u8],
out: &mut [u8; HASH_LEN],
) -> Result<(), Static::Error> {
Static::keyed_hash(key, data, out)
}
/// Returns the key length of the keyed hash function.
pub const fn key_len(self) -> usize {
Self::KEY_LEN
}
/// Returns the hash length of the keyed hash function.
pub const fn hash_len(self) -> usize {
Self::HASH_LEN
}
}
impl<const KEY_LEN: usize, const HASH_LEN: usize, Static: KeyedHash<KEY_LEN, HASH_LEN>>
KeyedHashInstance<KEY_LEN, HASH_LEN> for InferKeyedHash<Static, KEY_LEN, HASH_LEN>
{
type Error = Static::Error;
fn keyed_hash(
&self,
key: &[u8; KEY_LEN],
data: &[u8],
out: &mut [u8; HASH_LEN],
) -> Result<(), Static::Error> {
self.keyed_hash_internal(key, data, out)
}
}
// Helper traits /////////////////////////////////////////////
impl<Static, const KEY_LEN: usize, const OUT_LEN: usize> Default
for InferKeyedHash<Static, KEY_LEN, OUT_LEN>
where
Static: KeyedHash<KEY_LEN, OUT_LEN>,
{
fn default() -> Self {
Self::new()
}
}
impl<Static, const KEY_LEN: usize, const OUT_LEN: usize> Clone
for InferKeyedHash<Static, KEY_LEN, OUT_LEN>
where
Static: KeyedHash<KEY_LEN, OUT_LEN>,
{
fn clone(&self) -> Self {
*self
}
}
impl<Static, const KEY_LEN: usize, const OUT_LEN: usize> Copy
for InferKeyedHash<Static, KEY_LEN, OUT_LEN>
where
Static: KeyedHash<KEY_LEN, OUT_LEN>,
{
}
use rosenpass_to::{with_destination, To};
/// Extends the [`KeyedHash`] trait with a [`To`]-flavoured function.
pub trait KeyedHashTo<const KEY_LEN: usize, const HASH_LEN: usize>:
KeyedHash<KEY_LEN, HASH_LEN>
{
fn keyed_hash_to(
key: &[u8; KEY_LEN],
data: &[u8],
) -> impl To<[u8; HASH_LEN], Result<(), Self::Error>> {
with_destination(|out| Self::keyed_hash(key, data, out))
}
}
impl<const KEY_LEN: usize, const HASH_LEN: usize, T: KeyedHash<KEY_LEN, HASH_LEN>>
KeyedHashTo<KEY_LEN, HASH_LEN> for T
{
}
/// Extends the [`KeyedHashInstance`] trait with a [`To`]-flavoured function.
pub trait KeyedHashInstanceTo<const KEY_LEN: usize, const HASH_LEN: usize>:
KeyedHashInstance<KEY_LEN, HASH_LEN>
{
fn keyed_hash_to(
&self,
key: &[u8; KEY_LEN],
data: &[u8],
) -> impl To<[u8; HASH_LEN], Result<(), Self::Error>> {
with_destination(|out| self.keyed_hash(key, data, out))
}
}
impl<const KEY_LEN: usize, const HASH_LEN: usize, T: KeyedHashInstance<KEY_LEN, HASH_LEN>>
KeyedHashInstanceTo<KEY_LEN, HASH_LEN> for T
{
}

View File

@@ -8,42 +8,9 @@ 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]
# 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_define_chachapoly",
"dep:libcrux",
]
# 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"]
experiment_libcrux = ["dep:libcrux"]
[dependencies]
anyhow = { workspace = true }
@@ -52,22 +19,8 @@ rosenpass-constant-time = { workspace = true }
rosenpass-secret-memory = { workspace = true }
rosenpass-oqs = { workspace = true }
rosenpass-util = { workspace = true }
rosenpass-cipher-traits = { workspace = true }
static_assertions = { workspace = true }
zeroize = { workspace = true }
chacha20poly1305 = { workspace = true }
blake2 = { workspace = true }
sha3 = { workspace = true }
rand = { workspace = true, optional = true }
thiserror = { workspace = true, optional = true }
libcrux-chacha20poly1305 = { workspace = true, optional = true }
libcrux-blake2 = { workspace = true, optional = true }
libcrux-ml-kem = { workspace = true, optional = true, features = ["kyber"] }
# this one is only used in testing, so it requires the `experiment_libcrux_chachapoly_test` feature.
libcrux = { workspace = true, optional = true }
[dev-dependencies]
rand = { workspace = true }
criterion = { workspace = true }

View File

@@ -1,378 +0,0 @@
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();
})
});
}
}

View File

@@ -1,75 +1,74 @@
//!
//!```rust
//! # use rosenpass_ciphers::hash_domain::{HashDomain, HashDomainNamespace, SecretHashDomain, SecretHashDomainNamespace};
//! use rosenpass_ciphers::KeyedHash;
//! use rosenpass_secret_memory::Secret;
//! # rosenpass_secret_memory::secret_policy_use_only_malloc_secrets();
//!
//! const PROTOCOL_IDENTIFIER: &str = "MY_PROTOCOL:IDENTIFIER";
//! // create use once hash domain for the protocol identifier
//! let mut hash_domain = HashDomain::zero(KeyedHash::keyed_shake256());
//! hash_domain = hash_domain.mix(PROTOCOL_IDENTIFIER.as_bytes())?;
//! // upgrade to reusable hash domain
//! let hash_domain_namespace: HashDomainNamespace = hash_domain.dup();
//! // derive new key
//! let key_identifier = "my_key_identifier";
//! let key = hash_domain_namespace.mix(key_identifier.as_bytes())?.into_value();
//! // derive a new key based on a secret
//! const MY_SECRET_LEN: usize = 21;
//! let my_secret_bytes = "my super duper secret".as_bytes();
//! let my_secret: Secret<21> = Secret::from_slice("my super duper secret".as_bytes());
//! let secret_hash_domain: SecretHashDomain = hash_domain_namespace.mix_secret(my_secret)?;
//! // derive a new key based on the secret key
//! let new_key_identifier = "my_new_key_identifier".as_bytes();
//! let new_key = secret_hash_domain.mix(new_key_identifier)?.into_secret();
//!
//! # Ok::<(), anyhow::Error>(())
//!```
//!
use anyhow::Result;
use rosenpass_secret_memory::Secret;
use rosenpass_to::To as _;
use rosenpass_to::To;
pub use crate::{KeyedHash, KEY_LEN};
use crate::keyed_hash as hash;
use rosenpass_cipher_traits::primitives::KeyedHashInstanceTo;
pub use hash::KEY_LEN;
///
///```rust
/// # use rosenpass_ciphers::hash_domain::{HashDomain, HashDomainNamespace, SecretHashDomain, SecretHashDomainNamespace};
/// use rosenpass_secret_memory::Secret;
/// # rosenpass_secret_memory::secret_policy_use_only_malloc_secrets();
///
/// const PROTOCOL_IDENTIFIER: &str = "MY_PROTOCOL:IDENTIFIER";
/// // create use once hash domain for the protocol identifier
/// let mut hash_domain = HashDomain::zero();
/// hash_domain = hash_domain.mix(PROTOCOL_IDENTIFIER.as_bytes())?;
/// // upgrade to reusable hash domain
/// let hash_domain_namespace: HashDomainNamespace = hash_domain.dup();
/// // derive new key
/// let key_identifier = "my_key_identifier";
/// let key = hash_domain_namespace.mix(key_identifier.as_bytes())?.into_value();
/// // derive a new key based on a secret
/// const MY_SECRET_LEN: usize = 21;
/// let my_secret_bytes = "my super duper secret".as_bytes();
/// let my_secret: Secret<21> = Secret::from_slice("my super duper secret".as_bytes());
/// let secret_hash_domain: SecretHashDomain = hash_domain_namespace.mix_secret(my_secret)?;
/// // derive a new key based on the secret key
/// let new_key_identifier = "my_new_key_identifier".as_bytes();
/// let new_key = secret_hash_domain.mix(new_key_identifier)?.into_secret();
///
/// # Ok::<(), anyhow::Error>(())
///```
///
// TODO Use a proper Dec interface
/// A use-once hash domain for a specified key that can be used directly.
/// The key must consist of [KEY_LEN] many bytes. If the key must remain secret,
/// use [SecretHashDomain] instead.
#[derive(Clone, Debug)]
pub struct HashDomain([u8; KEY_LEN], KeyedHash);
pub struct HashDomain([u8; KEY_LEN]);
/// A reusable hash domain for a namespace identified by the key.
/// The key must consist of [KEY_LEN] many bytes. If the key must remain secret,
/// use [SecretHashDomainNamespace] instead.
#[derive(Clone, Debug)]
pub struct HashDomainNamespace([u8; KEY_LEN], KeyedHash);
pub struct HashDomainNamespace([u8; KEY_LEN]);
/// A use-once hash domain for a specified key that can be used directly
/// by wrapping it in [Secret]. The key must consist of [KEY_LEN] many bytes.
#[derive(Clone, Debug)]
pub struct SecretHashDomain(Secret<KEY_LEN>, KeyedHash);
pub struct SecretHashDomain(Secret<KEY_LEN>);
/// A reusable secure hash domain for a namespace identified by the key and that keeps the key secure
/// by wrapping it in [Secret]. The key must consist of [KEY_LEN] many bytes.
#[derive(Clone, Debug)]
pub struct SecretHashDomainNamespace(Secret<KEY_LEN>, KeyedHash);
pub struct SecretHashDomainNamespace(Secret<KEY_LEN>);
impl HashDomain {
/// Creates a nw [HashDomain] initialized with a all-zeros key.
pub fn zero(choice: KeyedHash) -> Self {
Self([0u8; KEY_LEN], choice)
pub fn zero() -> Self {
Self([0u8; KEY_LEN])
}
/// Turns this [HashDomain] into a [HashDomainNamespace], keeping the key.
pub fn dup(self) -> HashDomainNamespace {
HashDomainNamespace(self.0, self.1)
HashDomainNamespace(self.0)
}
/// Turns this [HashDomain] into a [SecretHashDomain] by wrapping the key into a [Secret]
/// and creating a new [SecretHashDomain] from it.
pub fn turn_secret(self) -> SecretHashDomain {
SecretHashDomain(Secret::from_slice(&self.0), self.1)
SecretHashDomain(Secret::from_slice(&self.0))
}
// TODO: Protocol! Use domain separation to ensure that
@@ -78,43 +77,14 @@ impl HashDomain {
/// as the `data` and uses the result as the key for the new [HashDomain].
///
pub fn mix(self, v: &[u8]) -> Result<Self> {
let mut new_key: [u8; KEY_LEN] = [0u8; KEY_LEN];
self.1.keyed_hash_to(&self.0, v).to(&mut new_key)?;
Ok(Self(new_key, self.1))
}
/// Version of [Self::mix] that accepts an iterator and mixes all values from the iterator into
/// this hash domain.
///
/// # Examples
///
/// ```rust
/// use rosenpass_ciphers::{hash_domain::HashDomain, KeyedHash};
///
/// let hasher = HashDomain::zero(KeyedHash::keyed_shake256());
/// assert_eq!(
/// hasher.clone().mix(b"Hello")?.mix(b"World")?.into_value(),
/// hasher.clone().mix_many([b"Hello", b"World"])?.into_value()
/// );
///
/// Ok::<(), anyhow::Error>(())
/// ```
pub fn mix_many<I, T>(mut self, it: I) -> Result<Self>
where
I: IntoIterator<Item = T>,
T: AsRef<[u8]>,
{
for e in it {
self = self.mix(e.as_ref())?;
}
Ok(self)
Ok(Self(hash::hash(&self.0, v).collect::<[u8; KEY_LEN]>()?))
}
/// Creates a new [SecretHashDomain] by mixing in a new key `v`
/// by calling [SecretHashDomain::invoke_primitive] with this
/// [HashDomain]'s key as `k` and `v` as `d`.
pub fn mix_secret<const N: usize>(self, v: Secret<N>) -> Result<SecretHashDomain> {
SecretHashDomain::invoke_primitive(&self.0, v.secret(), self.1)
SecretHashDomain::invoke_primitive(&self.0, v.secret())
}
/// Gets the key of this [HashDomain].
@@ -128,9 +98,9 @@ impl HashDomainNamespace {
/// it evaluates [hash::hash] with the key of this HashDomainNamespace key as the key and `v`
/// as the `data` and uses the result as the key for the new [HashDomain].
pub fn mix(&self, v: &[u8]) -> Result<HashDomain> {
let mut new_key: [u8; KEY_LEN] = [0u8; KEY_LEN];
self.1.keyed_hash_to(&self.0, v).to(&mut new_key)?;
Ok(HashDomain(new_key, self.1.clone()))
Ok(HashDomain(
hash::hash(&self.0, v).collect::<[u8; KEY_LEN]>()?,
))
}
/// Creates a new [SecretHashDomain] by mixing in a new key `v`
@@ -139,7 +109,7 @@ impl HashDomainNamespace {
///
/// It requires that `v` consists of exactly [KEY_LEN] many bytes.
pub fn mix_secret<const N: usize>(&self, v: Secret<N>) -> Result<SecretHashDomain> {
SecretHashDomain::invoke_primitive(&self.0, v.secret(), self.1.clone())
SecretHashDomain::invoke_primitive(&self.0, v.secret())
}
}
@@ -148,35 +118,27 @@ impl SecretHashDomain {
/// [hash::hash] with `k` as the `key` and `d` s the `data`, and using the result
/// as the content for the new [SecretHashDomain].
/// Both `k` and `d` have to be exactly [KEY_LEN] bytes in length.
/// TODO: docu
pub fn invoke_primitive(
k: &[u8],
d: &[u8],
hash_choice: KeyedHash,
) -> Result<SecretHashDomain> {
let mut new_secret_key = Secret::zero();
hash_choice
.keyed_hash_to(k.try_into()?, d)
.to(new_secret_key.secret_mut())?;
let r = SecretHashDomain(new_secret_key, hash_choice);
pub fn invoke_primitive(k: &[u8], d: &[u8]) -> Result<SecretHashDomain> {
let mut r = SecretHashDomain(Secret::zero());
hash::hash(k, d).to(r.0.secret_mut())?;
Ok(r)
}
/// Creates a new [SecretHashDomain] that is initialized with an all zeros key.
pub fn zero(hash_choice: KeyedHash) -> Self {
Self(Secret::zero(), hash_choice)
pub fn zero() -> Self {
Self(Secret::zero())
}
/// Turns this [SecretHashDomain] into a [SecretHashDomainNamespace].
pub fn dup(self) -> SecretHashDomainNamespace {
SecretHashDomainNamespace(self.0, self.1)
SecretHashDomainNamespace(self.0)
}
/// Creates a new [SecretHashDomain] from a [Secret] `k`.
///
/// It requires that `k` consist of exactly [KEY_LEN] bytes.
pub fn danger_from_secret(k: Secret<KEY_LEN>, hash_choice: KeyedHash) -> Self {
Self(k, hash_choice)
pub fn danger_from_secret(k: Secret<KEY_LEN>) -> Self {
Self(k)
}
/// Creates a new [SecretHashDomain] by mixing in a new key `v`. Specifically,
@@ -185,47 +147,7 @@ impl SecretHashDomain {
///
/// It requires that `v` consists of exactly [KEY_LEN] many bytes.
pub fn mix(self, v: &[u8]) -> Result<SecretHashDomain> {
Self::invoke_primitive(self.0.secret(), v, self.1)
}
/// Version of [Self::mix] that accepts an iterator and mixes all values from the iterator into
/// this hash domain.
///
/// # Examples
///
/// ```rust
/// use rosenpass_ciphers::{hash_domain::HashDomain, KeyedHash};
///
/// rosenpass_secret_memory::secret_policy_use_only_malloc_secrets();
///
/// let hasher = HashDomain::zero(KeyedHash::keyed_shake256());
/// assert_eq!(
/// hasher
/// .clone()
/// .turn_secret()
/// .mix(b"Hello")?
/// .mix(b"World")?
/// .into_secret()
/// .secret(),
/// hasher
/// .clone()
/// .turn_secret()
/// .mix_many([b"Hello", b"World"])?
/// .into_secret()
/// .secret(),
/// );
/// Ok::<(), anyhow::Error>(())
/// ```
pub fn mix_many<I, T>(mut self, it: I) -> Result<Self>
where
I: IntoIterator<Item = T>,
T: AsRef<[u8]>,
{
for e in it {
self = self.mix(e.as_ref())?;
}
Ok(self)
Self::invoke_primitive(self.0.secret(), v)
}
/// Creates a new [SecretHashDomain] by mixing in a new key `v`
@@ -234,13 +156,21 @@ impl SecretHashDomain {
///
/// It requires that `v` consists of exactly [KEY_LEN] many bytes.
pub fn mix_secret<const N: usize>(self, v: Secret<N>) -> Result<SecretHashDomain> {
Self::invoke_primitive(self.0.secret(), v.secret(), self.1)
Self::invoke_primitive(self.0.secret(), v.secret())
}
/// Get the secret key data from this [SecretHashDomain].
pub fn into_secret(self) -> Secret<KEY_LEN> {
self.0
}
/// Evaluate [hash::hash] with this [SecretHashDomain]'s data as the `key` and
/// `dst` as the `data` and stores the result as the new data for this [SecretHashDomain].
///
/// It requires that both `v` and `d` consist of exactly [KEY_LEN] many bytes.
pub fn into_secret_slice(mut self, v: &[u8], dst: &[u8]) -> Result<()> {
hash::hash(v, dst).to(self.0.secret_mut())
}
}
impl SecretHashDomainNamespace {
@@ -250,7 +180,7 @@ impl SecretHashDomainNamespace {
///
/// It requires that `v` consists of exactly [KEY_LEN] many bytes.
pub fn mix(&self, v: &[u8]) -> Result<SecretHashDomain> {
SecretHashDomain::invoke_primitive(self.0.secret(), v, self.1.clone())
SecretHashDomain::invoke_primitive(self.0.secret(), v)
}
/// Creates a new [SecretHashDomain] by mixing in a new key `v`
@@ -259,7 +189,7 @@ impl SecretHashDomainNamespace {
///
/// It requires that `v` consists of exactly [KEY_LEN] many bytes.
pub fn mix_secret<const N: usize>(&self, v: Secret<N>) -> Result<SecretHashDomain> {
SecretHashDomain::invoke_primitive(self.0.secret(), v.secret(), self.1.clone())
SecretHashDomain::invoke_primitive(self.0.secret(), v.secret())
}
// TODO: This entire API is not very nice; we need this for biscuits, but
@@ -269,8 +199,4 @@ impl SecretHashDomainNamespace {
pub fn danger_into_secret(self) -> Secret<KEY_LEN> {
self.0
}
pub fn keyed_hash(&self) -> &KeyedHash {
&self.1
}
}

View File

@@ -1,12 +1,11 @@
use rosenpass_cipher_traits::primitives::Aead as AeadTrait;
use static_assertions::const_assert;
pub mod subtle;
/// All keyed primitives in this crate use 32 byte keys
pub const KEY_LEN: usize = 32;
const_assert!(KEY_LEN == Aead::KEY_LEN);
const_assert!(KEY_LEN == XAead::KEY_LEN);
const_assert!(KEY_LEN == aead::KEY_LEN);
const_assert!(KEY_LEN == xaead::KEY_LEN);
const_assert!(KEY_LEN == hash_domain::KEY_LEN);
/// Keyed hashing
@@ -14,33 +13,41 @@ const_assert!(KEY_LEN == hash_domain::KEY_LEN);
/// This should only be used for implementation details; anything with relevance
/// to the cryptographic protocol should use the facilities in [hash_domain], (though
/// hash domain uses this module internally)
pub use crate::subtle::keyed_hash::KeyedHash;
pub mod keyed_hash {
pub use crate::subtle::incorrect_hmac_blake2b::{
hash, KEY_LEN, KEY_MAX, KEY_MIN, OUT_MAX, OUT_MIN,
};
}
/// Authenticated encryption with associated data (AEAD)
/// Authenticated encryption with associated data
/// Chacha20poly1305 is used.
#[cfg(feature = "experiment_libcrux_chachapoly")]
pub use subtle::libcrux::chacha20poly1305_ietf::ChaCha20Poly1305 as Aead;
pub mod aead {
#[cfg(not(feature = "experiment_libcrux"))]
pub use crate::subtle::chacha20poly1305_ietf::{decrypt, encrypt, KEY_LEN, NONCE_LEN, TAG_LEN};
#[cfg(feature = "experiment_libcrux")]
pub use crate::subtle::chacha20poly1305_ietf_libcrux::{
decrypt, encrypt, KEY_LEN, NONCE_LEN, TAG_LEN,
};
}
/// Authenticated encryption with associated data (AEAD)
/// Chacha20poly1305 is used.
#[cfg(not(feature = "experiment_libcrux_chachapoly"))]
pub use crate::subtle::rust_crypto::chacha20poly1305_ietf::ChaCha20Poly1305 as Aead;
/// Authenticated encryption with associated data with a extended-length nonce (XAEAD)
/// Authenticated encryption with associated data with a constant nonce
/// XChacha20poly1305 is used.
pub use crate::subtle::rust_crypto::xchacha20poly1305_ietf::XChaCha20Poly1305 as XAead;
/// Use Classic-McEcliece-460986 as the Static KEM.
///
/// See [rosenpass_oqs::ClassicMceliece460896] for more details.
pub use rosenpass_oqs::ClassicMceliece460896 as StaticKem;
/// Use Kyber-512 as the Static KEM
///
/// See [rosenpass_oqs::Kyber512] for more details.
#[cfg(not(feature = "experiment_libcrux_kyber"))]
pub use rosenpass_oqs::Kyber512 as EphemeralKem;
#[cfg(feature = "experiment_libcrux_kyber")]
pub use subtle::libcrux::kyber512::Kyber512 as EphemeralKem;
pub mod xaead {
pub use crate::subtle::xchacha20poly1305_ietf::{
decrypt, encrypt, KEY_LEN, NONCE_LEN, TAG_LEN,
};
}
pub mod hash_domain;
/// This crate includes two key encapsulation mechanisms.
/// Namely ClassicMceliece460896 (also referred to as `StaticKem` sometimes) and
/// Kyber512 (also referred to as `EphemeralKem` sometimes).
///
/// See [rosenpass_oqs::ClassicMceliece460896]
/// and [rosenpass_oqs::Kyber512] for more details on the specific KEMS.
///
pub mod kem {
pub use rosenpass_oqs::ClassicMceliece460896 as StaticKem;
pub use rosenpass_oqs::Kyber512 as EphemeralKem;
}

View File

@@ -0,0 +1,65 @@
use zeroize::Zeroizing;
use blake2::digest::crypto_common::generic_array::GenericArray;
use blake2::digest::crypto_common::typenum::U32;
use blake2::digest::crypto_common::KeySizeUser;
use blake2::digest::{FixedOutput, Mac, OutputSizeUser};
use blake2::Blake2bMac;
use rosenpass_to::{ops::copy_slice, with_destination, To};
use rosenpass_util::typenum2const;
/// Specify that the used implementation of BLAKE2b is the MAC version of BLAKE2b
/// with output and key length of 32 bytes (see [Blake2bMac]).
type Impl = Blake2bMac<U32>;
type KeyLen = <Impl as KeySizeUser>::KeySize;
type OutLen = <Impl as OutputSizeUser>::OutputSize;
/// The key length for BLAKE2b supported by this API. Currently 32 Bytes.
const KEY_LEN: usize = typenum2const! { KeyLen };
/// The output length for BLAKE2b supported by this API. Currently 32 Bytes.
const OUT_LEN: usize = typenum2const! { OutLen };
/// Minimal key length supported by this API.
pub const KEY_MIN: usize = KEY_LEN;
/// maximal key length supported by this API.
pub const KEY_MAX: usize = KEY_LEN;
/// minimal output length supported by this API.
pub const OUT_MIN: usize = OUT_LEN;
/// maximal output length supported by this API.
pub const OUT_MAX: usize = OUT_LEN;
/// Hashes the given `data` with the [Blake2bMac] hash function under the given `key`.
/// The both the length of the output the length of the key 32 bytes (or 256 bits).
///
/// # Examples
///
///```rust
/// # use rosenpass_ciphers::subtle::blake2b::hash;
/// use rosenpass_to::To;
/// let zero_key: [u8; 32] = [0; 32];
/// let data: [u8; 32] = [255; 32];
/// // buffer for the hash output
/// let mut hash_data: [u8; 32] = [0u8; 32];
///
/// assert!(hash(&zero_key, &data).to(&mut hash_data).is_ok(), "Hashing has to return OK result");
///```
///
#[inline]
pub fn hash<'a>(key: &'a [u8], data: &'a [u8]) -> impl To<[u8], anyhow::Result<()>> + 'a {
with_destination(|out: &mut [u8]| {
let mut h = Impl::new_from_slice(key)?;
h.update(data);
// Jesus christ, blake2 crate, your usage of GenericArray might be nice and fancy
// but it introduces a ton of complexity. This cost me half an hour just to figure
// out the right way to use the imports while allowing for zeroization.
// An API based on slices might actually be simpler.
let mut tmp = Zeroizing::new([0u8; OUT_LEN]);
let tmp = GenericArray::from_mut_slice(tmp.as_mut());
h.finalize_into(tmp);
copy_slice(tmp.as_ref()).to(out);
Ok(())
})
}

View File

@@ -0,0 +1,99 @@
use rosenpass_to::ops::copy_slice;
use rosenpass_to::To;
use rosenpass_util::typenum2const;
use chacha20poly1305::aead::generic_array::GenericArray;
use chacha20poly1305::ChaCha20Poly1305 as AeadImpl;
use chacha20poly1305::{AeadCore, AeadInPlace, KeyInit, KeySizeUser};
/// The key length is 32 bytes or 256 bits.
pub const KEY_LEN: usize = typenum2const! { <AeadImpl as KeySizeUser>::KeySize };
/// The MAC tag length is 16 bytes or 128 bits.
pub const TAG_LEN: usize = typenum2const! { <AeadImpl as AeadCore>::TagSize };
/// The nonce length is 12 bytes or 96 bits.
pub const NONCE_LEN: usize = typenum2const! { <AeadImpl as AeadCore>::NonceSize };
/// Encrypts using ChaCha20Poly1305 as implemented in [RustCrypto](https://github.com/RustCrypto/AEADs/tree/master/chacha20poly1305).
/// `key` MUST be chosen (pseudo-)randomly and `nonce` MOST NOT be reused. The `key` slice MUST have
/// a length of [KEY_LEN]. The `nonce` slice MUST have a length of [NONCE_LEN]. The last [TAG_LEN] bytes
/// written in `ciphertext` are the tag guaranteeing integrity. `ciphertext` MUST have a capacity of
/// `plaintext.len()` + [TAG_LEN].
///
/// # Examples
///```rust
/// # use rosenpass_ciphers::subtle::chacha20poly1305_ietf::{encrypt, TAG_LEN, KEY_LEN, NONCE_LEN};
///
/// const PLAINTEXT_LEN: usize = 43;
/// let plaintext = "post-quantum cryptography is very important".as_bytes();
/// assert_eq!(PLAINTEXT_LEN, plaintext.len());
/// let key: &[u8] = &[0u8; KEY_LEN]; // THIS IS NOT A SECURE KEY
/// let nonce: &[u8] = &[0u8; NONCE_LEN]; // THIS IS NOT A SECURE NONCE
/// let additional_data: &[u8] = "the encrypted message is very important".as_bytes();
/// let mut ciphertext_buffer = [0u8;PLAINTEXT_LEN + TAG_LEN];
///
/// let res: anyhow::Result<()> = encrypt(&mut ciphertext_buffer, key, nonce, additional_data, plaintext);
/// assert!(res.is_ok());
/// # let expected_ciphertext: &[u8] = &[239, 104, 148, 202, 120, 32, 77, 27, 246, 206, 226, 17,
/// # 83, 78, 122, 116, 187, 123, 70, 199, 58, 130, 21, 1, 107, 230, 58, 77, 18, 152, 31, 159, 80,
/// # 151, 72, 27, 236, 137, 60, 55, 180, 31, 71, 97, 199, 12, 60, 155, 70, 221, 225, 110, 132, 191,
/// # 8, 114, 85, 4, 25];
/// # assert_eq!(expected_ciphertext, &ciphertext_buffer);
///```
#[inline]
pub fn encrypt(
ciphertext: &mut [u8],
key: &[u8],
nonce: &[u8],
ad: &[u8],
plaintext: &[u8],
) -> anyhow::Result<()> {
let nonce = GenericArray::from_slice(nonce);
let (ct, mac) = ciphertext.split_at_mut(ciphertext.len() - TAG_LEN);
copy_slice(plaintext).to(ct);
let mac_value = AeadImpl::new_from_slice(key)?.encrypt_in_place_detached(nonce, ad, ct)?;
copy_slice(&mac_value[..]).to(mac);
Ok(())
}
/// Decrypts a `ciphertext` and verifies the integrity of the `ciphertext` and the additional data
/// `ad`. using ChaCha20Poly1305 as implemented in [RustCrypto](https://github.com/RustCrypto/AEADs/tree/master/chacha20poly1305).
///
/// The `key` slice MUST have a length of [KEY_LEN]. The `nonce` slice MUST have a length of
/// [NONCE_LEN]. The plaintext buffer must have a capacity of `ciphertext.len()` - [TAG_LEN].
///
/// # Examples
///```rust
/// # use rosenpass_ciphers::subtle::chacha20poly1305_ietf::{decrypt, TAG_LEN, KEY_LEN, NONCE_LEN};
/// let ciphertext: &[u8] = &[239, 104, 148, 202, 120, 32, 77, 27, 246, 206, 226, 17,
/// 83, 78, 122, 116, 187, 123, 70, 199, 58, 130, 21, 1, 107, 230, 58, 77, 18, 152, 31, 159, 80,
/// 151, 72, 27, 236, 137, 60, 55, 180, 31, 71, 97, 199, 12, 60, 155, 70, 221, 225, 110, 132, 191,
/// 8, 114, 85, 4, 25]; // this is the ciphertext generated by the example for the encryption
/// const PLAINTEXT_LEN: usize = 43;
/// assert_eq!(PLAINTEXT_LEN + TAG_LEN, ciphertext.len());
///
/// let key: &[u8] = &[0u8; KEY_LEN]; // THIS IS NOT A SECURE KEY
/// let nonce: &[u8] = &[0u8; NONCE_LEN]; // THIS IS NOT A SECURE NONCE
/// let additional_data: &[u8] = "the encrypted message is very important".as_bytes();
/// let mut plaintext_buffer = [0u8; PLAINTEXT_LEN];
///
/// let res: anyhow::Result<()> = decrypt(&mut plaintext_buffer, key, nonce, additional_data, ciphertext);
/// assert!(res.is_ok());
/// let expected_plaintext = "post-quantum cryptography is very important".as_bytes();
/// assert_eq!(expected_plaintext, plaintext_buffer);
///
///```
#[inline]
pub fn decrypt(
plaintext: &mut [u8],
key: &[u8],
nonce: &[u8],
ad: &[u8],
ciphertext: &[u8],
) -> anyhow::Result<()> {
let nonce = GenericArray::from_slice(nonce);
let (ct, mac) = ciphertext.split_at(ciphertext.len() - TAG_LEN);
let tag = GenericArray::from_slice(mac);
copy_slice(ct).to(plaintext);
AeadImpl::new_from_slice(key)?.decrypt_in_place_detached(nonce, ad, plaintext, tag)?;
Ok(())
}

View File

@@ -0,0 +1,117 @@
use rosenpass_to::ops::copy_slice;
use rosenpass_to::To;
use zeroize::Zeroize;
/// The key length is 32 bytes or 256 bits.
pub const KEY_LEN: usize = 32; // Grrrr! Libcrux, please provide me these constants.
/// The MAC tag length is 16 bytes or 128 bits.
pub const TAG_LEN: usize = 16;
/// The nonce length is 12 bytes or 96 bits.
pub const NONCE_LEN: usize = 12;
/// Encrypts using ChaCha20Poly1305 as implemented in [libcrux](https://github.com/cryspen/libcrux).
/// Key and nonce MUST be chosen (pseudo-)randomly. The `key` slice MUST have a length of
/// [KEY_LEN]. The `nonce` slice MUST have a length of [NONCE_LEN]. The last [TAG_LEN] bytes
/// written in `ciphertext` are the tag guaranteeing integrity. `ciphertext` MUST have a capacity of
/// `plaintext.len()` + [TAG_LEN].
///
/// # Examples
///```rust
/// # use rosenpass_ciphers::subtle::chacha20poly1305_ietf_libcrux::{encrypt, TAG_LEN, KEY_LEN, NONCE_LEN};
///
/// const PLAINTEXT_LEN: usize = 43;
/// let plaintext = "post-quantum cryptography is very important".as_bytes();
/// assert_eq!(PLAINTEXT_LEN, plaintext.len());
/// let key: &[u8] = &[0u8; KEY_LEN]; // THIS IS NOT A SECURE KEY
/// let nonce: &[u8] = &[0u8; NONCE_LEN]; // THIS IS NOT A SECURE NONCE
/// let additional_data: &[u8] = "the encrypted message is very important".as_bytes();
/// let mut ciphertext_buffer = [0u8; PLAINTEXT_LEN + TAG_LEN];
///
/// let res: anyhow::Result<()> = encrypt(&mut ciphertext_buffer, key, nonce, additional_data, plaintext);
/// assert!(res.is_ok());
/// # let expected_ciphertext: &[u8] = &[239, 104, 148, 202, 120, 32, 77, 27, 246, 206, 226, 17,
/// # 83, 78, 122, 116, 187, 123, 70, 199, 58, 130, 21, 1, 107, 230, 58, 77, 18, 152, 31, 159, 80,
/// # 151, 72, 27, 236, 137, 60, 55, 180, 31, 71, 97, 199, 12, 60, 155, 70, 221, 225, 110, 132, 191,
/// # 8, 114, 85, 4, 25];
/// # assert_eq!(expected_ciphertext, &ciphertext_buffer);
///```
///
#[inline]
pub fn encrypt(
ciphertext: &mut [u8],
key: &[u8],
nonce: &[u8],
ad: &[u8],
plaintext: &[u8],
) -> anyhow::Result<()> {
let (ciphertext, mac) = ciphertext.split_at_mut(ciphertext.len() - TAG_LEN);
use libcrux::aead as C;
let crux_key = C::Key::Chacha20Poly1305(C::Chacha20Key(key.try_into().unwrap()));
let crux_iv = C::Iv(nonce.try_into().unwrap());
copy_slice(plaintext).to(ciphertext);
let crux_tag = libcrux::aead::encrypt(&crux_key, ciphertext, crux_iv, ad).unwrap();
copy_slice(crux_tag.as_ref()).to(mac);
match crux_key {
C::Key::Chacha20Poly1305(mut k) => k.0.zeroize(),
_ => panic!(),
}
Ok(())
}
/// Decrypts a `ciphertext` and verifies the integrity of the `ciphertext` and the additional data
/// `ad`. using ChaCha20Poly1305 as implemented in [libcrux](https://github.com/cryspen/libcrux).
///
/// The `key` slice MUST have a length of [KEY_LEN]. The `nonce` slice MUST have a length of
/// [NONCE_LEN]. The plaintext buffer must have a capacity of `ciphertext.len()` - [TAG_LEN].
///
/// # Examples
///```rust
/// # use rosenpass_ciphers::subtle::chacha20poly1305_ietf_libcrux::{decrypt, TAG_LEN, KEY_LEN, NONCE_LEN};
/// let ciphertext: &[u8] = &[239, 104, 148, 202, 120, 32, 77, 27, 246, 206, 226, 17,
/// 83, 78, 122, 116, 187, 123, 70, 199, 58, 130, 21, 1, 107, 230, 58, 77, 18, 152, 31, 159, 80,
/// 151, 72, 27, 236, 137, 60, 55, 180, 31, 71, 97, 199, 12, 60, 155, 70, 221, 225, 110, 132, 191,
/// 8, 114, 85, 4, 25]; // this is the ciphertext generated by the example for the encryption
/// const PLAINTEXT_LEN: usize = 43;
/// assert_eq!(PLAINTEXT_LEN + TAG_LEN, ciphertext.len());
///
/// let key: &[u8] = &[0u8; KEY_LEN]; // THIS IS NOT A SECURE KEY
/// let nonce: &[u8] = &[0u8; NONCE_LEN]; // THIS IS NOT A SECURE NONCE
/// let additional_data: &[u8] = "the encrypted message is very important".as_bytes();
/// let mut plaintext_buffer = [0u8; PLAINTEXT_LEN];
///
/// let res: anyhow::Result<()> = decrypt(&mut plaintext_buffer, key, nonce, additional_data, ciphertext);
/// assert!(res.is_ok());
/// let expected_plaintext = "post-quantum cryptography is very important".as_bytes();
/// assert_eq!(expected_plaintext, plaintext_buffer);
///
///```
#[inline]
pub fn decrypt(
plaintext: &mut [u8],
key: &[u8],
nonce: &[u8],
ad: &[u8],
ciphertext: &[u8],
) -> anyhow::Result<()> {
let (ciphertext, mac) = ciphertext.split_at(ciphertext.len() - TAG_LEN);
use libcrux::aead as C;
let crux_key = C::Key::Chacha20Poly1305(C::Chacha20Key(key.try_into().unwrap()));
let crux_iv = C::Iv(nonce.try_into().unwrap());
let crux_tag = C::Tag::from_slice(mac).unwrap();
copy_slice(ciphertext).to(plaintext);
libcrux::aead::decrypt(&crux_key, plaintext, crux_iv, ad, &crux_tag).unwrap();
match crux_key {
C::Key::Chacha20Poly1305(mut k) => k.0.zeroize(),
_ => panic!(),
}
Ok(())
}

View File

@@ -1,79 +0,0 @@
use rosenpass_cipher_traits::{
algorithms::KeyedHashIncorrectHmacBlake2b,
primitives::{InferKeyedHash, KeyedHash, KeyedHashTo},
};
use rosenpass_constant_time::xor;
use rosenpass_to::{ops::copy_slice, To};
use zeroize::Zeroizing;
#[cfg(not(feature = "experiment_libcrux_blake2"))]
use crate::subtle::rust_crypto::blake2b::Blake2b;
#[cfg(not(feature = "experiment_libcrux_blake2"))]
use anyhow::Error;
#[cfg(feature = "experiment_libcrux_blake2")]
use crate::subtle::libcrux::blake2b::{Blake2b, Error};
/// The key length, 32 bytes or 256 bits.
pub const KEY_LEN: usize = 32;
/// The hash length, 32 bytes or 256 bits.
pub const HASH_LEN: usize = 32;
/// This is a woefully incorrect implementation of hmac_blake2b.
/// See <https://github.com/rosenpass/rosenpass/issues/68#issuecomment-1563612222>
///
/// It accepts 32 byte keys, exclusively.
///
/// This will be replaced, likely by Kekkac at some point soon.
/// <https://github.com/rosenpass/rosenpass/pull/145>
///
/// # Examples
///```rust
/// # use rosenpass_ciphers::subtle::custom::incorrect_hmac_blake2b::IncorrectHmacBlake2bCore;
/// use rosenpass_cipher_traits::primitives::KeyedHashTo;
/// use rosenpass_to::To;
/// let key: [u8; 32] = [0; 32];
/// let data: [u8; 32] = [255; 32];
/// // buffer for the hash output
/// let mut hash_data: [u8; 32] = [0u8; 32];
///
/// assert!(IncorrectHmacBlake2bCore::keyed_hash_to(&key, &data).to(&mut hash_data).is_ok(), "Hashing has to return OK result");
/// # let expected_hash: &[u8] = &[5, 152, 135, 141, 151, 106, 147, 8, 220, 95, 38, 66, 29, 33, 3,
/// 104, 250, 114, 131, 119, 27, 56, 59, 44, 11, 67, 230, 113, 112, 20, 80, 103];
/// # assert_eq!(hash_data, expected_hash);
///```
///
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct IncorrectHmacBlake2bCore;
impl KeyedHash<KEY_LEN, HASH_LEN> for IncorrectHmacBlake2bCore {
type Error = Error;
fn keyed_hash(
key: &[u8; KEY_LEN],
data: &[u8],
out: &mut [u8; HASH_LEN],
) -> Result<(), Self::Error> {
const IPAD: [u8; KEY_LEN] = [0x36u8; KEY_LEN];
const OPAD: [u8; KEY_LEN] = [0x5Cu8; KEY_LEN];
type Key = Zeroizing<[u8; KEY_LEN]>;
let mut tmp_key = Key::default();
copy_slice(key).to(tmp_key.as_mut());
xor(&IPAD).to(tmp_key.as_mut());
let mut outer_data = Key::default();
Blake2b::keyed_hash_to(&tmp_key, data).to(&mut outer_data)?;
copy_slice(key).to(tmp_key.as_mut());
xor(&OPAD).to(tmp_key.as_mut());
Blake2b::keyed_hash_to(&tmp_key, outer_data.as_ref()).to(out)?;
Ok(())
}
}
pub type IncorrectHmacBlake2b = InferKeyedHash<IncorrectHmacBlake2bCore, KEY_LEN, HASH_LEN>;
impl KeyedHashIncorrectHmacBlake2b for IncorrectHmacBlake2bCore {}

View File

@@ -1,3 +0,0 @@
//! Own implementations of custom algorithms
pub mod incorrect_hmac_blake2b;

View File

@@ -0,0 +1,67 @@
use anyhow::ensure;
use zeroize::Zeroizing;
use rosenpass_constant_time::xor;
use rosenpass_to::{ops::copy_slice, with_destination, To};
use crate::subtle::blake2b;
/// The key length, 32 bytes or 256 bits.
pub const KEY_LEN: usize = 32;
/// The minimal key length, identical to [KEY_LEN]
pub const KEY_MIN: usize = KEY_LEN;
/// The maximal key length, identical to [KEY_LEN]
pub const KEY_MAX: usize = KEY_LEN;
/// The minimal output length, see [blake2b::OUT_MIN]
pub const OUT_MIN: usize = blake2b::OUT_MIN;
/// The maximal output length, see [blake2b::OUT_MAX]
pub const OUT_MAX: usize = blake2b::OUT_MAX;
/// This is a woefully incorrect implementation of hmac_blake2b.
/// See <https://github.com/rosenpass/rosenpass/issues/68#issuecomment-1563612222>
///
/// It accepts 32 byte keys, exclusively.
///
/// This will be replaced, likely by Kekkac at some point soon.
/// <https://github.com/rosenpass/rosenpass/pull/145>
///
/// # Examples
///```rust
/// # use rosenpass_ciphers::subtle::incorrect_hmac_blake2b::hash;
/// use rosenpass_to::To;
/// let key: [u8; 32] = [0; 32];
/// let data: [u8; 32] = [255; 32];
/// // buffer for the hash output
/// let mut hash_data: [u8; 32] = [0u8; 32];
///
/// assert!(hash(&key, &data).to(&mut hash_data).is_ok(), "Hashing has to return OK result");
/// # let expected_hash: &[u8] = &[5, 152, 135, 141, 151, 106, 147, 8, 220, 95, 38, 66, 29, 33, 3,
/// 104, 250, 114, 131, 119, 27, 56, 59, 44, 11, 67, 230, 113, 112, 20, 80, 103];
/// # assert_eq!(hash_data, expected_hash);
///```
///
#[inline]
pub fn hash<'a>(key: &'a [u8], data: &'a [u8]) -> impl To<[u8], anyhow::Result<()>> + 'a {
const IPAD: [u8; KEY_LEN] = [0x36u8; KEY_LEN];
const OPAD: [u8; KEY_LEN] = [0x5Cu8; KEY_LEN];
with_destination(|out: &mut [u8]| {
// Not bothering with padding; the implementation
// uses appropriately sized keys.
ensure!(key.len() == KEY_LEN);
type Key = Zeroizing<[u8; KEY_LEN]>;
let mut tmp_key = Key::default();
copy_slice(key).to(tmp_key.as_mut());
xor(&IPAD).to(tmp_key.as_mut());
let mut outer_data = Key::default();
blake2b::hash(tmp_key.as_ref(), data).to(outer_data.as_mut())?;
copy_slice(key).to(tmp_key.as_mut());
xor(&OPAD).to(tmp_key.as_mut());
blake2b::hash(tmp_key.as_ref(), outer_data.as_ref()).to(out)?;
Ok(())
})
}

View File

@@ -1,65 +0,0 @@
//! This module provides types that enabling choosing the keyed hash building block to be used at
//! runtime (using enums) instead of at compile time (using generics).
use anyhow::Result;
use rosenpass_cipher_traits::primitives::KeyedHashInstance;
use std::fmt::Display;
use crate::subtle::{
custom::incorrect_hmac_blake2b::IncorrectHmacBlake2b, rust_crypto::keyed_shake256::SHAKE256_32,
};
/// Length of symmetric key throughout Rosenpass.
pub const KEY_LEN: usize = 32;
/// The hash is used as a symmetric key and should have the same length.
pub const HASH_LEN: usize = KEY_LEN;
/// Provides a way to pick which keyed hash to use at runtime.
/// Implements [`KeyedHashInstance`] to allow hashing using the respective algorithm.
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum KeyedHash {
/// A hasher backed by [`SHAKE256_32`].
KeyedShake256(SHAKE256_32),
/// A hasher backed by [`IncorrectHmacBlake2b`].
IncorrectHmacBlake2b(IncorrectHmacBlake2b),
}
impl KeyedHash {
/// Creates an [`KeyedHash`] backed by SHAKE256.
pub fn keyed_shake256() -> Self {
Self::KeyedShake256(Default::default())
}
/// Creates an [`KeyedHash`] backed by Blake2B.
pub fn incorrect_hmac_blake2b() -> Self {
Self::IncorrectHmacBlake2b(Default::default())
}
}
impl KeyedHashInstance<KEY_LEN, HASH_LEN> for KeyedHash {
type Error = anyhow::Error;
fn keyed_hash(
&self,
key: &[u8; KEY_LEN],
data: &[u8],
out: &mut [u8; HASH_LEN],
) -> Result<(), Self::Error> {
match self {
Self::KeyedShake256(h) => h.keyed_hash(key, data, out)?,
Self::IncorrectHmacBlake2b(h) => h.keyed_hash(key, data, out)?,
};
Ok(())
}
}
impl Display for KeyedHash {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::KeyedShake256(_) => write!(f, "KeyedShake256_32"),
Self::IncorrectHmacBlake2b(_) => write!(f, "IncorrectHmacBlake2b"),
}
}
}

View File

@@ -1,88 +0,0 @@
//! Implementation of the [`KeyedHashBlake2b`] trait based on the [`libcrux_blake2`] crate.
use libcrux_blake2::Blake2bBuilder;
use rosenpass_cipher_traits::algorithms::KeyedHashBlake2b;
use rosenpass_cipher_traits::primitives::KeyedHash;
pub use rosenpass_cipher_traits::algorithms::keyed_hash_blake2b::HASH_LEN;
pub use rosenpass_cipher_traits::algorithms::keyed_hash_blake2b::KEY_LEN;
/// Describles which error occurred
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// An unexpected internal error occurred. Should never be returned and points to a bug in the
/// implementation.
#[error("internal error")]
InternalError,
/// Indicates that the provided data was too long.
#[error("data is too long")]
DataTooLong,
}
/// Hasher for the given `data` with the Blake2b hash function.
pub struct Blake2b;
impl KeyedHash<KEY_LEN, HASH_LEN> for Blake2b {
type Error = Error;
fn keyed_hash(
key: &[u8; KEY_LEN],
data: &[u8],
out: &mut [u8; HASH_LEN],
) -> Result<(), Self::Error> {
let mut h = Blake2bBuilder::new_keyed_const(key)
// this may fail if the key length is invalid, but 32 is fine
.map_err(|_| Error::InternalError)?
.build_const_digest_len()
.map_err(|_|
// this can only fail if the output length is invalid, but 32 is fine.
Error::InternalError)?;
h.update(data).map_err(|_| Error::DataTooLong)?;
h.finalize(out);
Ok(())
}
}
impl KeyedHashBlake2b for Blake2b {}
#[cfg(test)]
mod equivalence_tests {
use super::*;
use rand::RngCore;
#[test]
fn fuzz_equivalence_libcrux_old_new() {
let datas: [&[u8]; 3] = [
b"".as_slice(),
b"test".as_slice(),
b"abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
];
let mut key = [0; KEY_LEN];
let mut rng = rand::thread_rng();
let mut hash_left = [0; 32];
let mut hash_right = [0; 32];
for data in datas {
for _ in 0..1000 {
rng.fill_bytes(&mut key);
crate::subtle::rust_crypto::blake2b::Blake2b::keyed_hash(
&key,
data,
&mut hash_left,
)
.unwrap();
crate::subtle::libcrux::blake2b::Blake2b::keyed_hash(&key, data, &mut hash_right)
.unwrap();
assert_eq!(hash_left, hash_right);
}
}
}
}

View File

@@ -1,274 +0,0 @@
//! Implementation of the [`AeadChaCha20Poly1305`] trait based on the [`libcrux_chacha20poly1305`] crate.
use rosenpass_cipher_traits::algorithms::AeadChaCha20Poly1305;
use rosenpass_cipher_traits::primitives::{Aead, AeadError};
pub use rosenpass_cipher_traits::algorithms::aead_chacha20poly1305::{KEY_LEN, NONCE_LEN, TAG_LEN};
/// An implementation of the ChaCha20Poly1305 AEAD based on libcrux
pub struct ChaCha20Poly1305;
impl Aead<KEY_LEN, NONCE_LEN, TAG_LEN> for ChaCha20Poly1305 {
fn encrypt(
&self,
ciphertext: &mut [u8],
key: &[u8; KEY_LEN],
nonce: &[u8; NONCE_LEN],
ad: &[u8],
plaintext: &[u8],
) -> Result<(), AeadError> {
let (ctxt, tag) = libcrux_chacha20poly1305::encrypt(key, plaintext, ciphertext, ad, nonce)
.map_err(|_| AeadError::InternalError)?;
// return an error of the destination buffer is longer than expected
// because the caller wouldn't know where the end is
if ctxt.len() + tag.len() != ciphertext.len() {
return Err(AeadError::InternalError);
}
Ok(())
}
fn decrypt(
&self,
plaintext: &mut [u8],
key: &[u8; KEY_LEN],
nonce: &[u8; NONCE_LEN],
ad: &[u8],
ciphertext: &[u8],
) -> Result<(), AeadError> {
let ptxt = libcrux_chacha20poly1305::decrypt(key, plaintext, ciphertext, ad, nonce)
.map_err(|_| AeadError::DecryptError)?;
// return an error of the destination buffer is longer than expected
// because the caller wouldn't know where the end is
if ptxt.len() != plaintext.len() {
return Err(AeadError::DecryptError);
}
Ok(())
}
}
impl AeadChaCha20Poly1305 for ChaCha20Poly1305 {}
/// The idea of these tests is to check that the above implemenatation behaves, by and large, the
/// same as the one from the old libcrux and the one from RustCrypto. You can consider them janky,
/// self-rolled property-based tests.
#[cfg(test)]
mod equivalence_tests {
use super::*;
use rand::RngCore;
#[test]
fn proptest_equivalence_libcrux_rustcrypto() {
use crate::subtle::rust_crypto::chacha20poly1305_ietf::ChaCha20Poly1305 as RustCryptoChaCha20Poly1305;
let ptxts: [&[u8]; 3] = [
b"".as_slice(),
b"test".as_slice(),
b"abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
];
let mut key = [0; KEY_LEN];
let mut rng = rand::thread_rng();
let mut ctxt_left = [0; 64 + TAG_LEN];
let mut ctxt_right = [0; 64 + TAG_LEN];
let mut ptxt_left = [0; 64];
let mut ptxt_right = [0; 64];
let nonce = [0; NONCE_LEN];
let ad = b"";
for ptxt in ptxts {
for _ in 0..1000 {
rng.fill_bytes(&mut key);
let ctxt_left = &mut ctxt_left[..ptxt.len() + TAG_LEN];
let ctxt_right = &mut ctxt_right[..ptxt.len() + TAG_LEN];
let ptxt_left = &mut ptxt_left[..ptxt.len()];
let ptxt_right = &mut ptxt_right[..ptxt.len()];
RustCryptoChaCha20Poly1305
.encrypt(ctxt_left, &key, &nonce, ad, ptxt)
.unwrap();
ChaCha20Poly1305
.encrypt(ctxt_right, &key, &nonce, ad, ptxt)
.unwrap();
assert_eq!(ctxt_left, ctxt_right);
RustCryptoChaCha20Poly1305
.decrypt(ptxt_left, &key, &nonce, ad, ctxt_left)
.unwrap();
ChaCha20Poly1305
.decrypt(ptxt_right, &key, &nonce, ad, ctxt_right)
.unwrap();
assert_eq!(ptxt_left, ptxt);
assert_eq!(ptxt_right, ptxt);
}
}
}
#[test]
#[cfg(feature = "experiment_libcrux_chachapoly_test")]
fn proptest_equivalence_libcrux_old_new() {
let ptxts: [&[u8]; 3] = [
b"".as_slice(),
b"test".as_slice(),
b"abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd",
];
let mut key = [0; KEY_LEN];
let mut rng = rand::thread_rng();
let mut ctxt_left = [0; 64 + TAG_LEN];
let mut ctxt_right = [0; 64 + TAG_LEN];
let mut ptxt_left = [0; 64];
let mut ptxt_right = [0; 64];
let nonce = [0; NONCE_LEN];
let ad = b"";
for ptxt in ptxts {
for _ in 0..1000 {
rng.fill_bytes(&mut key);
let ctxt_left = &mut ctxt_left[..ptxt.len() + TAG_LEN];
let ctxt_right = &mut ctxt_right[..ptxt.len() + TAG_LEN];
let ptxt_left = &mut ptxt_left[..ptxt.len()];
let ptxt_right = &mut ptxt_right[..ptxt.len()];
encrypt(ctxt_left, &key, &nonce, ad, ptxt).unwrap();
ChaCha20Poly1305
.encrypt(ctxt_right, &key, &nonce, ad, ptxt)
.unwrap();
assert_eq!(ctxt_left, ctxt_right);
decrypt(ptxt_left, &key, &nonce, ad, ctxt_left).unwrap();
ChaCha20Poly1305
.decrypt(ptxt_right, &key, &nonce, ad, ctxt_right)
.unwrap();
assert_eq!(ptxt_left, ptxt);
assert_eq!(ptxt_right, ptxt);
}
}
// The old libcrux functions:
// The functions below are from the old libcrux backend. I am keeping them around so we can
// check if they behave the same.
use rosenpass_to::ops::copy_slice;
use rosenpass_to::To;
use zeroize::Zeroize;
/// Encrypts using ChaCha20Poly1305 as implemented in [libcrux](https://github.com/cryspen/libcrux).
/// Key and nonce MUST be chosen (pseudo-)randomly. The `key` slice MUST have a length of
/// [KEY_LEN]. The `nonce` slice MUST have a length of [NONCE_LEN]. The last [TAG_LEN] bytes
/// written in `ciphertext` are the tag guaranteeing integrity. `ciphertext` MUST have a capacity of
/// `plaintext.len()` + [TAG_LEN].
///
/// # Examples
///```rust
/// # use rosenpass_ciphers::subtle::chacha20poly1305_ietf_libcrux::{encrypt, TAG_LEN, KEY_LEN, NONCE_LEN};
///
/// const PLAINTEXT_LEN: usize = 43;
/// let plaintext = "post-quantum cryptography is very important".as_bytes();
/// assert_eq!(PLAINTEXT_LEN, plaintext.len());
/// let key: &[u8] = &[0u8; KEY_LEN]; // THIS IS NOT A SECURE KEY
/// let nonce: &[u8] = &[0u8; NONCE_LEN]; // THIS IS NOT A SECURE NONCE
/// let additional_data: &[u8] = "the encrypted message is very important".as_bytes();
/// let mut ciphertext_buffer = [0u8; PLAINTEXT_LEN + TAG_LEN];
///
/// let res: anyhow::Result<()> = encrypt(&mut ciphertext_buffer, key, nonce, additional_data, plaintext);
/// assert!(res.is_ok());
/// # let expected_ciphertext: &[u8] = &[239, 104, 148, 202, 120, 32, 77, 27, 246, 206, 226, 17,
/// # 83, 78, 122, 116, 187, 123, 70, 199, 58, 130, 21, 1, 107, 230, 58, 77, 18, 152, 31, 159, 80,
/// # 151, 72, 27, 236, 137, 60, 55, 180, 31, 71, 97, 199, 12, 60, 155, 70, 221, 225, 110, 132, 191,
/// # 8, 114, 85, 4, 25];
/// # assert_eq!(expected_ciphertext, &ciphertext_buffer);
///```
///
#[inline]
pub fn encrypt(
ciphertext: &mut [u8],
key: &[u8],
nonce: &[u8],
ad: &[u8],
plaintext: &[u8],
) -> anyhow::Result<()> {
let (ciphertext, mac) = ciphertext.split_at_mut(ciphertext.len() - TAG_LEN);
use libcrux::aead as C;
let crux_key = C::Key::Chacha20Poly1305(C::Chacha20Key(key.try_into().unwrap()));
let crux_iv = C::Iv(nonce.try_into().unwrap());
copy_slice(plaintext).to(ciphertext);
let crux_tag = libcrux::aead::encrypt(&crux_key, ciphertext, crux_iv, ad).unwrap();
copy_slice(crux_tag.as_ref()).to(mac);
match crux_key {
C::Key::Chacha20Poly1305(mut k) => k.0.zeroize(),
_ => panic!(),
}
Ok(())
}
/// Decrypts a `ciphertext` and verifies the integrity of the `ciphertext` and the additional data
/// `ad`. using ChaCha20Poly1305 as implemented in [libcrux](https://github.com/cryspen/libcrux).
///
/// The `key` slice MUST have a length of [KEY_LEN]. The `nonce` slice MUST have a length of
/// [NONCE_LEN]. The plaintext buffer must have a capacity of `ciphertext.len()` - [TAG_LEN].
///
/// # Examples
///```rust
/// # use rosenpass_ciphers::subtle::chacha20poly1305_ietf_libcrux::{decrypt, TAG_LEN, KEY_LEN, NONCE_LEN};
/// let ciphertext: &[u8] = &[239, 104, 148, 202, 120, 32, 77, 27, 246, 206, 226, 17,
/// 83, 78, 122, 116, 187, 123, 70, 199, 58, 130, 21, 1, 107, 230, 58, 77, 18, 152, 31, 159, 80,
/// 151, 72, 27, 236, 137, 60, 55, 180, 31, 71, 97, 199, 12, 60, 155, 70, 221, 225, 110, 132, 191,
/// 8, 114, 85, 4, 25]; // this is the ciphertext generated by the example for the encryption
/// const PLAINTEXT_LEN: usize = 43;
/// assert_eq!(PLAINTEXT_LEN + TAG_LEN, ciphertext.len());
///
/// let key: &[u8] = &[0u8; KEY_LEN]; // THIS IS NOT A SECURE KEY
/// let nonce: &[u8] = &[0u8; NONCE_LEN]; // THIS IS NOT A SECURE NONCE
/// let additional_data: &[u8] = "the encrypted message is very important".as_bytes();
/// let mut plaintext_buffer = [0u8; PLAINTEXT_LEN];
///
/// let res: anyhow::Result<()> = decrypt(&mut plaintext_buffer, key, nonce, additional_data, ciphertext);
/// assert!(res.is_ok());
/// let expected_plaintext = "post-quantum cryptography is very important".as_bytes();
/// assert_eq!(expected_plaintext, plaintext_buffer);
///
///```
#[inline]
pub fn decrypt(
plaintext: &mut [u8],
key: &[u8],
nonce: &[u8],
ad: &[u8],
ciphertext: &[u8],
) -> anyhow::Result<()> {
let (ciphertext, mac) = ciphertext.split_at(ciphertext.len() - TAG_LEN);
use libcrux::aead as C;
let crux_key = C::Key::Chacha20Poly1305(C::Chacha20Key(key.try_into().unwrap()));
let crux_iv = C::Iv(nonce.try_into().unwrap());
let crux_tag = C::Tag::from_slice(mac).unwrap();
copy_slice(ciphertext).to(plaintext);
libcrux::aead::decrypt(&crux_key, plaintext, crux_iv, ad, &crux_tag).unwrap();
match crux_key {
C::Key::Chacha20Poly1305(mut k) => k.0.zeroize(),
_ => panic!(),
}
Ok(())
}
}
}

View File

@@ -1,133 +0,0 @@
//! Implementation of the [`KemKyber512`] trait based on the [`libcrux_ml_kem`] crate.
use libcrux_ml_kem::kyber512;
use rand::RngCore;
use rosenpass_cipher_traits::algorithms::KemKyber512;
use rosenpass_cipher_traits::primitives::{Kem, KemError};
pub use rosenpass_cipher_traits::algorithms::kem_kyber512::{CT_LEN, PK_LEN, SHK_LEN, SK_LEN};
/// An implementation of the Kyber512 KEM based on libcrux
pub struct Kyber512;
impl Kem<SK_LEN, PK_LEN, CT_LEN, SHK_LEN> for Kyber512 {
fn keygen(&self, sk: &mut [u8; SK_LEN], pk: &mut [u8; PK_LEN]) -> Result<(), KemError> {
let mut randomness = [0u8; libcrux_ml_kem::KEY_GENERATION_SEED_SIZE];
rand::thread_rng().fill_bytes(&mut randomness);
let key_pair = kyber512::generate_key_pair(randomness);
let new_sk: &[u8; SK_LEN] = key_pair.sk();
let new_pk: &[u8; PK_LEN] = key_pair.pk();
sk.clone_from_slice(new_sk);
pk.clone_from_slice(new_pk);
Ok(())
}
fn encaps(
&self,
shk: &mut [u8; SHK_LEN],
ct: &mut [u8; CT_LEN],
pk: &[u8; PK_LEN],
) -> Result<(), KemError> {
let mut randomness = [0u8; libcrux_ml_kem::SHARED_SECRET_SIZE];
rand::thread_rng().fill_bytes(&mut randomness);
let (new_ct, new_shk) = kyber512::encapsulate(&pk.into(), randomness);
let new_ct: &[u8; CT_LEN] = new_ct.as_slice();
shk.clone_from_slice(&new_shk);
ct.clone_from_slice(new_ct);
Ok(())
}
fn decaps(
&self,
shk: &mut [u8; SHK_LEN],
sk: &[u8; SK_LEN],
ct: &[u8; CT_LEN],
) -> Result<(), KemError> {
let new_shk: [u8; SHK_LEN] = kyber512::decapsulate(&sk.into(), &ct.into());
shk.clone_from(&new_shk);
Ok(())
}
}
impl Default for Kyber512 {
fn default() -> Self {
Self
}
}
impl KemKyber512 for Kyber512 {}
#[cfg(test)]
mod equivalence_tests {
use super::*;
// Test that libcrux and OQS produce the same results
#[test]
fn proptest_equivalence_libcrux_oqs() {
use rosenpass_oqs::Kyber512 as OqsKyber512;
let (mut sk1, mut pk1) = ([0; SK_LEN], [0; PK_LEN]);
let (mut sk2, mut pk2) = ([0; SK_LEN], [0; PK_LEN]);
let mut ct_left = [0; CT_LEN];
let mut ct_right = [0; CT_LEN];
let mut shk_enc_left = [0; SHK_LEN];
let mut shk_enc_right = [0; SHK_LEN];
// naming schema: shk_dec_{encapsing lib}_{decapsing lib}
// should be the same if the encapsing lib was the same.
let mut shk_dec_left_left = [0; SHK_LEN];
let mut shk_dec_left_right = [0; SHK_LEN];
let mut shk_dec_right_left = [0; SHK_LEN];
let mut shk_dec_right_right = [0; SHK_LEN];
for _ in 0..1000 {
let sk1 = &mut sk1;
let pk1 = &mut pk1;
let sk2 = &mut sk2;
let pk2 = &mut pk2;
let ct_left = &mut ct_left;
let ct_right = &mut ct_right;
let shk_enc_left = &mut shk_enc_left;
let shk_enc_right = &mut shk_enc_right;
let shk_dec_left_left = &mut shk_dec_left_left;
let shk_dec_left_right = &mut shk_dec_left_right;
let shk_dec_right_left = &mut shk_dec_right_left;
let shk_dec_right_right = &mut shk_dec_right_right;
Kyber512.keygen(sk1, pk1).unwrap();
Kyber512.keygen(sk2, pk2).unwrap();
Kyber512.encaps(shk_enc_left, ct_left, pk2).unwrap();
OqsKyber512.encaps(shk_enc_right, ct_right, pk2).unwrap();
Kyber512.decaps(shk_dec_left_left, sk2, ct_left).unwrap();
Kyber512.decaps(shk_dec_right_left, sk2, ct_right).unwrap();
OqsKyber512
.decaps(shk_dec_left_right, sk2, ct_left)
.unwrap();
OqsKyber512
.decaps(shk_dec_right_right, sk2, ct_right)
.unwrap();
assert_eq!(shk_enc_left, shk_dec_left_left);
assert_eq!(shk_enc_left, shk_dec_left_right);
assert_eq!(shk_enc_right, shk_dec_right_left);
assert_eq!(shk_enc_right, shk_dec_right_right);
}
}
}

View File

@@ -1,14 +0,0 @@
//! Implementations backed by libcrux, a verified crypto library.
//!
//! [Website](https://cryspen.com/libcrux/)
//!
//! [Github](https://github.com/cryspen/libcrux)
#[cfg(feature = "experiment_libcrux_define_blake2")]
pub mod blake2b;
#[cfg(feature = "experiment_libcrux_define_chachapoly")]
pub mod chacha20poly1305_ietf;
#[cfg(feature = "experiment_libcrux_define_kyber")]
pub mod kyber512;

View File

@@ -1,16 +1,13 @@
//! Contains the implementations of the crypto algorithms used throughout Rosenpass.
pub mod keyed_hash;
pub use custom::incorrect_hmac_blake2b;
pub use rust_crypto::{blake2b, keyed_shake256};
pub mod custom;
pub mod rust_crypto;
#[cfg(any(
feature = "experiment_libcrux_define_blake2",
feature = "experiment_libcrux_define_chachapoly",
feature = "experiment_libcrux_define_kyber",
))]
pub mod libcrux;
/// This module provides the following cryptographic schemes:
/// - [blake2b]: The blake2b hash function
/// - [chacha20poly1305_ietf]: The Chacha20Poly1305 AEAD as implemented in [RustCrypto](https://crates.io/crates/chacha20poly1305) (only used when the feature `experiment_libcrux` is disabled).
/// - [chacha20poly1305_ietf_libcrux]: The Chacha20Poly1305 AEAD as implemented in [libcrux](https://github.com/cryspen/libcrux) (only used when the feature `experiment_libcrux` is enabled).
/// - [incorrect_hmac_blake2b]: An (incorrect) hmac based on [blake2b].
/// - [xchacha20poly1305_ietf] The Chacha20Poly1305 AEAD as implemented in [RustCrypto](https://crates.io/crates/chacha20poly1305)
pub mod blake2b;
#[cfg(not(feature = "experiment_libcrux"))]
pub mod chacha20poly1305_ietf;
#[cfg(feature = "experiment_libcrux")]
pub mod chacha20poly1305_ietf_libcrux;
pub mod incorrect_hmac_blake2b;
pub mod xchacha20poly1305_ietf;

View File

@@ -1,44 +0,0 @@
use zeroize::Zeroizing;
use blake2::digest::crypto_common::generic_array::GenericArray;
use blake2::digest::crypto_common::typenum::U32;
use blake2::digest::{FixedOutput, Mac};
use blake2::Blake2bMac;
use rosenpass_cipher_traits::primitives::KeyedHash;
use rosenpass_to::{ops::copy_slice, To};
pub use rosenpass_cipher_traits::algorithms::keyed_hash_blake2b::{HASH_LEN, KEY_LEN};
/// Specify that the used implementation of BLAKE2b is the MAC version of BLAKE2b
/// with output and key length of 32 bytes (see [Blake2bMac]).
type Impl = Blake2bMac<U32>;
/// Hashes the given `data` with the [Blake2bMac] hash function under the given `key`.
/// The both the length of the output the length of the key 32 bytes (or 256 bits).
pub struct Blake2b;
impl KeyedHash<KEY_LEN, HASH_LEN> for Blake2b {
type Error = anyhow::Error;
fn keyed_hash(
key: &[u8; KEY_LEN],
data: &[u8],
out: &mut [u8; HASH_LEN],
) -> Result<(), Self::Error> {
let mut h = Impl::new_from_slice(key)?;
h.update(data);
// Jesus christ, blake2 crate, your usage of GenericArray might be nice and fancy,
// but it introduces a ton of complexity. This cost me half an hour just to figure
// out the right way to use the imports while allowing for zeroization.
// An API based on slices might actually be simpler.
let mut tmp = Zeroizing::new([0u8; HASH_LEN]);
let tmp = GenericArray::from_mut_slice(tmp.as_mut());
h.finalize_into(tmp);
copy_slice(tmp.as_ref()).to(out);
Ok(())
}
}
impl rosenpass_cipher_traits::algorithms::KeyedHashBlake2b for Blake2b {}

View File

@@ -1,79 +0,0 @@
use rosenpass_to::ops::copy_slice;
use rosenpass_to::To;
use rosenpass_cipher_traits::algorithms::AeadChaCha20Poly1305;
use rosenpass_cipher_traits::primitives::{Aead, AeadError};
use chacha20poly1305::aead::generic_array::GenericArray;
use chacha20poly1305::ChaCha20Poly1305 as AeadImpl;
use chacha20poly1305::{AeadInPlace, KeyInit};
pub use rosenpass_cipher_traits::algorithms::aead_chacha20poly1305::{KEY_LEN, NONCE_LEN, TAG_LEN};
/// Implements the [`Aead`] and [`AeadChaCha20Poly1305`] traits backed by the RustCrypto
/// implementation.
pub struct ChaCha20Poly1305;
impl Aead<KEY_LEN, NONCE_LEN, TAG_LEN> for ChaCha20Poly1305 {
fn encrypt(
&self,
ciphertext: &mut [u8],
key: &[u8; KEY_LEN],
nonce: &[u8; NONCE_LEN],
ad: &[u8],
plaintext: &[u8],
) -> Result<(), AeadError> {
// The comparison looks complicated, but we need to do it this way to prevent
// over/underflows.
if ciphertext.len() < TAG_LEN || ciphertext.len() - TAG_LEN < plaintext.len() {
return Err(AeadError::InvalidLengths);
}
let nonce = GenericArray::from_slice(nonce);
let (ct, mac) = ciphertext.split_at_mut(ciphertext.len() - TAG_LEN);
copy_slice(plaintext).to(ct);
// This only fails if the length is wrong, which really shouldn't happen and would
// constitute an internal error.
let encrypter = AeadImpl::new_from_slice(key).map_err(|_| AeadError::InternalError)?;
let mac_value = encrypter
.encrypt_in_place_detached(nonce, ad, ct)
.map_err(|_| AeadError::InternalError)?;
copy_slice(&mac_value[..]).to(mac);
Ok(())
}
fn decrypt(
&self,
plaintext: &mut [u8],
key: &[u8; KEY_LEN],
nonce: &[u8; NONCE_LEN],
ad: &[u8],
ciphertext: &[u8],
) -> Result<(), AeadError> {
// The comparison looks complicated, but we need to do it this way to prevent
// over/underflows.
if ciphertext.len() < TAG_LEN || ciphertext.len() - TAG_LEN < plaintext.len() {
return Err(AeadError::InvalidLengths);
}
let nonce = GenericArray::from_slice(nonce);
let (ct, mac) = ciphertext.split_at(ciphertext.len() - TAG_LEN);
let tag = GenericArray::from_slice(mac);
copy_slice(ct).to(plaintext);
// This only fails if the length is wrong, which really shouldn't happen and would
// constitute an internal error.
let decrypter = AeadImpl::new_from_slice(key).map_err(|_| AeadError::InternalError)?;
decrypter
.decrypt_in_place_detached(nonce, ad, plaintext, tag)
.map_err(|_| AeadError::DecryptError)?;
Ok(())
}
}
impl AeadChaCha20Poly1305 for ChaCha20Poly1305 {}

View File

@@ -1,117 +0,0 @@
use anyhow::ensure;
use rosenpass_cipher_traits::primitives::{InferKeyedHash, KeyedHash};
use sha3::digest::{ExtendableOutput, Update, XofReader};
use sha3::Shake256;
pub use rosenpass_cipher_traits::algorithms::keyed_hash_shake256::{HASH_LEN, KEY_LEN};
/// An implementation of the [`KeyedHash`] trait backed by the RustCrypto implementation of SHAKE256.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct SHAKE256Core<const KEY_LEN: usize, const HASH_LEN: usize>;
impl<const KEY_LEN: usize, const HASH_LEN: usize> KeyedHash<KEY_LEN, HASH_LEN>
for SHAKE256Core<KEY_LEN, HASH_LEN>
{
type Error = anyhow::Error;
/// Provides a keyed hash function based on SHAKE256. To work for the protocol, the output length
/// and key length are fixed to 32 bytes (also see [KEY_LEN] and [HASH_LEN]).
///
/// Note that the SHAKE256 is designed for 64 bytes output length, which we truncate to 32 bytes
/// to work well with the overall protocol. Referring to Table 4 of FIPS 202, this offers the
/// same collision resistance as SHAKE128, but 256 bits of preimage resistance. We therefore
/// prefer a truncated SHAKE256 over SHAKE128.
///
/// #Examples
/// ```rust
/// # use rosenpass_ciphers::subtle::rust_crypto::keyed_shake256::SHAKE256Core;
/// use rosenpass_cipher_traits::primitives::KeyedHash;
/// const KEY_LEN: usize = 32;
/// const HASH_LEN: usize = 32;
/// let key: [u8; 32] = [0; KEY_LEN];
/// let data: [u8; 32] = [255; 32]; // arbitrary data, could also be longer
/// // buffer for the hash output
/// let mut hash_data: [u8; 32] = [0u8; HASH_LEN];
///
/// assert!(SHAKE256Core::<32, 32>::keyed_hash(&key, &data, &mut hash_data).is_ok(), "Hashing has to return OK result");
/// # let expected_hash: &[u8] = &[174, 4, 47, 188, 1, 228, 179, 246, 67, 43, 255, 94, 155, 11,
/// 187, 161, 38, 110, 217, 23, 4, 62, 172, 30, 218, 187, 249, 80, 171, 21, 145, 238];
/// # assert_eq!(hash_data, expected_hash);
/// ```
fn keyed_hash(
key: &[u8; KEY_LEN],
data: &[u8],
out: &mut [u8; HASH_LEN],
) -> Result<(), Self::Error> {
// Since SHAKE256 is a XOF, we fix the output length manually to what is required for the
// protocol.
ensure!(out.len() == HASH_LEN);
// Not bothering with padding; the implementation
// uses appropriately sized keys.
ensure!(key.len() == KEY_LEN);
let mut shake256 = Shake256::default();
shake256.update(key);
shake256.update(data);
// Since we use domain separation extensively, related outputs of the truncated XOF
// are not a concern. This follows the NIST recommendations in Section A.2 of the FIPS 202
// standard, (pages 24/25, i.e., 32/33 in the PDF).
shake256.finalize_xof().read(out);
Ok(())
}
}
impl<const KEY_LEN: usize, const HASH_LEN: usize> SHAKE256Core<KEY_LEN, HASH_LEN> {
pub fn new() -> Self {
Self
}
}
impl<const KEY_LEN: usize, const HASH_LEN: usize> Default for SHAKE256Core<KEY_LEN, HASH_LEN> {
fn default() -> Self {
Self::new()
}
}
/// This type provides the same functionality as [SHAKE256Core], but bound to an instance.
/// In contrast to [SHAKE256Core], this allows for type interference and thus allows the user of the
/// type to omit explicit type parameters when instantiating the type or using it.
///
/// The instantiation is based on the [InferKeyedHash] trait.
///
/// ```rust
/// # use rosenpass_ciphers::subtle::rust_crypto::keyed_shake256::{SHAKE256};
/// use rosenpass_cipher_traits::primitives::KeyedHashInstance;
/// const KEY_LEN: usize = 32;
/// const HASH_LEN: usize = 32;
/// let key: [u8; KEY_LEN] = [0; KEY_LEN];
/// let data: [u8; 32] = [255; 32]; // arbitrary data, could also be longer
/// // buffer for the hash output
/// let mut hash_data: [u8; 32] = [0u8; HASH_LEN];
/// assert!(SHAKE256::new().keyed_hash(&key, &data, &mut hash_data).is_ok(), "Hashing has to return OK result");
/// # let expected_hash: &[u8] = &[174, 4, 47, 188, 1, 228, 179, 246, 67, 43, 255, 94, 155, 11, 187,
/// 161, 38, 110, 217, 23, 4, 62, 172, 30, 218, 187, 249, 80, 171, 21, 145, 238];
/// # assert_eq!(hash_data, expected_hash);
/// ```
pub type SHAKE256<const KEY_LEN: usize, const HASH_LEN: usize> =
InferKeyedHash<SHAKE256Core<KEY_LEN, HASH_LEN>, KEY_LEN, HASH_LEN>;
/// The SHAKE256_32 type is a specific instance of the [SHAKE256] type with the key length and hash
/// length fixed to 32 bytes.
///
/// ```rust
/// # use rosenpass_ciphers::subtle::keyed_shake256::{SHAKE256_32};
/// use rosenpass_cipher_traits::primitives::KeyedHashInstance;
/// const KEY_LEN: usize = 32;
/// const HASH_LEN: usize = 32;
/// let key: [u8; 32] = [0; KEY_LEN];
/// let data: [u8; 32] = [255; 32]; // arbitrary data, could also be longer
/// // buffer for the hash output
/// let mut hash_data: [u8; 32] = [0u8; HASH_LEN];
///
/// assert!(SHAKE256_32::new().keyed_hash(&key, &data, &mut hash_data).is_ok(), "Hashing has to return OK result");
/// # let expected_hash: &[u8] = &[174, 4, 47, 188, 1, 228, 179, 246, 67, 43, 255, 94, 155, 11, 187,
/// 161, 38, 110, 217, 23, 4, 62, 172, 30, 218, 187, 249, 80, 171, 21, 145, 238];
/// # assert_eq!(hash_data, expected_hash);
/// ```
pub type SHAKE256_32 = SHAKE256<32, 32>;

View File

@@ -1,7 +0,0 @@
//! Implementations backed by RustCrypto
pub mod blake2b;
pub mod keyed_shake256;
pub mod chacha20poly1305_ietf;
pub mod xchacha20poly1305_ietf;

View File

@@ -1,82 +1,17 @@
use rosenpass_to::ops::copy_slice;
use rosenpass_to::To;
use rosenpass_cipher_traits::algorithms::aead_xchacha20poly1305::AeadXChaCha20Poly1305;
use rosenpass_cipher_traits::primitives::{Aead, AeadError, AeadWithNonceInCiphertext};
use rosenpass_util::typenum2const;
use chacha20poly1305::aead::generic_array::GenericArray;
use chacha20poly1305::XChaCha20Poly1305 as AeadImpl;
use chacha20poly1305::{AeadInPlace, KeyInit};
use chacha20poly1305::{AeadCore, AeadInPlace, KeyInit, KeySizeUser};
pub use rosenpass_cipher_traits::algorithms::aead_xchacha20poly1305::{
KEY_LEN, NONCE_LEN, TAG_LEN,
};
/// Implements the [`Aead`] and [`AeadXChaCha20Poly1305`] traits backed by the RustCrypto
/// implementation.
pub struct XChaCha20Poly1305;
impl Aead<KEY_LEN, NONCE_LEN, TAG_LEN> for XChaCha20Poly1305 {
fn encrypt(
&self,
ciphertext: &mut [u8],
key: &[u8; KEY_LEN],
nonce: &[u8; NONCE_LEN],
ad: &[u8],
plaintext: &[u8],
) -> Result<(), AeadError> {
// The comparison looks complicated, but we need to do it this way to prevent
// over/underflows.
if ciphertext.len() < TAG_LEN || ciphertext.len() - TAG_LEN < plaintext.len() {
return Err(AeadError::InvalidLengths);
}
let (ct, mac) = ciphertext.split_at_mut(ciphertext.len() - TAG_LEN);
copy_slice(plaintext).to(ct);
let nonce = GenericArray::from_slice(nonce);
// This only fails if the length is wrong, which really shouldn't happen and would
// constitute an internal error.
let encrypter = AeadImpl::new_from_slice(key).map_err(|_| AeadError::InternalError)?;
let mac_value = encrypter
.encrypt_in_place_detached(nonce, ad, ct)
.map_err(|_| AeadError::InternalError)?;
copy_slice(&mac_value[..]).to(mac);
Ok(())
}
fn decrypt(
&self,
plaintext: &mut [u8],
key: &[u8; KEY_LEN],
nonce: &[u8; NONCE_LEN],
ad: &[u8],
ciphertext: &[u8],
) -> Result<(), AeadError> {
// The comparison looks complicated, but we need to do it this way to prevent
// over/underflows.
if ciphertext.len() < TAG_LEN || ciphertext.len() - TAG_LEN < plaintext.len() {
return Err(AeadError::InvalidLengths);
}
let (ct, mac) = ciphertext.split_at(ciphertext.len() - TAG_LEN);
let nonce = GenericArray::from_slice(nonce);
let tag = GenericArray::from_slice(mac);
copy_slice(ct).to(plaintext);
// This only fails if the length is wrong, which really shouldn't happen and would
// constitute an internal error.
let decrypter = AeadImpl::new_from_slice(key).map_err(|_| AeadError::InternalError)?;
decrypter
.decrypt_in_place_detached(nonce, ad, plaintext, tag)
.map_err(|_| AeadError::DecryptError)?;
Ok(())
}
}
impl AeadXChaCha20Poly1305 for XChaCha20Poly1305 {}
/// The key length is 32 bytes or 256 bits.
pub const KEY_LEN: usize = typenum2const! { <AeadImpl as KeySizeUser>::KeySize };
/// The MAC tag length is 16 bytes or 128 bits.
pub const TAG_LEN: usize = typenum2const! { <AeadImpl as AeadCore>::TagSize };
/// The nonce length is 24 bytes or 192 bits.
pub const NONCE_LEN: usize = typenum2const! { <AeadImpl as AeadCore>::NonceSize };
/// Encrypts using XChaCha20Poly1305 as implemented in [RustCrypto](https://github.com/RustCrypto/AEADs/tree/master/chacha20poly1305).
/// `key` and `nonce` MUST be chosen (pseudo-)randomly. The `key` slice MUST have a length of
@@ -88,12 +23,12 @@ impl AeadXChaCha20Poly1305 for XChaCha20Poly1305 {}
///
/// # Examples
///```rust
/// # use rosenpass_ciphers::subtle::rust_crypto::xchacha20poly1305_ietf::{encrypt, TAG_LEN, KEY_LEN, NONCE_LEN};
/// # use rosenpass_ciphers::subtle::xchacha20poly1305_ietf::{encrypt, TAG_LEN, KEY_LEN, NONCE_LEN};
/// const PLAINTEXT_LEN: usize = 43;
/// let plaintext = "post-quantum cryptography is very important".as_bytes();
/// assert_eq!(PLAINTEXT_LEN, plaintext.len());
/// let key: &[u8; KEY_LEN] = &[0u8; KEY_LEN]; // THIS IS NOT A SECURE KEY
/// let nonce: &[u8; NONCE_LEN] = &[0u8; NONCE_LEN]; // THIS IS NOT A SECURE NONCE
/// let key: &[u8] = &[0u8; KEY_LEN]; // THIS IS NOT A SECURE KEY
/// let nonce: &[u8] = &[0u8; NONCE_LEN]; // THIS IS NOT A SECURE NONCE
/// let additional_data: &[u8] = "the encrypted message is very important".as_bytes();
/// let mut ciphertext_buffer = [0u8; NONCE_LEN + PLAINTEXT_LEN + TAG_LEN];
///
@@ -109,14 +44,19 @@ impl AeadXChaCha20Poly1305 for XChaCha20Poly1305 {}
#[inline]
pub fn encrypt(
ciphertext: &mut [u8],
key: &[u8; KEY_LEN],
nonce: &[u8; NONCE_LEN],
key: &[u8],
nonce: &[u8],
ad: &[u8],
plaintext: &[u8],
) -> anyhow::Result<()> {
XChaCha20Poly1305
.encrypt_with_nonce_in_ctxt(ciphertext, key, nonce, ad, plaintext)
.map_err(anyhow::Error::from)
let nonce = GenericArray::from_slice(nonce);
let (n, ct_mac) = ciphertext.split_at_mut(NONCE_LEN);
let (ct, mac) = ct_mac.split_at_mut(ct_mac.len() - TAG_LEN);
copy_slice(nonce).to(n);
copy_slice(plaintext).to(ct);
let mac_value = AeadImpl::new_from_slice(key)?.encrypt_in_place_detached(nonce, ad, ct)?;
copy_slice(&mac_value[..]).to(mac);
Ok(())
}
/// Decrypts a `ciphertext` and verifies the integrity of the `ciphertext` and the additional data
@@ -131,7 +71,7 @@ pub fn encrypt(
///
/// # Examples
///```rust
/// # use rosenpass_ciphers::subtle::rust_crypto::xchacha20poly1305_ietf::{decrypt, TAG_LEN, KEY_LEN, NONCE_LEN};
/// # use rosenpass_ciphers::subtle::xchacha20poly1305_ietf::{decrypt, TAG_LEN, KEY_LEN, NONCE_LEN};
/// let ciphertext: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
/// # 0, 0, 0, 0, 8, 241, 229, 253, 200, 81, 248, 30, 183, 149, 134, 168, 149, 87, 109, 49, 159, 108,
/// # 206, 89, 51, 232, 232, 197, 163, 253, 254, 208, 73, 76, 253, 13, 247, 162, 133, 184, 177, 44,
@@ -140,8 +80,8 @@ pub fn encrypt(
/// const PLAINTEXT_LEN: usize = 43;
/// assert_eq!(PLAINTEXT_LEN + TAG_LEN + NONCE_LEN, ciphertext.len());
///
/// let key: &[u8; KEY_LEN] = &[0u8; KEY_LEN]; // THIS IS NOT A SECURE KEY
/// let nonce: &[u8; NONCE_LEN] = &[0u8; NONCE_LEN]; // THIS IS NOT A SECURE NONCE
/// let key: &[u8] = &[0u8; KEY_LEN]; // THIS IS NOT A SECURE KEY
/// let nonce: &[u8] = &[0u8; NONCE_LEN]; // THIS IS NOT A SECURE NONCE
/// let additional_data: &[u8] = "the encrypted message is very important".as_bytes();
/// let mut plaintext_buffer = [0u8; PLAINTEXT_LEN];
///
@@ -154,11 +94,15 @@ pub fn encrypt(
#[inline]
pub fn decrypt(
plaintext: &mut [u8],
key: &[u8; KEY_LEN],
key: &[u8],
ad: &[u8],
ciphertext: &[u8],
) -> anyhow::Result<()> {
XChaCha20Poly1305
.decrypt_with_nonce_in_ctxt(plaintext, key, ad, ciphertext)
.map_err(anyhow::Error::from)
let (n, ct_mac) = ciphertext.split_at(NONCE_LEN);
let (ct, mac) = ct_mac.split_at(ct_mac.len() - TAG_LEN);
let nonce = GenericArray::from_slice(n);
let tag = GenericArray::from_slice(mac);
copy_slice(ct).to(plaintext);
AeadImpl::new_from_slice(key)?.decrypt_in_place_detached(nonce, ad, plaintext, tag)?;
Ok(())
}

View File

@@ -8,7 +8,6 @@ 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
@@ -20,7 +19,7 @@ rosenpass-to = { workspace = true }
memsec = { workspace = true }
[dev-dependencies]
rand = { workspace = true }
rand = "0.8.5"
[lints.rust]
unexpected_cfgs = { level = "allow", check-cfg = ['cfg(coverage)'] }

View File

@@ -32,11 +32,8 @@ pub fn memcmp(a: &[u8], b: &[u8]) -> bool {
/// For discussion on how to (further) ensure the constant-time execution of this function,
/// see <https://github.com/rosenpass/rosenpass/issues/232>
#[cfg(all(test, feature = "constant_time_tests"))]
// Stopgap measure against https://github.com/rosenpass/rosenpass/issues/634
#[cfg(not(all(target_os = "macos", target_arch = "aarch64")))]
mod tests {
use super::*;
use core::hint::black_box;
use rand::seq::SliceRandom;
use rand::thread_rng;
use std::time::Instant;
@@ -53,12 +50,14 @@ mod tests {
fn memcmp_runs_in_constant_time() {
// prepare data to compare
let n: usize = 1E6 as usize; // number of comparisons to run
const LEN: usize = 1024; // length of each slice passed as parameters to the tested comparison function
let len = 1024; // length of each slice passed as parameters to the tested comparison function
let a1 = "a".repeat(len);
let a2 = a1.clone();
let b = "b".repeat(len);
let a = [b'a'; LEN];
let b = [b'b'; LEN];
let mut tmp = [0u8; LEN];
let a1 = a1.as_bytes();
let a2 = a2.as_bytes();
let b = b.as_bytes();
// vector representing all timing tests
//
@@ -72,14 +71,12 @@ mod tests {
// run comparisons / call function to test
for test in tests.iter_mut() {
let src = match test.0 {
true => a,
false => b,
};
tmp.copy_from_slice(&src);
let now = Instant::now();
memcmp(black_box(&a), black_box(&tmp));
if test.0 {
memcmp(a1, a2);
} else {
memcmp(a1, b);
}
test.1 = now.elapsed();
// println!("eq: {}, elapsed: {:.2?}", test.0, test.1);
}
@@ -120,6 +117,6 @@ mod tests {
assert!(
correlation.abs() < 0.01,
"execution time correlates with result"
)
);
}
}

View File

@@ -23,8 +23,7 @@ main() {
exc cargo llvm-cov --all-features --workspace --doctests --branch
exc rm -rf target/llvm-cov-target/debug/deps/doctestbins
exc mv -v target/llvm-cov-target/doctestbins target/llvm-cov-target/debug/deps/
exc cp -rv target/llvm-cov-target/doctestbins target/llvm-cov-target/debug/deps/doctestbins
exc rm -rf "${OUTPUT_DIR}"
exc mkdir -p "${OUTPUT_DIR}"
exc grcov target/llvm-cov-target/ --llvm -s . --branch \

121
deny.toml
View File

@@ -1,121 +0,0 @@
# The graph table configures how the dependency graph is constructed and thus
# which crates the checks are performed against
[graph]
# If true, metadata will be collected with `--all-features`. Note that this can't
# be toggled off if true, if you want to conditionally enable `--all-features` it
# is recommended to pass `--all-features` on the cmd line instead
all-features = true
# If true, metadata will be collected with `--no-default-features`. The same
# caveat with `all-features` applies
no-default-features = false
# The output table provides options for how/if diagnostics are outputted
[output]
# When outputting inclusion graphs in diagnostics that include features, this
# option can be used to specify the depth at which feature edges will be added.
# This option is included since the graphs can be quite large and the addition
# of features from the crate(s) to all of the graph roots can be far too verbose.
# This option can be overridden via `--feature-depth` on the cmd line
feature-depth = 1
# This section is considered when running `cargo deny check advisories`
# More documentation for the advisories section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html
[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", "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.
# See Git Authentication for more information about setting up git authentication.
#git-fetch-with-cli = true
# This section is considered when running `cargo deny check #licenses`
# More documentation for the licenses section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html
[licenses]
# List of explicitly allowed licenses
# 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",
]
# The confidence threshold for detecting a license from license text.
# The higher the value, the more closely the license text must be to the
# canonical license text of a valid SPDX license file.
# [possible values: any between 0.0 and 1.0].
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" },
]
[licenses.private]
# If true, ignores workspace crates that aren't published, or are only
# published to private registries.
# To see how to mark a crate as unpublished (to the official registry),
# visit https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field.
ignore = true
# This section is considered when running `cargo deny check bans`.
# More documentation about the 'bans' section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html
[bans]
# Lint level for when multiple versions of the same crate are detected
multiple-versions = "warn"
# Lint level for when a crate version requirement is `*`
wildcards = "allow"
# The graph highlighting used when creating dotgraphs for crates
# with multiple versions
# * lowest-version - The path to the lowest versioned duplicate is highlighted
# * simplest-path - The path to the version with the fewest edges is highlighted
# * all - Both lowest-version and simplest-path are used
highlight = "all"
# The default lint level for `default` features for crates that are members of
# the workspace that is being checked. This can be overridden by allowing/denying
# `default` on a crate-by-crate basis if desired.
workspace-default-features = "allow"
# The default lint level for `default` features for external crates that are not
# members of the workspace. This can be overridden by allowing/denying `default`
# on a crate-by-crate basis if desired.
external-default-features = "allow"
# List of crates that are allowed. Use with care!
allow = []
# List of crates to deny
deny = []
skip-tree = []
# This section is considered when running `cargo deny check sources`.
# More documentation about the 'sources' section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html
[sources]
# Lint level for what to happen when a crate from a crate registry that is not
# in the allow list is encountered
unknown-registry = "warn"
# Lint level for what to happen when a crate from a git repository that is not
# in the allow list is encountered
unknown-git = "warn"
# List of URLs for allowed crate registries. Defaults to the crates.io index
# if not specified. If it is specified but empty, no registries are allowed.
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
# List of URLs for allowed Git repositories
allow-git = ["git+https://github.com/rosenpass/memsec.git?branch=master"]
[sources.allow-org]
# github.com organizations to allow git sources for
github = []
# gitlab.com organizations to allow git sources for
gitlab = []
# bitbucket.org organizations to allow git sources for
bitbucket = []

View File

@@ -1,46 +0,0 @@
# syntax=docker/dockerfile:1
ARG BASE_IMAGE=debian:bookworm-slim
ARG CHEF_IMAGE=rust:slim-bookworm
# Stage 1: Base image with cargo-chef installed
FROM ${CHEF_IMAGE} AS chef
RUN cargo install cargo-chef
# install software required for liboqs-rust
RUN apt-get update && apt-get install -y clang cmake && rm -rf /var/lib/apt/lists/*
# Stage 2: Prepare the cargo-chef recipe
FROM chef AS planner
WORKDIR /app
COPY . .
RUN cargo chef prepare --recipe-path recipe.json
# Stage 3: Cache dependencies using the recipe
FROM chef AS cacher
WORKDIR /app
COPY --from=planner /app/recipe.json recipe.json
RUN cargo chef cook --release --recipe-path recipe.json
# Stage 4: Build the application
FROM cacher AS builder
WORKDIR /app
COPY . .
RUN cargo build --release
# Stage 5: Install runtime-dependencies in the base image
FROM ${BASE_IMAGE} AS base_image_with_dependencies
RUN apt-get update && apt-get install -y iproute2 && rm -rf /var/lib/apt/lists/*
# Final Stage (rosenpass): Copy the rosenpass binary
FROM base_image_with_dependencies AS rosenpass
COPY --from=builder /app/target/release/rosenpass /usr/local/bin/rosenpass
ENTRYPOINT [ "/usr/local/bin/rosenpass" ]
# Final Stage (rp): Copy the rp binary
FROM base_image_with_dependencies AS rp
RUN apt-get update && apt-get install -y wireguard && rm -rf /var/lib/apt/lists/*
COPY --from=builder /app/target/release/rp /usr/local/bin/rp
ENTRYPOINT [ "/usr/local/bin/rp" ]

View File

@@ -1,203 +0,0 @@
# Rosenpass in Docker
Rosenpass provides post-quantum-secure key exchange for VPNs. It generates symmetric keys used by [WireGuard](https://www.wireguard.com/papers/wireguard.pdf) or other applications. The protocol enhances "Post-Quantum WireGuard" ([PQWG](https://eprint.iacr.org/2020/379)) with a cookie mechanism for better security against state disruption attacks.
Prebuilt Docker images are available for easy deployment:
- [`ghcr.io/rosenpass/rosenpass`](https://github.com/rosenpass/rosenpass/pkgs/container/rosenpass) the core key exchange tool
- [`ghcr.io/rosenpass/rp`](https://github.com/rosenpass/rosenpass/pkgs/container/rp) a frontend for setting up WireGuard VPNs
The entrypoint of the `rosenpass` image is the `rosenpass` executable, whose documentation can be found [here](https://rosenpass.eu/docs/rosenpass-tool/manuals/rp_manual/).
Similarly, the entrypoint of the `rp` image is the `rp` executable, with its documentation available [here](https://rosenpass.eu/docs/rosenpass-tool/manuals/rp1/).
## Usage - Standalone Key Exchange
The `ghcr.io/rosenpass/rosenpass` image can be used in a server-client setup to exchange quantum-secure shared keys.
This setup uses rosenpass as a standalone application, without using any other component such as wireguard.
What follows, is a simple setup for illustrative purposes.
Create a docker network that is used to connect the containers:
```bash
docker network create -d bridge rp
export NET=rp
```
Generate the server and client key pairs:
```bash
mkdir ./workdir-client ./workdir-server
docker run -it --rm -v ./workdir-server:/workdir ghcr.io/rosenpass/rosenpass \
gen-keys --public-key=workdir/server-public --secret-key=workdir/server-secret
docker run -it --rm -v ./workdir-client:/workdir ghcr.io/rosenpass/rosenpass \
gen-keys --public-key=workdir/client-public --secret-key=workdir/client-secret
# share the public keys between client and server
cp workdir-client/client-public workdir-server/client-public
cp workdir-server/server-public workdir-client/server-public
```
Start the server container:
```bash
docker run --name "rpserver" --network ${NET} \
-it --rm -v ./workdir-server:/workdir ghcr.io/rosenpass/rosenpass \
exchange \
private-key workdir/server-secret \
public-key workdir/server-public \
listen 0.0.0.0:9999 \
peer public-key workdir/client-public \
outfile workdir/server-sharedkey
```
Find out the ip address of the server container:
```bash
EP="rpserver"
EP=$(docker inspect --format '{{ .NetworkSettings.Networks.rp.IPAddress }}' $EP)
```
Run the client container and perform the key exchange:
```bash
docker run --name "rpclient" --network ${NET} \
-it --rm -v ./workdir-client:/workdir ghcr.io/rosenpass/rosenpass \
exchange \
private-key workdir/client-secret \
public-key workdir/client-public \
peer public-key workdir/server-public endpoint ${EP}:9999 \
outfile workdir/client-sharedkey
```
Now the containers will exchange shared keys and each put them into their respective outfile.
Comparing the outfiles shows that these shared keys equal:
```bash
cmp workdir-server/server-sharedkey workdir-client/client-sharedkey
```
It is now possible to set add these keys as pre-shared keys within a wireguard interface.
For example as the server,
```bash
PREKEY=$(cat workdir-server/server-sharedkey)
wg set <server-interface> peer <client-peer-public-key> preshared-key <(echo "$PREKEY")
```
## Usage - Combined with wireguard
The `ghcr.io/rosenpass/rp` image can be used to build a VPN with WireGuard and Rosenpass.
In this example, we run two containers on the same system and connect them with a bridge network within the docker overlay network.
Create the named docker network, to be able to connect the containers.
Create a docker network that is used to connect the containers:
```bash
docker network create -d bridge rp
export NET=rp
```
Generate the server and client secret keys and extract public keys.
```bash
mkdir -p ./workdir-server ./workdir-client
# server
docker run -it --rm -v ./workdir-server:/workdir ghcr.io/rosenpass/rp \
genkey workdir/server.rosenpass-secret
docker run -it --rm -v ./workdir-server:/workdir ghcr.io/rosenpass/rp \
pubkey workdir/server.rosenpass-secret workdir/server.rosenpass-public
# client
docker run -it --rm -v ./workdir-client:/workdir ghcr.io/rosenpass/rp \
genkey workdir/client.rosenpass-secret
docker run -it --rm -v ./workdir-client:/workdir ghcr.io/rosenpass/rp \
pubkey workdir/client.rosenpass-secret workdir/client.rosenpass-public
# share the public keys between client and server
cp -r workdir-client/client.rosenpass-public workdir-server/client.rosenpass-public
cp -r workdir-server/server.rosenpass-public workdir-client/server.rosenpass-public
```
Start the server container.
Note that the `NET_ADMIN` capability is neccessary, the rp command will create and manage wireguard interfaces.
Also make sure the `wireguard` kernel module is loaded by the host. (`lsmod | grep wireguard`)
```bash
docker run --name "rpserver" --network ${NET} -it -d --rm -v ./workdir-server:/workdir \
--cap-add=NET_ADMIN \
ghcr.io/rosenpass/rp \
exchange workdir/server.rosenpass-secret dev rosenpass0 \
listen 0.0.0.0:9999 peer workdir/client.rosenpass-public allowed-ips 10.0.0.0/8
```
Now find out the ip-address of the server container and then start the client container:
```bash
EP="rpserver"
EP=$(docker inspect --format '{{ .NetworkSettings.Networks.rp.IPAddress }}' $EP)
docker run --name "rpclient" --network ${NET} -it -d --rm -v ./workdir-client:/workdir \
--cap-add=NET_ADMIN \
ghcr.io/rosenpass/rp \
exchange workdir/client.rosenpass-secret dev rosenpass1 \
peer workdir/server.rosenpass-public endpoint ${EP}:9999 allowed-ips 10.0.0.1
```
Inside the docker containers assign the IP addresses:
```bash
# server
docker exec -it rpserver ip a add 10.0.0.1/24 dev rosenpass0
# client
docker exec -it rpclient ip a add 10.0.0.2/24 dev rosenpass1
```
Done! The two containers should now be connected through a wireguard VPN (Port 1000) with pre-shared keys exchanged by rosenpass (Port 9999).
Now, test the connection by starting a shell inside the client container, and ping the server through the VPN:
```bash
# client
docker exec -it rpclient bash
apt update; apt install iputils-ping
ping 10.0.0.1
```
The ping command should continuously show ping-logs:
```
PING 10.0.0.1 (10.0.0.1) 56(84) bytes of data.
64 bytes from 10.0.0.1: icmp_seq=1 ttl=64 time=0.119 ms
64 bytes from 10.0.0.1: icmp_seq=2 ttl=64 time=0.132 ms
64 bytes from 10.0.0.1: icmp_seq=3 ttl=64 time=0.394 ms
...
```
While the ping is running, you may stop the server container, and verify that the ping-log halts. In another terminal do:
```
docker stop -t 1 rpserver
```
## Building the Docker Images Locally
Clone the Rosenpass repository:
```
git clone https://github.com/rosenpass/rosenpass
cd rosenpass
```
Build the rp image from the root of the repository as follows:
```
docker build -f docker/Dockerfile -t ghcr.io/rosenpass/rp --target rp .
```
Build the rosenpass image from the root of the repostiry with the following command:
```
docker build -f docker/Dockerfile -t ghcr.io/rosenpass/rosenpass --target rosenpass .
```

212
flake.lock generated
View File

@@ -1,5 +1,26 @@
{
"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"
@@ -18,65 +39,6 @@
"type": "github"
}
},
"flake-utils_2": {
"inputs": {
"systems": "systems_2"
},
"locked": {
"lastModified": 1726560853,
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"type": "github"
}
},
"nix-vm-test": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1734355073,
"narHash": "sha256-FfdPOGy1zElTwKzjgIMp5K2D3gfPn6VWjVa4MJ9L1Tc=",
"owner": "numtide",
"repo": "nix-vm-test",
"rev": "5948de39a616f2261dbbf4b6f25cbe1cbefd788c",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "nix-vm-test",
"type": "github"
}
},
"nix-vm-test_2": {
"inputs": {
"nixpkgs": [
"rosenpassOld",
"nixpkgs"
]
},
"locked": {
"lastModified": 1734355073,
"narHash": "sha256-FfdPOGy1zElTwKzjgIMp5K2D3gfPn6VWjVa4MJ9L1Tc=",
"owner": "numtide",
"repo": "nix-vm-test",
"rev": "5948de39a616f2261dbbf4b6f25cbe1cbefd788c",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "nix-vm-test",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1728193676,
@@ -95,77 +57,25 @@
},
"root": {
"inputs": {
"fenix": "fenix",
"flake-utils": "flake-utils",
"nix-vm-test": "nix-vm-test",
"nixpkgs": "nixpkgs",
"rosenpassOld": "rosenpassOld",
"rust-overlay": "rust-overlay_2",
"treefmt-nix": "treefmt-nix_2"
"nixpkgs": "nixpkgs"
}
},
"rosenpassOld": {
"inputs": {
"flake-utils": "flake-utils_2",
"nix-vm-test": "nix-vm-test_2",
"nixpkgs": [
"nixpkgs"
],
"rust-overlay": "rust-overlay",
"treefmt-nix": "treefmt-nix"
},
"rust-analyzer-src": {
"flake": false,
"locked": {
"lastModified": 1754748821,
"narHash": "sha256-mMggTZDC97lLvKNOLtDz3GBjjxXFD++e1s0RZsVH/vI=",
"owner": "rosenpass",
"repo": "rosenpass",
"rev": "916a9ebb7133f0b22057fb097a473217f261928a",
"lastModified": 1728249780,
"narHash": "sha256-J269DvCI5dzBmPrXhAAtj566qt0b22TJtF3TIK+tMsI=",
"owner": "rust-lang",
"repo": "rust-analyzer",
"rev": "2b750da1a1a2c1d2c70896108d7096089842d877",
"type": "github"
},
"original": {
"owner": "rosenpass",
"repo": "rosenpass",
"rev": "916a9ebb7133f0b22057fb097a473217f261928a",
"type": "github"
}
},
"rust-overlay": {
"inputs": {
"nixpkgs": [
"rosenpassOld",
"nixpkgs"
]
},
"locked": {
"lastModified": 1744513456,
"narHash": "sha256-NLVluTmK8d01Iz+WyarQhwFcXpHEwU7m5hH3YQQFJS0=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "730fd8e82799219754418483fabe1844262fd1e2",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"type": "github"
}
},
"rust-overlay_2": {
"inputs": {
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1744513456,
"narHash": "sha256-NLVluTmK8d01Iz+WyarQhwFcXpHEwU7m5hH3YQQFJS0=",
"owner": "oxalica",
"repo": "rust-overlay",
"rev": "730fd8e82799219754418483fabe1844262fd1e2",
"type": "github"
},
"original": {
"owner": "oxalica",
"repo": "rust-overlay",
"owner": "rust-lang",
"ref": "nightly",
"repo": "rust-analyzer",
"type": "github"
}
},
@@ -183,62 +93,6 @@
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"repo": "default",
"type": "github"
}
},
"treefmt-nix": {
"inputs": {
"nixpkgs": [
"rosenpassOld",
"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"
}
},
"treefmt-nix_2": {
"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",

313
flake.nix
View File

@@ -3,56 +3,37 @@
nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.05";
flake-utils.url = "github:numtide/flake-utils";
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";
# Older version of rosenpass, referenced here for backwards compatibility
rosenpassOld.url = "github:rosenpass/rosenpass?rev=916a9ebb7133f0b22057fb097a473217f261928a";
rosenpassOld.inputs.nixpkgs.follows = "nixpkgs";
fenix.url = "github:nix-community/fenix";
fenix.inputs.nixpkgs.follows = "nixpkgs";
};
outputs =
{
self,
nixpkgs,
flake-utils,
nix-vm-test,
rust-overlay,
treefmt-nix,
rosenpassOld,
...
}@inputs:
outputs = { self, nixpkgs, flake-utils, ... }@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 {
@@ -63,185 +44,115 @@
};
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"
"i686-linux"
]
(
system:
let
pkgs = import nixpkgs {
inherit system;
(flake-utils.lib.eachSystem [ "x86_64-linux" "aarch64-linux" ] (system:
let
pkgs = import nixpkgs {
inherit system;
overlays = [
# apply our own overlay, overriding/inserting our packages as defined in ./pkgs
self.overlays.default
# apply our own overlay, overriding/inserting our packages as defined in ./pkgs
overlays = [ self.overlays.default ];
};
in
{
nix-vm-test.overlays.default
#
### Reading materials ###
#
packages.whitepaper = pkgs.whitepaper;
# apply rust-overlay to get specific versions of the rust toolchain for a MSRV check
(import rust-overlay)
];
};
#
### Proof and Proof Tools ###
#
packages.proverif-patched = pkgs.proverif-patched;
packages.proof-proverif = pkgs.proof-proverif;
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;
};
#
### Reading materials ###
#
packages.whitepaper = pkgs.whitepaper;
#
### 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-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
];
};
#
### Proof and Proof Tools ###
#
packages.proverif-patched = pkgs.proverif-patched;
packages.proof-proverif = pkgs.proof-proverif;
#
### 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
];
};
# a devshell to hunt unsafe `unsafe` in the code
devShells.miri = pkgs.mkShell {
# inputsFrom = [ self.packages.${system}.rosenpass ];
nativeBuildInputs = with pkgs; [
((rust-bin.selectLatestNightlyWith (toolchain: toolchain.default)).override {
extensions = [
"rust-analysis"
"rust-src"
"miri-preview"
];
})
pkgs.cmake
pkgs.rustPlatform.bindgenHook
];
# Run this to find unsafe `unsafe`:
# MIRIFLAGS="-Zmiri-disable-isolation" cargo miri test --no-fail-fast --lib --bins --tests
#
# - Some test failure is expected.
};
checks = {
systemd-rosenpass = pkgs.testers.runNixOSTest ./tests/systemd/rosenpass.nix;
systemd-rp = pkgs.testers.runNixOSTest ./tests/systemd/rp.nix;
checks =
import ./tests/integration/integration-checks.nix {
inherit system;
pkgs = inputs.nixpkgs;
lib = nixpkgs.lib;
rosenpassNew = self.packages.${system}.default;
rosenpassOld = rosenpassOld.packages.${system}.default;
}
// {
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;
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
'';
};
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;
}
)
)
formatter = pkgs.nixpkgs-fmt;
}))
];
}

View File

@@ -3,10 +3,9 @@ name = "rosenpass-fuzzing"
version = "0.0.1"
publish = false
edition = "2021"
rust-version = "1.77.0"
[features]
experiment_libcrux = ["rosenpass-ciphers/experiment_libcrux_all"]
experiment_libcrux = ["rosenpass-ciphers/experiment_libcrux"]
[package.metadata]
cargo-fuzz = true

View File

@@ -4,8 +4,7 @@ extern crate rosenpass;
use libfuzzer_sys::fuzz_target;
use rosenpass_cipher_traits::primitives::Aead as _;
use rosenpass_ciphers::Aead;
use rosenpass_ciphers::aead;
#[derive(arbitrary::Arbitrary, Debug)]
pub struct Input {
@@ -18,7 +17,7 @@ pub struct Input {
fuzz_target!(|input: Input| {
let mut ciphertext = vec![0u8; input.plaintext.len() + 16];
Aead.encrypt(
aead::encrypt(
ciphertext.as_mut_slice(),
&input.key,
&input.nonce,

View File

@@ -4,7 +4,6 @@ extern crate rosenpass;
use libfuzzer_sys::fuzz_target;
use rosenpass_cipher_traits::primitives::KeyedHashTo;
use rosenpass_ciphers::subtle::blake2b;
use rosenpass_to::To;
@@ -17,7 +16,5 @@ pub struct Blake2b {
fuzz_target!(|input: Blake2b| {
let mut out = [0u8; 32];
blake2b::Blake2b::keyed_hash_to(&input.key, &input.data)
.to(&mut out)
.unwrap();
blake2b::hash(&input.key, &input.data).to(&mut out).unwrap();
});

View File

@@ -4,8 +4,8 @@ extern crate rosenpass;
use libfuzzer_sys::fuzz_target;
use rosenpass::protocol::CryptoServer;
use rosenpass_cipher_traits::primitives::Kem;
use rosenpass_ciphers::StaticKem;
use rosenpass_cipher_traits::Kem;
use rosenpass_ciphers::kem::StaticKem;
use rosenpass_secret_memory::policy::*;
use rosenpass_secret_memory::{PublicBox, Secret};
use std::sync::Once;

View File

@@ -4,8 +4,8 @@ extern crate rosenpass;
use libfuzzer_sys::fuzz_target;
use rosenpass_cipher_traits::primitives::Kem;
use rosenpass_ciphers::EphemeralKem;
use rosenpass_cipher_traits::Kem;
use rosenpass_ciphers::kem::EphemeralKem;
#[derive(arbitrary::Arbitrary, Debug)]
pub struct Input {
@@ -16,7 +16,5 @@ fuzz_target!(|input: Input| {
let mut ciphertext = [0u8; EphemeralKem::CT_LEN];
let mut shared_secret = [0u8; EphemeralKem::SHK_LEN];
EphemeralKem
.encaps(&mut shared_secret, &mut ciphertext, &input.pk)
.unwrap();
EphemeralKem::encaps(&mut shared_secret, &mut ciphertext, &input.pk).unwrap();
});

View File

@@ -3,13 +3,13 @@ extern crate rosenpass;
use libfuzzer_sys::fuzz_target;
use rosenpass_cipher_traits::primitives::Kem;
use rosenpass_ciphers::StaticKem;
use rosenpass_cipher_traits::Kem;
use rosenpass_ciphers::kem::StaticKem;
fuzz_target!(|input: [u8; StaticKem::PK_LEN]| {
let mut ciphertext = [0u8; StaticKem::CT_LEN];
let mut shared_secret = [0u8; StaticKem::SHK_LEN];
// We expect errors while fuzzing therefore we do not check the result.
let _ = StaticKem.encaps(&mut shared_secret, &mut ciphertext, &input);
let _ = StaticKem::encaps(&mut shared_secret, &mut ciphertext, &input);
});

View File

@@ -8,7 +8,6 @@ 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 }

View File

@@ -2,10 +2,11 @@
/// Generate bindings to a liboqs-provided KEM
macro_rules! oqs_kem {
($name:ident, $algo_trait:path) => { ::paste::paste!{
($name:ident) => { ::paste::paste!{
#[doc = "Bindings for ::oqs_sys::kem::" [<"OQS_KEM" _ $name:snake>] "_*"]
mod [< $name:snake >] {
use rosenpass_cipher_traits::primitives::{Kem, KemError};
use rosenpass_cipher_traits::Kem;
use rosenpass_util::result::Guaranteed;
#[doc = "Bindings for ::oqs_sys::kem::" [<"OQS_KEM" _ $name:snake>] "_*"]
#[doc = ""]
@@ -13,7 +14,7 @@ macro_rules! oqs_kem {
#[doc = ""]
#[doc = "```rust"]
#[doc = "use std::borrow::{Borrow, BorrowMut};"]
#[doc = "use rosenpass_cipher_traits::primitives::Kem;"]
#[doc = "use rosenpass_cipher_traits::Kem;"]
#[doc = "use rosenpass_oqs::" $name:camel " as MyKem;"]
#[doc = "use rosenpass_secret_memory::{Secret, Public};"]
#[doc = ""]
@@ -22,26 +23,21 @@ macro_rules! oqs_kem {
#[doc = "// Recipient generates secret key, transfers pk to sender"]
#[doc = "let mut sk = Secret::<{ MyKem::SK_LEN }>::zero();"]
#[doc = "let mut pk = Public::<{ MyKem::PK_LEN }>::zero();"]
#[doc = "MyKem.keygen(sk.secret_mut(), &mut pk);"]
#[doc = "MyKem::keygen(sk.secret_mut(), pk.borrow_mut());"]
#[doc = ""]
#[doc = "// Sender generates ciphertext and local shared key, sends ciphertext to recipient"]
#[doc = "let mut shk_enc = Secret::<{ MyKem::SHK_LEN }>::zero();"]
#[doc = "let mut ct = Public::<{ MyKem::CT_LEN }>::zero();"]
#[doc = "MyKem.encaps(shk_enc.secret_mut(), &mut ct, &pk);"]
#[doc = "MyKem::encaps(shk_enc.secret_mut(), ct.borrow_mut(), pk.borrow());"]
#[doc = ""]
#[doc = "// Recipient decapsulates ciphertext"]
#[doc = "let mut shk_dec = Secret::<{ MyKem::SHK_LEN }>::zero();"]
#[doc = "MyKem.decaps(shk_dec.secret_mut(), sk.secret_mut(), &ct);"]
#[doc = "MyKem::decaps(shk_dec.secret_mut(), sk.secret(), ct.borrow());"]
#[doc = ""]
#[doc = "// Both parties end up with the same shared key"]
#[doc = "assert!(rosenpass_constant_time::compare(shk_enc.secret(), shk_dec.secret()) == 0);"]
#[doc = "assert!(rosenpass_constant_time::compare(shk_enc.secret_mut(), shk_dec.secret_mut()) == 0);"]
#[doc = "```"]
pub struct [< $name:camel >];
pub const SK_LEN: usize = ::oqs_sys::kem::[<OQS_KEM _ $name:snake _ length_secret_key >] as usize;
pub const PK_LEN: usize = ::oqs_sys::kem::[<OQS_KEM _ $name:snake _ length_public_key >] as usize;
pub const CT_LEN: usize = ::oqs_sys::kem::[<OQS_KEM _ $name:snake _ length_ciphertext >] as usize;
pub const SHK_LEN: usize = ::oqs_sys::kem::[<OQS_KEM _ $name:snake _ length_shared_secret >] as usize;
pub enum [< $name:camel >] {}
/// # Panic & Safety
///
@@ -55,8 +51,17 @@ macro_rules! oqs_kem {
/// to only check that the buffers are big enough, allowing them to be even
/// bigger. However, from a correctness point of view it does not make sense to
/// allow bigger buffers.
impl Kem<SK_LEN, PK_LEN, CT_LEN, SHK_LEN> for [< $name:camel >] {
fn keygen(&self, sk: &mut [u8; SK_LEN], pk: &mut [u8; PK_LEN]) -> Result<(), KemError> {
impl Kem for [< $name:camel >] {
type Error = ::std::convert::Infallible;
const SK_LEN: usize = ::oqs_sys::kem::[<OQS_KEM _ $name:snake _ length_secret_key >] as usize;
const PK_LEN: usize = ::oqs_sys::kem::[<OQS_KEM _ $name:snake _ length_public_key >] as usize;
const CT_LEN: usize = ::oqs_sys::kem::[<OQS_KEM _ $name:snake _ length_ciphertext >] as usize;
const SHK_LEN: usize = ::oqs_sys::kem::[<OQS_KEM _ $name:snake _ length_shared_secret >] as usize;
fn keygen(sk: &mut [u8], pk: &mut [u8]) -> Guaranteed<()> {
assert_eq!(sk.len(), Self::SK_LEN);
assert_eq!(pk.len(), Self::PK_LEN);
unsafe {
oqs_call!(
::oqs_sys::kem::[< OQS_KEM _ $name:snake _ keypair >],
@@ -68,7 +73,10 @@ macro_rules! oqs_kem {
Ok(())
}
fn encaps(&self, shk: &mut [u8; SHK_LEN], ct: &mut [u8; CT_LEN], pk: &[u8; PK_LEN]) -> Result<(), KemError> {
fn encaps(shk: &mut [u8], ct: &mut [u8], pk: &[u8]) -> Guaranteed<()> {
assert_eq!(shk.len(), Self::SHK_LEN);
assert_eq!(ct.len(), Self::CT_LEN);
assert_eq!(pk.len(), Self::PK_LEN);
unsafe {
oqs_call!(
::oqs_sys::kem::[< OQS_KEM _ $name:snake _ encaps >],
@@ -81,7 +89,10 @@ macro_rules! oqs_kem {
Ok(())
}
fn decaps(&self, shk: &mut [u8; SHK_LEN], sk: &[u8; SK_LEN], ct: &[u8; CT_LEN]) -> Result<(), KemError> {
fn decaps(shk: &mut [u8], sk: &[u8], ct: &[u8]) -> Guaranteed<()> {
assert_eq!(shk.len(), Self::SHK_LEN);
assert_eq!(sk.len(), Self::SK_LEN);
assert_eq!(ct.len(), Self::CT_LEN);
unsafe {
oqs_call!(
::oqs_sys::kem::[< OQS_KEM _ $name:snake _ decaps >],
@@ -94,16 +105,9 @@ macro_rules! oqs_kem {
Ok(())
}
}
}
impl Default for [< $name:camel >] {
fn default() -> Self {
Self
}
}
impl $algo_trait for [< $name:camel >] {}
pub use [< $name:snake >] :: [< $name:camel >];
}}
}

View File

@@ -22,8 +22,5 @@ macro_rules! oqs_call {
#[macro_use]
mod kem_macro;
oqs_kem!(kyber_512, rosenpass_cipher_traits::algorithms::KemKyber512);
oqs_kem!(
classic_mceliece_460896,
rosenpass_cipher_traits::algorithms::KemClassicMceliece460896
);
oqs_kem!(kyber_512);
oqs_kem!(classic_mceliece_460896);

View File

@@ -1,5 +1,6 @@
final: prev: {
#
### Actual rosenpass software ###
#
@@ -26,10 +27,7 @@ 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

Binary file not shown.

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 751 KiB

After

Width:  |  Height:  |  Size: 725 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 221 KiB

After

Width:  |  Height:  |  Size: 218 KiB

View File

@@ -0,0 +1,191 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 2037 1491" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.5;">
<g transform="matrix(0.958104,0,0,0.883458,-169.743,-156.518)">
<rect id="ArtBoard1" x="177.165" y="177.165" width="2125.98" height="1687.51" style="fill:none;"/>
<clipPath id="_clip1">
<rect id="ArtBoard11" serif:id="ArtBoard1" x="177.165" y="177.165" width="2125.98" height="1687.51"/>
</clipPath>
<g clip-path="url(#_clip1)">
<g transform="matrix(0.377816,0,0,0.318513,-62.5845,3.62207)">
<path d="M1608.99,599.153C1608.99,575.987 1594.37,557.179 1576.37,557.179L680.292,557.179C662.284,557.179 647.664,575.987 647.664,599.153L647.664,903.661C647.664,926.827 662.284,945.635 680.292,945.635L1576.37,945.635C1594.37,945.635 1608.99,926.827 1608.99,903.661L1608.99,599.153Z" style="fill:rgb(247,4,132);"/>
</g>
<g transform="matrix(1.11885,0,0,0.472336,1334.4,22.5297)">
<path d="M497.076,394.18L497.076,1793.56C497.076,1793.56 -810.094,1791.78 -810.094,1793.56L-810.094,2231.73L497.076,2231.73L497.076,3888.59" style="fill:none;stroke:rgb(255,166,48);stroke-width:15.37px;"/>
</g>
<g transform="matrix(1.10326,0,0,0.239529,-152.083,336.057)">
<g transform="matrix(0.946041,-0,-0,4.72559,298.433,-663.352)">
<path d="M1597.09,252.781L1609.59,265.281L1597.09,277.781" style="fill:none;stroke:rgb(247,4,132);stroke-width:8.33px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:10;"/>
<path d="M209.973,265.281L1609.59,265.281" style="fill:none;stroke:rgb(247,4,132);stroke-width:8.33px;stroke-linecap:round;stroke-dasharray:8.33,16.67,0,0;"/>
</g>
</g>
<g transform="matrix(0.54423,0,0,0.514519,523.603,90.8277)">
<path d="M1608.99,583.163C1608.99,568.822 1598.85,557.179 1586.34,557.179L670.315,557.179C657.814,557.179 647.664,568.822 647.664,583.163L647.664,919.651C647.664,933.992 657.814,945.635 670.315,945.635L1586.34,945.635C1598.85,945.635 1608.99,933.992 1608.99,919.651L1608.99,583.163Z" style="fill:rgb(247,4,132);"/>
<path d="M1624.98,583.163L1624.98,919.651C1624.98,944.11 1607.66,963.968 1586.34,963.968L670.315,963.968C648.993,963.968 631.682,944.11 631.682,919.651L631.682,583.163C631.682,558.704 648.993,538.846 670.315,538.846L1586.34,538.846C1607.66,538.846 1624.98,558.704 1624.98,583.163ZM1608.99,583.163C1608.99,568.822 1598.85,557.179 1586.34,557.179L670.315,557.179C657.814,557.179 647.664,568.822 647.664,583.163L647.664,919.651C647.664,933.992 657.814,945.635 670.315,945.635L1586.34,945.635C1598.85,945.635 1608.99,933.992 1608.99,919.651L1608.99,583.163Z" style="fill:white;"/>
</g>
<g transform="matrix(1.04373,0,0,1.13192,-323.596,-1172.27)">
<g transform="matrix(50,0,0,50,1497.15,1475.25)">
</g>
<text x="1302.95px" y="1475.25px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:50px;">InitHell<tspan x="1469.15px " y="1475.25px ">o</tspan></text>
</g>
<g transform="matrix(1.10157,0,0,0.239529,-151.245,1006.25)">
<g transform="matrix(0.947489,-0,-0,4.72559,298.129,-3461.31)">
<path d="M1597.09,844.867L1609.59,857.367L1597.09,869.867" style="fill:none;stroke:rgb(247,4,132);stroke-width:8.33px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:10;"/>
<path d="M209.973,857.367L1609.59,857.367" style="fill:none;stroke:rgb(247,4,132);stroke-width:8.33px;stroke-linecap:round;stroke-dasharray:8.33,16.67,0,0;"/>
</g>
</g>
<g transform="matrix(0.54423,0,0,0.514519,523.603,752.344)">
<path d="M1608.99,583.163C1608.99,568.822 1598.85,557.179 1586.34,557.179L670.315,557.179C657.814,557.179 647.664,568.822 647.664,583.163L647.664,919.651C647.664,933.992 657.814,945.635 670.315,945.635L1586.34,945.635C1598.85,945.635 1608.99,933.992 1608.99,919.651L1608.99,583.163Z" style="fill:rgb(247,4,132);"/>
<path d="M1624.98,583.163L1624.98,919.651C1624.98,944.11 1607.66,963.968 1586.34,963.968L670.315,963.968C648.993,963.968 631.682,944.11 631.682,919.651L631.682,583.163C631.682,558.704 648.993,538.846 670.315,538.846L1586.34,538.846C1607.66,538.846 1624.98,558.704 1624.98,583.163ZM1608.99,583.163C1608.99,568.822 1598.85,557.179 1586.34,557.179L670.315,557.179C657.814,557.179 647.664,568.822 647.664,583.163L647.664,919.651C647.664,933.992 657.814,945.635 670.315,945.635L1586.34,945.635C1598.85,945.635 1608.99,933.992 1608.99,919.651L1608.99,583.163Z" style="fill:white;"/>
</g>
<g transform="matrix(0.19416,0,0,0.275328,1052.99,940.806)">
<path d="M1608.99,571.746C1608.99,563.706 1600.46,557.179 1589.95,557.179L666.712,557.179C656.199,557.179 647.664,563.706 647.664,571.746L647.664,931.068C647.664,939.108 656.199,945.635 666.712,945.635L1589.95,945.635C1600.46,945.635 1608.99,939.108 1608.99,931.068L1608.99,571.746Z" style="fill:rgb(255,211,152);stroke:white;stroke-width:19.24px;stroke-linecap:round;"/>
</g>
<g transform="matrix(1.04373,0,0,1.13192,-345.04,-502.074)">
<g transform="matrix(50,0,0,50,1404.28,1475.25)">
</g>
<text x="1227.23px" y="1475.25px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:50px;">InitC<tspan x="1330.68px " y="1475.25px ">o</tspan>nf</text>
</g>
<g transform="matrix(1.04373,0,0,1.13192,-34.3588,-501.229)">
<g transform="matrix(41.6667,0,0,41.6667,1315.29,1464.53)">
</g>
<text x="1188.09px" y="1464.53px" style="font-family:'Nunito-SemiBold', 'Nunito';font-weight:600;font-size:41.667px;">Biscuit</text>
</g>
<g transform="matrix(8.61155e-18,1.13192,-0.0754413,3.71795e-17,1069.8,-342.031)">
<path d="M497.076,394.18L497.076,1793.56" style="fill:none;stroke:rgb(247,4,132);stroke-width:17.63px;"/>
</g>
<g transform="matrix(8.61155e-18,1.13192,-0.0754413,3.71795e-17,1069.8,-288.169)">
<path d="M497.076,394.18L497.076,1793.56" style="fill:none;stroke:rgb(255,166,48);stroke-width:17.63px;"/>
</g>
<g transform="matrix(1.10808,0,0,1.04133,-187.35,-115.819)">
<path d="M497.076,394.18L497.076,1896.68" style="fill:none;stroke:rgb(247,4,132);stroke-width:12.58px;"/>
</g>
<g transform="matrix(-1.09658,0,0,0.321304,2399.88,618.547)">
<g transform="matrix(-0.9518,0,0,3.52288,2026.95,-1373.72)">
<path d="M220.225,569.992L207.725,557.492L220.225,544.992" style="fill:none;stroke:rgb(255,166,48);stroke-width:8.33px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:10;"/>
<path d="M1607.34,557.492L207.725,557.492" style="fill:none;stroke:rgb(255,166,48);stroke-width:8.33px;stroke-linecap:round;stroke-dasharray:8.33,16.67,0,0;"/>
</g>
</g>
<g transform="matrix(0.54423,0,0,0.514519,523.603,421.586)">
<path d="M1608.99,583.163C1608.99,568.822 1598.85,557.179 1586.34,557.179L670.315,557.179C657.814,557.179 647.664,568.822 647.664,583.163L647.664,919.651C647.664,933.992 657.814,945.635 670.315,945.635L1586.34,945.635C1598.85,945.635 1608.99,933.992 1608.99,919.651L1608.99,583.163Z" style="fill:rgb(255,166,48);"/>
<path d="M1624.98,583.163L1624.98,919.651C1624.98,944.11 1607.66,963.968 1586.34,963.968L670.315,963.968C648.993,963.968 631.682,944.11 631.682,919.651L631.682,583.163C631.682,558.704 648.993,538.846 670.315,538.846L1586.34,538.846C1607.66,538.846 1624.98,558.704 1624.98,583.163ZM1608.99,583.163C1608.99,568.822 1598.85,557.179 1586.34,557.179L670.315,557.179C657.814,557.179 647.664,568.822 647.664,583.163L647.664,919.651C647.664,933.992 657.814,945.635 670.315,945.635L1586.34,945.635C1598.85,945.635 1608.99,933.992 1608.99,919.651L1608.99,583.163Z" style="fill:white;"/>
</g>
<g transform="matrix(0.19416,0,0,0.275328,1052.99,601.372)">
<path d="M1608.99,571.746C1608.99,563.706 1600.46,557.179 1589.95,557.179L666.712,557.179C656.199,557.179 647.664,563.706 647.664,571.746L647.664,931.068C647.664,939.108 656.199,945.635 666.712,945.635L1589.95,945.635C1600.46,945.635 1608.99,939.108 1608.99,931.068L1608.99,571.746Z" style="fill:rgb(255,211,152);stroke:white;stroke-width:19.24px;stroke-linecap:round;"/>
</g>
<g transform="matrix(1.04373,0,0,1.13192,-345.04,-841.508)">
<g transform="matrix(50,0,0,50,1433.76,1475.25)">
</g>
<text x="1197.76px" y="1475.25px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:50px;">R<tspan x="1230.81px " y="1475.25px ">e</tspan>spHell<tspan x="1405.76px " y="1475.25px ">o</tspan></text>
</g>
<g transform="matrix(1.04373,0,0,1.13192,-34.3588,-841.794)">
<g transform="matrix(41.6667,0,0,41.6667,1315.29,1464.53)">
</g>
<text x="1188.09px" y="1464.53px" style="font-family:'Nunito-SemiBold', 'Nunito';font-weight:600;font-size:41.667px;">Biscuit</text>
</g>
<g transform="matrix(-1.10076,0,0,0.321304,2401.96,1404.06)">
<g transform="matrix(-0.94819,0,0,3.52288,2021.14,-3818.47)">
<path d="M220.225,1263.96L207.725,1251.46L220.225,1238.96" style="fill:none;stroke:rgb(255,166,48);stroke-width:8.33px;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:10;"/>
<path d="M1607.34,1251.46L207.725,1251.46" style="fill:none;stroke:rgb(255,166,48);stroke-width:8.33px;stroke-linecap:round;stroke-dasharray:8.33,16.67,0,0;"/>
</g>
</g>
<g transform="matrix(0.54423,0,0,0.514519,523.603,1207.09)">
<path d="M1608.99,583.163C1608.99,568.822 1598.85,557.179 1586.34,557.179L670.315,557.179C657.814,557.179 647.664,568.822 647.664,583.163L647.664,919.651C647.664,933.992 657.814,945.635 670.315,945.635L1586.34,945.635C1598.85,945.635 1608.99,933.992 1608.99,919.651L1608.99,583.163Z" style="fill:rgb(255,166,48);"/>
<path d="M1624.98,583.163L1624.98,919.651C1624.98,944.11 1607.66,963.968 1586.34,963.968L670.315,963.968C648.993,963.968 631.682,944.11 631.682,919.651L631.682,583.163C631.682,558.704 648.993,538.846 670.315,538.846L1586.34,538.846C1607.66,538.846 1624.98,558.704 1624.98,583.163ZM1608.99,583.163C1608.99,568.822 1598.85,557.179 1586.34,557.179L670.315,557.179C657.814,557.179 647.664,568.822 647.664,583.163L647.664,919.651C647.664,933.992 657.814,945.635 670.315,945.635L1586.34,945.635C1598.85,945.635 1608.99,933.992 1608.99,919.651L1608.99,583.163Z" style="fill:white;"/>
</g>
<g transform="matrix(1.04373,0,0,1.13192,-323.596,-115.707)">
<g transform="matrix(50,0,0,50,1528.5,1528)">
</g>
<text x="1274.4px" y="1528px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:50px;">Emp<tspan x="1375.85px 1394.1px " y="1528px 1528px ">ty</tspan>Data</text>
</g>
<g transform="matrix(1.16933e-17,1.13192,-0.102439,3.71795e-17,1384.12,272.481)">
<path d="M497.076,394.18L497.076,1793.56" style="fill:none;stroke:rgb(255,166,48);stroke-width:17.59px;stroke-linecap:round;"/>
</g>
<g transform="matrix(1.16933e-17,1.13192,-0.102439,3.71795e-17,1384.12,612.276)">
<path d="M497.076,394.18L497.076,1793.56" style="fill:none;stroke:rgb(255,166,48);stroke-width:17.59px;stroke-linecap:round;"/>
</g>
<g transform="matrix(0.377816,0,0,0.318513,1464.43,3.62207)">
<path d="M1608.99,599.153C1608.99,575.987 1594.37,557.179 1576.37,557.179L680.292,557.179C662.284,557.179 647.664,575.987 647.664,599.153L647.664,903.661C647.664,926.827 662.284,945.635 680.292,945.635L1576.37,945.635C1594.37,945.635 1608.99,926.827 1608.99,903.661L1608.99,599.153Z" style="fill:rgb(255,166,48);"/>
</g>
<g transform="matrix(1.04373,2.9937e-16,-2.74652e-16,1.13192,767.205,-815.996)">
<text x="1171.58px" y="1474.94px" style="font-family:'Nunito-Light', 'Nunito';font-weight:300;font-size:41.667px;fill:rgb(64,63,73);">r<tspan x="1185.58px " y="1474.94px ">e</tspan>sponder</text>
<g transform="matrix(41.6667,0,0,41.6667,1432.53,1516.61)">
</g>
<text x="1171.58px" y="1516.61px" style="font-family:'Nunito-Light', 'Nunito';font-weight:300;font-size:41.667px;fill:rgb(64,63,73);">aut<tspan x="1230.45px " y="1516.61px ">h</tspan>ent<tspan x="1313.16px 1322.41px 1341.33px 1363.08px 1377.16px " y="1516.61px 1516.61px 1516.61px 1516.61px 1516.61px ">icati</tspan>on</text>
</g>
<g transform="matrix(1.04373,1.80409e-17,1.85964e-17,1.13192,767.205,-611.456)">
<text x="1171.58px" y="1454.11px" style="font-family:'Nunito-Light', 'Nunito';font-weight:300;font-size:41.667px;fill:rgb(64,63,73);">init<tspan x="1227.49px " y="1454.11px ">i</tspan>at<tspan x="1272.24px " y="1454.11px ">o</tspan>r</text>
<text x="1171.58px" y="1495.78px" style="font-family:'Nunito-Light', 'Nunito';font-weight:300;font-size:41.667px;fill:rgb(64,63,73);">aut<tspan x="1230.45px " y="1495.78px ">h</tspan>ent<tspan x="1313.16px 1322.41px 1341.33px 1363.08px 1377.16px " y="1495.78px 1495.78px 1495.78px 1495.78px 1495.78px ">icati</tspan>on,</text>
<g transform="matrix(41.6667,0,0,41.6667,1464.49,1537.44)">
</g>
<text x="1171.58px" y="1537.44px" style="font-family:'Nunito-Light', 'Nunito';font-weight:300;font-size:41.667px;fill:rgb(64,63,73);">f<tspan x="1184.24px 1207.03px 1222.53px 1256.91px 1278.66px 1292.66px " y="1537.44px 1537.44px 1537.44px 1537.44px 1537.44px 1537.44px ">orward</tspan> secr<tspan x="1402.12px " y="1537.44px ">e</tspan>cy</text>
</g>
<g transform="matrix(1.04373,1.80409e-17,1.85964e-17,1.13192,705.967,-92.9691)">
<text x="1171.58px" y="1474.94px" style="font-family:'Nunito-Light', 'Nunito';font-weight:300;font-size:41.667px;fill:rgb(64,63,73);">ackno<tspan x="1278.49px 1313.28px 1324.95px " y="1474.94px 1474.94px 1474.94px ">wle</tspan>dges</text>
<g transform="matrix(41.6667,0,0,41.6667,1314.2,1516.61)">
</g>
<text x="1171.58px" y="1516.61px" style="font-family:'Nunito-Light', 'Nunito';font-weight:300;font-size:41.667px;fill:rgb(64,63,73);">InitC<tspan x="1254.78px " y="1516.61px ">o</tspan>nf</text>
</g>
<g transform="matrix(1.04373,1.72621e-17,1.94353e-17,1.13192,767.205,-321.469)">
<text x="1171.58px" y="1472.39px" style="font-family:'Nunito-Light', 'Nunito';font-weight:300;font-size:41.667px;fill:rgb(64,63,73);">OSK handed</text>
<g transform="matrix(41.6667,0,0,41.6667,1422.78,1514.06)">
</g>
<text x="1171.58px" y="1514.06px" style="font-family:'Nunito-Light', 'Nunito';font-weight:300;font-size:41.667px;fill:rgb(64,63,73);">t<tspan x="1185.33px " y="1514.06px ">o</tspan> W<tspan x="1264.74px 1273.99px 1287.99px " y="1514.06px 1514.06px 1514.06px ">ire</tspan>Guar<tspan x="1398.83px " y="1514.06px ">d</tspan></text>
</g>
<g transform="matrix(1.04373,0,0,1.13192,-159.675,-1425.03)">
<g transform="matrix(33.3333,0,0,33.3333,1376.21,1461.44)">
</g>
<text x="1171.58px" y="1461.44px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:33.333px;fill:rgb(64,63,73);">Init<tspan x="1219.48px " y="1461.44px ">i</tspan>at<tspan x="1256.91px " y="1461.44px ">o</tspan>r Stat<tspan x="1358.41px " y="1461.44px ">e</tspan></text>
</g>
<g transform="matrix(1.04373,0,0,1.13192,-159.675,-1369.01)">
<g transform="matrix(33.3333,0,0,33.3333,1422.81,1461.44)">
</g>
<text x="1171.58px" y="1461.44px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:33.333px;fill:rgb(64,63,73);">R<tspan x="1193.61px " y="1461.44px ">e</tspan>sponder Stat<tspan x="1405.01px " y="1461.44px ">e</tspan></text>
</g>
<g transform="matrix(1.04373,0,0,1.13192,-1040.69,-1406.95)">
<g transform="matrix(50,0,0,50,1434.05,1476.14)">
</g>
<text x="1257.1px" y="1476.14px" style="font-family:'Nunito-SemiBold', 'Nunito';font-weight:600;font-size:50px;fill:white;">Init<tspan x="1330.14px " y="1476.14px ">i</tspan>at<tspan x="1387.14px " y="1476.14px ">o</tspan>r</text>
</g>
<g transform="matrix(1.04373,0,0,1.13192,486.326,-1406.95)">
<g transform="matrix(50,0,0,50,1468.55,1476.14)">
</g>
<text x="1222.6px" y="1476.14px" style="font-family:'Nunito-SemiBold', 'Nunito';font-weight:600;font-size:50px;fill:white;">R<tspan x="1255.85px " y="1476.14px ">e</tspan>sponder</text>
</g>
<g transform="matrix(1.29981,-1.40964,1.29981,1.40964,-996.095,-284.091)">
<path d="M735.267,1542.91L717.276,1524.92L711.619,1548.57L735.267,1542.91Z" style="fill:rgb(179,178,182);"/>
<path d="M736.092,1546.36L712.445,1552.02L708.168,1547.74L713.825,1524.09L719.785,1522.41L737.776,1540.4L736.092,1546.36ZM735.267,1542.91L717.276,1524.92L711.619,1548.57L735.267,1542.91Z" style="fill:white;"/>
</g>
<g transform="matrix(1.29981,-1.40964,1.29981,1.40964,-996.095,-79.5508)">
<path d="M735.267,1542.91L717.276,1524.92L711.619,1548.57L735.267,1542.91Z" style="fill:rgb(179,178,182);"/>
<path d="M736.092,1546.36L712.445,1552.02L708.168,1547.74L713.825,1524.09L719.785,1522.41L737.776,1540.4L736.092,1546.36ZM735.267,1542.91L717.276,1524.92L711.619,1548.57L735.267,1542.91Z" style="fill:white;"/>
</g>
<g transform="matrix(1.29981,-1.40964,1.29981,1.40964,-996.095,207.55)">
<path d="M735.267,1542.91L717.276,1524.92L711.619,1548.57L735.267,1542.91Z" style="fill:rgb(179,178,182);"/>
<path d="M736.092,1546.36L712.445,1552.02L708.168,1547.74L713.825,1524.09L719.785,1522.41L737.776,1540.4L736.092,1546.36ZM735.267,1542.91L717.276,1524.92L711.619,1548.57L735.267,1542.91Z" style="fill:white;"/>
</g>
<g transform="matrix(1.04373,2.04033e-17,1.82707e-17,1.13192,287.154,-312.768)">
<g transform="matrix(41.6667,0,0,41.6667,1473.76,1457.69)">
</g>
<text x="1274.85px" y="1457.69px" style="font-family:'Nunito-Light', 'Nunito';font-weight:300;font-size:41.667px;fill:rgb(64,63,73);">handshak<tspan x="1451.8px " y="1457.69px ">e</tspan></text>
</g>
<g transform="matrix(1.04373,4.8711e-17,3.06091e-17,1.13192,312.355,-241.08)">
<g transform="matrix(41.6667,0,0,41.6667,1449.62,1457.69)">
</g>
<text x="1249.16px" y="1457.69px" style="font-family:'Nunito-Light', 'Nunito';font-weight:300;font-size:41.667px;fill:rgb(64,63,73);">l<tspan x="1262.7px 1273.62px 1296.24px 1319.87px 1332.03px 1357.66px 1382.66px 1406.07px 1427.66px " y="1457.69px 1457.69px 1457.69px 1457.69px 1457.69px 1457.69px 1457.69px 1457.69px 1457.69px ">ive phase</tspan></text>
</g>
<g transform="matrix(1.04373,0,0,1.24761,-135.752,-334.388)">
<g transform="matrix(1,-0,-0,0.90727,299.807,410.028)">
<path d="M1593.36,999.66L1602.74,980.91L1612.11,999.66C1607.42,994.973 1598.05,994.973 1593.36,999.66Z" style="fill:rgb(179,178,182);"/>
<path d="M1602.74,1027.14L1602.74,995.91" style="fill:none;stroke:rgb(179,178,182);stroke-width:6.25px;stroke-linecap:round;"/>
</g>
</g>
<g transform="matrix(-1.04373,1.52788e-16,-1.2782e-16,-1.24761,3835.73,3054.11)">
<g transform="matrix(-1,-1.22465e-16,1.11109e-16,-0.90727,3505.28,2305.97)">
<path d="M1612.11,1090.07L1602.74,1108.82L1593.36,1090.07C1598.05,1094.75 1607.42,1094.75 1612.11,1090.07Z" style="fill:rgb(179,178,182);"/>
<path d="M1602.74,1062.59L1602.74,1093.82" style="fill:none;stroke:rgb(179,178,182);stroke-width:6.25px;stroke-linecap:round;"/>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 134 KiB

After

Width:  |  Height:  |  Size: 138 KiB

View File

@@ -1,12 +1,15 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 2037 1491" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.5;">
<g id="ArtBoard1" transform="matrix(0.958104,0,0,0.883458,-169.743,-156.518)">
<rect x="177.165" y="177.165" width="2125.98" height="1687.51" style="fill:none;"/>
<g transform="matrix(0.958104,0,0,0.883458,-169.743,-156.518)">
<rect id="ArtBoard1" x="177.165" y="177.165" width="2125.98" height="1687.51" style="fill:none;"/>
<clipPath id="_clip1">
<rect x="177.165" y="177.165" width="2125.98" height="1687.51"/>
<rect id="ArtBoard11" serif:id="ArtBoard1" x="177.165" y="177.165" width="2125.98" height="1687.51"/>
</clipPath>
<g clip-path="url(#_clip1)">
<g transform="matrix(1.04373,0,0,1.13192,177.165,177.165)">
<rect x="-16.526" y="0" width="2083.17" height="1490.84" style="fill:white;"/>
</g>
<g transform="matrix(0.377816,0,0,0.318513,-62.5845,3.62207)">
<path d="M1608.99,599.153C1608.99,575.987 1594.37,557.179 1576.37,557.179L680.292,557.179C662.284,557.179 647.664,575.987 647.664,599.153L647.664,903.661C647.664,926.827 662.284,945.635 680.292,945.635L1576.37,945.635C1594.37,945.635 1608.99,926.827 1608.99,903.661L1608.99,599.153Z" style="fill:rgb(247,4,132);"/>
</g>

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 926 KiB

After

Width:  |  Height:  |  Size: 921 KiB

View File

@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 2990 2133" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;">
<g id="ArtBoard1" transform="matrix(1.0091,0,0,1.00305,-371.54,-177.706)">
<rect x="368.192" y="177.165" width="2962.52" height="2125.98" style="fill:none;"/>
<g transform="matrix(1.0091,0,0,1.00305,-371.54,-177.706)">
<rect id="ArtBoard1" x="368.192" y="177.165" width="2962.52" height="2125.98" style="fill:none;"/>
<clipPath id="_clip1">
<rect x="368.192" y="177.165" width="2962.52" height="2125.98"/>
<rect id="ArtBoard11" serif:id="ArtBoard1" x="368.192" y="177.165" width="2962.52" height="2125.98"/>
</clipPath>
<g clip-path="url(#_clip1)">
<g transform="matrix(0.990987,0,0,0.996959,368.192,177.165)">
@@ -70,6 +70,9 @@
<g transform="matrix(0.72523,0,0,0.837445,1933.65,1691.32)">
<path d="M1922.27,398.791C1922.27,390.83 1914.85,384.367 1905.72,384.367L363.747,384.367C354.61,384.367 347.192,390.83 347.192,398.791L347.192,427.639C347.192,435.599 354.61,442.062 363.747,442.062L1905.72,442.062C1914.85,442.062 1922.27,435.599 1922.27,427.639L1922.27,398.791Z" style="fill:rgb(253,180,218);fill-opacity:0.5;"/>
</g>
<g transform="matrix(1.1024,0,0,1.21164,9.17461,250.929)">
<rect x="347.192" y="384.367" width="1575.08" height="57.695" style="fill:rgb(253,180,218);"/>
</g>
<g transform="matrix(1.1024,0,0,1.20414,9.17461,982.985)">
<rect x="347.192" y="384.367" width="1575.08" height="57.695" style="fill:rgb(255,229,193);"/>
</g>
@@ -91,9 +94,6 @@
<g transform="matrix(1.1024,0,0,1.21164,9.17461,375.544)">
<rect x="347.192" y="384.367" width="1575.08" height="57.695" style="fill:rgb(253,180,218);"/>
</g>
<g transform="matrix(1.1024,0,0,1.21164,9.17461,251.722)">
<rect x="347.192" y="384.367" width="1575.08" height="57.695" style="fill:rgb(253,180,218);"/>
</g>
<g transform="matrix(1.1024,0,0,0.837445,9.17461,1264.69)">
<rect x="347.192" y="384.367" width="1575.08" height="57.695" style="fill:rgb(255,229,193);"/>
</g>
@@ -310,7 +310,7 @@
<g transform="matrix(0.990987,0,0,0.996959,400.873,805.267)">
<g transform="matrix(29.1667,0,0,29.1667,209.923,19.398)">
</g>
<text x="123.853px" y="19.398px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:29.167px;">pidi_<tspan x="185.89px " y="19.398px ">c</tspan>t</text>
<text x="142.169px" y="19.398px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:29.167px;">pidiC</text>
</g>
<g transform="matrix(0.990987,0,0,0.996959,556.294,805.267)">
<text x="63.967px" y="19.461px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:29.167px;"></text>
@@ -351,9 +351,9 @@
<text x="46.506px" y="26.764px" style="font-family:'Nunito-Light', 'Nunito';font-weight:300;font-size:29.167px;"><tspan x="46.506px " y="26.764px ">m</tspan>ix(sidi, epki)</text>
</g>
<g transform="matrix(0.990987,0,0,0.996959,1406.03,735.765)">
<g transform="matrix(29.1667,0,0,29.1667,595.391,26.2132)">
<g transform="matrix(29.1667,0,0,29.1667,595.77,26.2132)">
</g>
<text x="70.595px" y="26.213px" style="font-family:'Nunito-Light', 'Nunito';font-weight:300;font-size:29.167px;"><tspan x="70.595px " y="26.213px ">d</tspan>ec<tspan x="115.978px " y="26.213px ">a</tspan>ps<tspan x="161.77px 176.207px " y="26.213px 26.213px ">_a</tspan>nd_mix&lt;SKEM&gt;(sskr<tspan x="457.374px " y="26.213px ">,</tspan> spkr<tspan x="525.303px " y="26.213px ">,</tspan> sctr<tspan x="586.67px " y="26.213px ">)</tspan></text>
<text x="70.595px" y="26.213px" style="font-family:'Nunito-Light', 'Nunito';font-weight:300;font-size:29.167px;"><tspan x="70.595px " y="26.213px ">d</tspan>ec<tspan x="115.978px " y="26.213px ">a</tspan>ps<tspan x="161.77px 176.207px " y="26.213px 26.213px ">_a</tspan>nd_mix&lt;SKEM&gt;(sskr<tspan x="457.374px " y="26.213px ">,</tspan> spkr<tspan x="525.303px " y="26.213px ">,</tspan> ct1)</text>
</g>
<g transform="matrix(0.990987,0,0,0.996959,944.05,805.321)">
<g transform="matrix(29.1667,0,0,29.1667,492.12,19.3437)">
@@ -362,9 +362,9 @@
</g>
<g transform="matrix(0.990987,0,0,0.996959,1343.8,805.267)">
<text x="97.956px" y="19.461px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:29.167px;"></text>
<g transform="matrix(29.1667,0,0,29.1667,641.239,19.4608)">
<g transform="matrix(29.1667,0,0,29.1667,621.377,19.4608)">
</g>
<text x="133.389px" y="19.461px" style="font-family:'Nunito-Light', 'Nunito';font-weight:300;font-size:29.167px;"><tspan x="133.389px 141.556px " y="19.461px 19.461px ">lo</tspan>okup<tspan x="219.81px " y="19.461px ">_</tspan>peer(<tspan x="300.31px " y="19.461px ">d</tspan>ecr<tspan x="356.689px 371.535px 388.16px 398.281px 412.718px " y="19.461px 19.461px 19.461px 19.461px 19.461px ">ypt_a</tspan>nd_mix(pidi_<tspan x="590.956px 604.343px 616.448px " y="19.461px 19.461px 19.461px ">ct)</tspan>)</text>
<text x="133.389px" y="19.461px" style="font-family:'Nunito-Light', 'Nunito';font-weight:300;font-size:29.167px;"><tspan x="133.389px 141.556px " y="19.461px 19.461px ">lo</tspan>okup<tspan x="219.81px " y="19.461px ">_</tspan>peer(<tspan x="300.31px " y="19.461px ">d</tspan>ecr<tspan x="356.689px 371.535px 388.16px 398.281px 412.718px " y="19.461px 19.461px 19.461px 19.461px 19.461px ">ypt_a</tspan>nd_mix(pidiC))</text>
</g>
<g transform="matrix(0.990987,0,0,0.996959,1428.98,860.915)">
<g transform="matrix(29.1667,0,0,29.1667,234.685,25.593)">
@@ -720,9 +720,9 @@
<text x="85.515px" y="26.478px" style="font-family:'Nunito-Light', 'Nunito';font-weight:300;font-size:29.167px;"><tspan x="85.515px " y="26.478px ">d</tspan>ec<tspan x="130.898px " y="26.478px ">a</tspan>ps<tspan x="176.69px 191.127px " y="26.478px 26.478px ">_a</tspan>nd_mix&lt;SKEM&gt;(sski, spki, scti);</text>
</g>
<g transform="matrix(0.990987,0,0,0.996959,598.806,1534.07)">
<g transform="matrix(29.1667,0,0,29.1667,250.198,27.2845)">
<g transform="matrix(29.1667,0,0,29.1667,212.777,27.2845)">
</g>
<text x="56.502px" y="27.284px" style="font-family:'Nunito-Light', 'Nunito';font-weight:300;font-size:29.167px;"><tspan x="56.502px " y="27.284px ">m</tspan>ix(biscuit<tspan x="194.723px 208.635px 222.023px 234.127px " y="27.284px 27.284px 27.284px 27.284px ">_ct)</tspan></text>
<text x="56.502px" y="27.284px" style="font-family:'Nunito-Light', 'Nunito';font-weight:300;font-size:29.167px;"><tspan x="56.502px " y="27.284px ">m</tspan>ix(biscuit<tspan x="196.706px " y="27.284px ">)</tspan></text>
</g>
<g transform="matrix(0.990987,0,0,0.996959,589.076,1605.36)">
<g transform="matrix(29.1667,0,0,29.1667,370.179,15.7636)">
@@ -774,9 +774,9 @@
<text x="55.154px" y="28.384px" style="font-family:'Nunito-Light', 'Nunito';font-weight:300;font-size:29.167px;"><tspan x="55.154px 68.95px 78.575px 94.529px 104.329px " y="28.384px 28.384px 28.384px 28.384px 28.384px ">store</tspan>_biscuit(<tspan x="227.121px " y="28.384px ">)</tspan>;</text>
</g>
<g transform="matrix(0.990987,0,0,0.996959,1231.61,1534.18)">
<g transform="matrix(28.75,0,0,28.75,192.222,27.9976)">
<g transform="matrix(29.1667,0,0,29.1667,192.222,28.1459)">
</g>
<text x="70.034px" y="27.998px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:28.75px;">biscuit<tspan x="154.761px 168.532px " y="27.998px 27.998px ">_c</tspan>t</text>
<text x="106.705px" y="28.146px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:29.167px;">biscuit</text>
</g>
<g transform="matrix(0.990987,0,0,0.996959,1413.83,1606.73)">
<text x="27.294px" y="15.076px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:29.167px;"></text>
@@ -816,10 +816,10 @@
<text x="39.094px" y="15.047px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:29.167px;">biscuit<tspan x="125.049px " y="15.047px ">_</tspan>no</text>
</g>
<g transform="matrix(0.990987,0,0,0.996959,1414.45,1937)">
<text x="26.666px" y="15.72px" style="font-family:'Arial-BoldMT', 'Arial', sans-serif;font-weight:700;font-size:29.167px;"></text>
<g transform="matrix(29.1667,0,0,29.1667,356.978,15.7199)">
<text x="26.666px" y="15.727px" style="font-family:'ArialMT', 'Arial', sans-serif;font-size:29.167px;"></text>
<g transform="matrix(29.1667,0,0,29.1667,332.212,15.727)">
</g>
<text x="63.183px" y="15.72px" style="font-family:'Nunito-Light', 'Nunito';font-weight:300;font-size:29.167px;">l<tspan x="71.349px " y="15.72px ">o</tspan>ad_biscuit(biscuit<tspan x="308.853px 322.766px 336.153px 348.258px " y="15.72px 15.72px 15.72px 15.72px ">_ct)</tspan></text>
<text x="62.099px" y="15.727px" style="font-family:'Nunito-Light', 'Nunito';font-weight:300;font-size:29.167px;"><tspan x="62.099px 70.266px " y="15.727px 15.727px ">lo</tspan>ad_biscuit(biscuit<tspan x="309.753px " y="15.727px ">)</tspan>;</text>
</g>
<g transform="matrix(0.990987,0,0,0.996959,1420.02,1985.2)">
<g transform="matrix(29.1667,0,0,29.1667,408.55,14.2792)">
@@ -924,32 +924,32 @@
<path d="M25.178,1596.45L1770.22,1596.45" style="fill:none;stroke:rgb(247,4,132);stroke-width:8.33px;stroke-dasharray:8.33,16.67,0,0;"/>
</g>
</g>
<g transform="matrix(1.11927,0,0,0.265077,-31.9199,146.07)">
<path d="M1608.99,601.6C1608.99,577.084 1604.31,557.179 1598.54,557.179L658.122,557.179C652.35,557.179 647.664,577.084 647.664,601.6L647.664,901.214C647.664,925.73 652.35,945.635 658.122,945.635L1598.54,945.635C1604.31,945.635 1608.99,925.73 1608.99,901.214L1608.99,601.6Z" style="fill:rgb(247,4,132);"/>
<path d="M1616.37,601.6L1616.37,901.214C1616.37,943.028 1608.38,976.977 1598.54,976.977L658.122,976.977C648.278,976.977 640.286,943.028 640.286,901.214L640.286,601.6C640.286,559.786 648.278,525.837 658.122,525.837L1598.54,525.837C1608.38,525.837 1616.37,559.786 1616.37,601.6ZM1608.99,601.6C1608.99,577.084 1604.31,557.179 1598.54,557.179L658.122,557.179C652.35,557.179 647.664,577.084 647.664,601.6L647.664,901.214C647.664,925.73 652.35,945.635 658.122,945.635L1598.54,945.635C1604.31,945.635 1608.99,925.73 1608.99,901.214L1608.99,601.6Z" style="fill:white;"/>
<g transform="matrix(1.04736,0,0,0.265077,49.2217,146.07)">
<path d="M1608.99,601.6C1608.99,577.084 1603.99,557.179 1597.82,557.179L658.84,557.179C652.672,557.179 647.664,577.084 647.664,601.6L647.664,901.214C647.664,925.73 652.672,945.635 658.84,945.635L1597.82,945.635C1603.99,945.635 1608.99,925.73 1608.99,901.214L1608.99,601.6Z" style="fill:rgb(247,4,132);"/>
<path d="M1616.88,601.6L1616.88,901.214C1616.88,943.028 1608.34,976.977 1597.82,976.977L658.84,976.977C648.32,976.977 639.779,943.028 639.779,901.214L639.779,601.6C639.779,559.786 648.32,525.837 658.84,525.837L1597.82,525.837C1608.34,525.837 1616.88,559.786 1616.88,601.6ZM1608.99,601.6C1608.99,577.084 1603.99,557.179 1597.82,557.179L658.84,557.179C652.672,557.179 647.664,577.084 647.664,601.6L647.664,901.214C647.664,925.73 652.672,945.635 658.84,945.635L1597.82,945.635C1603.99,945.635 1608.99,925.73 1608.99,901.214L1608.99,601.6Z" style="fill:white;"/>
</g>
<g transform="matrix(1.11927,0,0,0.265077,-31.9199,912.386)">
<path d="M1608.99,601.6C1608.99,577.084 1604.31,557.179 1598.54,557.179L658.122,557.179C652.35,557.179 647.664,577.084 647.664,601.6L647.664,901.214C647.664,925.73 652.35,945.635 658.122,945.635L1598.54,945.635C1604.31,945.635 1608.99,925.73 1608.99,901.214L1608.99,601.6Z" style="fill:rgb(255,166,48);"/>
<path d="M1616.37,601.6L1616.37,901.214C1616.37,943.028 1608.38,976.977 1598.54,976.977L658.122,976.977C648.278,976.977 640.286,943.028 640.286,901.214L640.286,601.6C640.286,559.786 648.278,525.837 658.122,525.837L1598.54,525.837C1608.38,525.837 1616.37,559.786 1616.37,601.6ZM1608.99,601.6C1608.99,577.084 1604.31,557.179 1598.54,557.179L658.122,557.179C652.35,557.179 647.664,577.084 647.664,601.6L647.664,901.214C647.664,925.73 652.35,945.635 658.122,945.635L1598.54,945.635C1604.31,945.635 1608.99,925.73 1608.99,901.214L1608.99,601.6Z" style="fill:white;"/>
<g transform="matrix(1.04736,0,0,0.265077,49.2217,912.386)">
<path d="M1608.99,601.6C1608.99,577.084 1603.99,557.179 1597.82,557.179L658.84,557.179C652.672,557.179 647.664,577.084 647.664,601.6L647.664,901.214C647.664,925.73 652.672,945.635 658.84,945.635L1597.82,945.635C1603.99,945.635 1608.99,925.73 1608.99,901.214L1608.99,601.6Z" style="fill:rgb(255,166,48);"/>
<path d="M1616.88,601.6L1616.88,901.214C1616.88,943.028 1608.34,976.977 1597.82,976.977L658.84,976.977C648.32,976.977 639.779,943.028 639.779,901.214L639.779,601.6C639.779,559.786 648.32,525.837 658.84,525.837L1597.82,525.837C1608.34,525.837 1616.88,559.786 1616.88,601.6ZM1608.99,601.6C1608.99,577.084 1603.99,557.179 1597.82,557.179L658.84,557.179C652.672,557.179 647.664,577.084 647.664,601.6L647.664,901.214C647.664,925.73 652.672,945.635 658.84,945.635L1597.82,945.635C1603.99,945.635 1608.99,925.73 1608.99,901.214L1608.99,601.6Z" style="fill:white;"/>
</g>
<g transform="matrix(1.11927,0,0,0.265077,-31.9199,1569.58)">
<path d="M1608.99,601.6C1608.99,577.084 1604.31,557.179 1598.54,557.179L658.122,557.179C652.35,557.179 647.664,577.084 647.664,601.6L647.664,901.214C647.664,925.73 652.35,945.635 658.122,945.635L1598.54,945.635C1604.31,945.635 1608.99,925.73 1608.99,901.214L1608.99,601.6Z" style="fill:rgb(247,4,132);"/>
<path d="M1616.37,601.6L1616.37,901.214C1616.37,943.028 1608.38,976.977 1598.54,976.977L658.122,976.977C648.278,976.977 640.286,943.028 640.286,901.214L640.286,601.6C640.286,559.786 648.278,525.837 658.122,525.837L1598.54,525.837C1608.38,525.837 1616.37,559.786 1616.37,601.6ZM1608.99,601.6C1608.99,577.084 1604.31,557.179 1598.54,557.179L658.122,557.179C652.35,557.179 647.664,577.084 647.664,601.6L647.664,901.214C647.664,925.73 652.35,945.635 658.122,945.635L1598.54,945.635C1604.31,945.635 1608.99,925.73 1608.99,901.214L1608.99,601.6Z" style="fill:white;"/>
<g transform="matrix(1.04736,0,0,0.265077,49.2217,1569.58)">
<path d="M1608.99,601.6C1608.99,577.084 1603.99,557.179 1597.82,557.179L658.84,557.179C652.672,557.179 647.664,577.084 647.664,601.6L647.664,901.214C647.664,925.73 652.672,945.635 658.84,945.635L1597.82,945.635C1603.99,945.635 1608.99,925.73 1608.99,901.214L1608.99,601.6Z" style="fill:rgb(247,4,132);"/>
<path d="M1616.88,601.6L1616.88,901.214C1616.88,943.028 1608.34,976.977 1597.82,976.977L658.84,976.977C648.32,976.977 639.779,943.028 639.779,901.214L639.779,601.6C639.779,559.786 648.32,525.837 658.84,525.837L1597.82,525.837C1608.34,525.837 1616.88,559.786 1616.88,601.6ZM1608.99,601.6C1608.99,577.084 1603.99,557.179 1597.82,557.179L658.84,557.179C652.672,557.179 647.664,577.084 647.664,601.6L647.664,901.214C647.664,925.73 652.672,945.635 658.84,945.635L1597.82,945.635C1603.99,945.635 1608.99,925.73 1608.99,901.214L1608.99,601.6Z" style="fill:white;"/>
</g>
<g transform="matrix(0.990987,0,0,0.996959,-393.972,-1123.82)">
<g transform="matrix(50,0,0,50,2075.42,1491.35)">
<g transform="matrix(50,0,0,50,2059.59,1491.35)">
</g>
<text x="1204.07px" y="1491.35px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:50px;">InitHell<tspan x="1370.27px " y="1491.35px ">o</tspan> { sidi, epki, sctr<tspan x="1744.82px " y="1491.35px ">,</tspan> pidi_<tspan x="1875.87px 1899.17px 1917.82px " y="1491.35px 1491.35px 1491.35px ">ct,</tspan> aut<tspan x="2015.72px " y="1491.35px ">h</tspan> }</text>
<text x="1219.89px" y="1491.35px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:50px;">InitHell<tspan x="1386.09px " y="1491.35px ">o</tspan> { sidi, epki, sctr<tspan x="1760.64px " y="1491.35px ">,</tspan> pidiC<tspan x="1901.99px " y="1491.35px ">,</tspan> aut<tspan x="1999.89px " y="1491.35px ">h</tspan> }</text>
</g>
<g transform="matrix(0.990987,0,0,0.996959,-477.45,-357.502)">
<g transform="matrix(50,0,0,50,2231.1,1491.35)">
<g transform="matrix(0.990987,0,0,0.996959,-433.456,-357.502)">
<g transform="matrix(50,0,0,50,2155.26,1491.35)">
</g>
<text x="1216.85px" y="1491.35px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:50px;">R<tspan x="1248.9px 1274.6px 1297.75px 1326.1px 1363.3px 1389px 1403.05px 1416.85px 1443.85px 1455.9px 1472.95px 1485px 1508.15px 1519px 1547.35px 1563.5px 1574.15px 1586.2px 1609.35px 1620.2px 1648.55px 1659.4px 1670.05px 1682.1px 1707.8px 1730.1px 1747.4px 1758.25px 1768.9px 1780.95px 1804.1px 1826.4px 1843.7px 1854.55px 1865.2px 1877.25px 1905.6px 1916.45px 1939.6px 1961.85px 1989.1px 1999.95px 2017.6px 2040.55px 2062.85px 2080.5px 2091.15px 2103.2px 2128.85px 2156.1px 2173.4px 2201px 2213.05px " y="1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px ">espHello { sidr, sidi, ecti, scti, biscuit_ct, auth }</tspan></text>
<text x="1203.91px" y="1491.35px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:50px;">R<tspan x="1235.96px 1261.66px 1284.81px 1313.16px 1350.36px 1376.06px 1390.11px 1403.91px 1430.91px 1442.96px 1460.01px 1472.06px 1495.21px 1506.06px 1534.41px 1550.56px 1561.21px 1573.26px 1596.41px 1607.26px 1635.61px 1646.46px 1657.11px 1669.16px 1694.86px 1717.16px 1734.46px 1745.31px 1755.96px 1768.01px 1791.16px 1813.46px 1830.76px 1841.61px 1852.26px 1864.31px 1892.66px 1903.51px 1926.66px 1948.91px 1976.16px 1987.01px 2004.66px 2015.31px 2027.36px 2053.01px 2080.26px 2097.56px 2125.16px 2137.21px " y="1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px 1491.35px ">espHello { sidr, sidi, ecti, scti, biscuit, auth }</tspan></text>
</g>
<g transform="matrix(0.990987,0,0,0.996959,-393.972,299.694)">
<g transform="matrix(50,0,0,50,2053.37,1491.35)">
<g transform="matrix(50,0,0,50,2020.42,1491.35)">
</g>
<text x="1239.17px" y="1491.35px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:50px;">InitC<tspan x="1342.62px " y="1491.35px ">o</tspan>nf { sidi, sidr<tspan x="1644.77px " y="1491.35px ">,</tspan> biscuit<tspan x="1816.82px 1840.77px 1864.07px 1882.72px " y="1491.35px 1491.35px 1491.35px 1491.35px ">_ct,</tspan> aut<tspan x="1980.62px " y="1491.35px ">h</tspan> }</text>
<text x="1272.12px" y="1491.35px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:50px;">InitC<tspan x="1375.57px " y="1491.35px ">o</tspan>nf { sidi, sidr<tspan x="1677.72px " y="1491.35px ">,</tspan> biscuit<tspan x="1849.77px " y="1491.35px ">,</tspan> aut<tspan x="1947.67px " y="1491.35px ">h</tspan> }</text>
</g>
<g transform="matrix(0.990987,0,0,0.996959,467.587,-208.686)">
<circle cx="92.21" cy="555.627" r="46.396" style="fill:rgb(64,63,73);"/>

Before

Width:  |  Height:  |  Size: 100 KiB

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

View File

@@ -0,0 +1,393 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 1890 1086" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;">
<g transform="matrix(0.888676,0,0,0.801704,-157.443,-1585.2)">
<rect id="ArtBoard1" x="177.165" y="1977.29" width="2125.98" height="1353.42" style="fill:none;"/>
<g id="ArtBoard11" serif:id="ArtBoard1">
<g transform="matrix(1.12527,0,-3.46751e-33,1.24734,-109.061,-29.2601)">
<rect x="1454.89" y="2496.4" width="25.344" height="20.909" style="fill:rgb(212,226,247);"/>
<path d="M1484.4,2496.4L1484.4,2517.3C1484.4,2519.61 1482.53,2521.47 1480.23,2521.47L1454.89,2521.47C1452.59,2521.47 1450.72,2519.61 1450.72,2517.3L1450.72,2496.4C1450.72,2494.1 1452.59,2492.23 1454.89,2492.23L1480.23,2492.23C1482.53,2492.23 1484.4,2494.1 1484.4,2496.4ZM1480.23,2496.4L1454.89,2496.4L1454.89,2517.3L1480.23,2517.3L1480.23,2496.4Z" style="fill:rgb(212,226,247);"/>
</g>
<g transform="matrix(1.12527,0,-3.46751e-33,1.24734,-646.644,-769.875)">
<rect x="1454.89" y="2496.4" width="25.344" height="20.909" style="fill:rgb(212,226,247);"/>
<path d="M1484.4,2496.4L1484.4,2517.3C1484.4,2519.61 1482.53,2521.47 1480.23,2521.47L1454.89,2521.47C1452.59,2521.47 1450.72,2519.61 1450.72,2517.3L1450.72,2496.4C1450.72,2494.1 1452.59,2492.23 1454.89,2492.23L1480.23,2492.23C1482.53,2492.23 1484.4,2494.1 1484.4,2496.4ZM1480.23,2496.4L1454.89,2496.4L1454.89,2517.3L1480.23,2517.3L1480.23,2496.4Z" style="fill:rgb(212,226,247);"/>
</g>
<g transform="matrix(4.00596,0,-1.23443e-32,1.24734,-4842.07,-29.2601)">
<rect x="1454.89" y="2496.4" width="25.344" height="20.909" style="fill:rgb(212,226,247);"/>
<path d="M1481.4,2496.4L1481.4,2517.3C1481.4,2519.61 1480.88,2521.47 1480.23,2521.47L1454.89,2521.47C1454.24,2521.47 1453.72,2519.61 1453.72,2517.3L1453.72,2496.4C1453.72,2494.1 1454.24,2492.23 1454.89,2492.23L1480.23,2492.23C1480.88,2492.23 1481.4,2494.1 1481.4,2496.4ZM1480.23,2496.4L1454.89,2496.4L1454.89,2517.3L1480.23,2517.3L1480.23,2496.4Z" style="fill:rgb(212,226,247);"/>
</g>
<g transform="matrix(1.12527,0,-3.46751e-33,1.24734,-42.3997,-29.2601)">
<rect x="1454.89" y="2496.4" width="25.344" height="20.909" style="fill:rgb(198,198,201);"/>
<path d="M1484.4,2496.4L1484.4,2517.3C1484.4,2519.61 1482.53,2521.47 1480.23,2521.47L1454.89,2521.47C1452.59,2521.47 1450.72,2519.61 1450.72,2517.3L1450.72,2496.4C1450.72,2494.1 1452.59,2492.23 1454.89,2492.23L1480.23,2492.23C1482.53,2492.23 1484.4,2494.1 1484.4,2496.4ZM1480.23,2496.4L1454.89,2496.4L1454.89,2517.3L1480.23,2517.3L1480.23,2496.4Z" style="fill:rgb(198,198,201);"/>
</g>
<g transform="matrix(1.12527,0,-3.46751e-33,1.24734,-579.982,-769.875)">
<rect x="1454.89" y="2496.4" width="25.344" height="20.909" style="fill:rgb(198,198,201);"/>
<path d="M1484.4,2496.4L1484.4,2517.3C1484.4,2519.61 1482.53,2521.47 1480.23,2521.47L1454.89,2521.47C1452.59,2521.47 1450.72,2519.61 1450.72,2517.3L1450.72,2496.4C1450.72,2494.1 1452.59,2492.23 1454.89,2492.23L1480.23,2492.23C1482.53,2492.23 1484.4,2494.1 1484.4,2496.4ZM1480.23,2496.4L1454.89,2496.4L1454.89,2517.3L1480.23,2517.3L1480.23,2496.4Z" style="fill:rgb(198,198,201);"/>
</g>
<g transform="matrix(0.381932,0,0,1.66872,42.8569,1055.77)">
<path d="M1608.99,559.828C1608.99,558.366 1604.32,557.179 1598.56,557.179L658.104,557.179C652.342,557.179 647.664,558.366 647.664,559.828L647.664,942.986C647.664,944.448 652.342,945.635 658.104,945.635L1598.56,945.635C1604.32,945.635 1608.99,944.448 1608.99,942.986L1608.99,559.828Z" style="fill:none;stroke:rgb(64,63,73);stroke-width:8.54px;"/>
</g>
<g transform="matrix(0.319269,0,0,0.306737,111.831,2084.53)">
<path d="M1608.99,571.588C1608.99,563.635 1603.4,557.179 1596.51,557.179L660.153,557.179C653.26,557.179 647.664,563.635 647.664,571.588L647.664,931.226C647.664,939.179 653.26,945.635 660.153,945.635L1596.51,945.635C1603.4,945.635 1608.99,939.179 1608.99,931.226L1608.99,571.588Z" style="fill:white;"/>
</g>
<g transform="matrix(0.381932,0,0,0.364294,42.8569,1783.2)">
<rect x="647.664" y="557.179" width="961.33" height="388.456" style="fill:rgb(64,63,73);"/>
</g>
<g transform="matrix(1.12527,0,0,1.24734,-142.419,-742.377)">
<path d="M686.627,2406.91L686.627,2495.34C686.627,2499.6 683.172,2503.05 678.917,2503.05L413.249,2503.05C408.994,2503.05 405.539,2499.6 405.539,2495.34L405.539,2406.91C405.539,2402.65 408.994,2399.2 413.249,2399.2L678.917,2399.2C683.172,2399.2 686.627,2402.65 686.627,2406.91ZM413.872,2457.17L413.872,2494.72L678.293,2494.72L678.293,2457.17L413.872,2457.17Z" style="fill:rgb(179,178,182);"/>
<clipPath id="_clip1">
<path d="M686.627,2406.91L686.627,2495.34C686.627,2499.6 683.172,2503.05 678.917,2503.05L413.249,2503.05C408.994,2503.05 405.539,2499.6 405.539,2495.34L405.539,2406.91C405.539,2402.65 408.994,2399.2 413.249,2399.2L678.917,2399.2C683.172,2399.2 686.627,2402.65 686.627,2406.91ZM413.872,2457.17L413.872,2494.72L678.293,2494.72L678.293,2457.17L413.872,2457.17Z"/>
</clipPath>
<g clip-path="url(#_clip1)">
<g>
<g transform="matrix(0.707107,0.707107,-0.707107,0.707107,1731.31,392.021)">
<rect x="320.594" y="2142.43" width="296.282" height="308.698" style="fill:rgb(247,4,132);"/>
</g>
<g transform="matrix(0.707107,0.707107,-0.707107,0.707107,1939.29,599.998)">
<rect x="320.594" y="2142.43" width="296.282" height="308.698" style="fill:rgb(255,166,48);"/>
</g>
</g>
</g>
</g>
<g transform="matrix(1.12527,0,0,1.24734,-988.061,373.696)">
<text x="1171.58px" y="1445.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">t<tspan x="1183.44px " y="1445.64px ">y</tspan>pe</text>
<text x="1171.58px" y="1487.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;fill:rgb(160,159,164);">r<tspan x="1183.31px " y="1487.31px ">e</tspan>ser<tspan x="1247.74px 1264.68px " y="1487.31px 1487.31px ">ve</tspan>d</text>
<text x="1171.58px" y="1545.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">pa<tspan x="1208.51px 1225.64px 1235.34px " y="1545.64px 1545.64px 1545.64px ">ylo</tspan>ad</text>
<text x="1171.58px" y="1653.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">mac</text>
<g transform="matrix(33.3333,0,0,33.3333,1265.88,1695.64)">
</g>
<text x="1171.58px" y="1695.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">c<tspan x="1186.68px " y="1695.64px ">o</tspan>okie</text>
</g>
<g transform="matrix(1.12527,0,0,1.24734,-1032.48,373.696)">
<text x="1443.43px" y="1445.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">1</text>
<text x="1443.43px" y="1487.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">3</text>
<text x="1444.5px" y="1545.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">n</text>
<text x="1423.43px" y="1653.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">16</text>
<text x="1443.43px" y="1695.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">6</text>
<g transform="matrix(33.3333,0,0,33.3333,1463.43,1766.48)">
</g>
<text x="1213.53px" y="1766.48px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">en<tspan x="1250.03px 1266.96px 1284.7px 1294.4px " y="1766.48px 1766.48px 1766.48px 1766.48px ">velo</tspan>pe  n + 36</text>
</g>
<g transform="matrix(1.12527,0,0,1.24734,-1006.67,212.568)">
<text x="1228.7px" y="1470.55px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:41.667px;fill:white;">En<tspan x="1276.75px 1298px 1320.25px 1332.58px " y="1470.55px 1470.55px 1470.55px 1470.55px ">velo</tspan>pe</text>
<g transform="matrix(25,0,0,25,1459.75,1516.38)">
</g>
<text x="1398.3px" y="1516.38px" style="font-family:'Nunito-Regular', 'Nunito';font-size:25px;fill:white;">b<tspan x="1412.7px 1425.8px 1434.42px " y="1516.38px 1516.38px 1516.38px ">yte</tspan>s</text>
</g>
<g transform="matrix(0.597054,0,0,0.741612,65.5056,511.466)">
<path d="M432.703,2196.97L345.361,2196.97L345.361,2547.98L432.703,2547.98" style="fill:none;stroke:rgb(160,159,164);stroke-width:5.18px;"/>
</g>
<g transform="matrix(0.63007,0,0,0.90399,0.337587,154.729)">
<path d="M376.162,2196.97L345.361,2196.97L345.361,2544.77L513.459,2544.77" style="fill:none;stroke:rgb(160,159,164);stroke-width:4.5px;"/>
</g>
<g transform="matrix(4.69386e-17,-1.24734,1.12527,9.74939e-17,-2569.76,2501.33)">
<g transform="matrix(25,0,0,25,286.877,2518.25)">
</g>
<text x="82.852px" y="2518.25px" style="font-family:'Nunito-Regular', 'Nunito';font-size:25px;">M<tspan x="103.602px 120.902px 137.352px 147.927px 174.827px 180.627px 196.727px 210.927px 222.802px 240.427px 256.127px 268.652px " y="2518.25px 2518.25px 2518.25px 2518.25px 2518.25px 2518.25px 2518.25px 2518.25px 2518.25px 2518.25px 2518.25px 2518.25px ">AC_WIRE_DATA</tspan></text>
</g>
<g transform="matrix(4.35236e-17,-1.24734,1.12527,9.46525e-17,-2623.43,2555.42)">
<g transform="matrix(25,0,0,25,325.196,2518.25)">
</g>
<text x="87.896px" y="2518.25px" style="font-family:'Nunito-Regular', 'Nunito';font-size:25px;">C<tspan x="103.571px 122.121px 140.671px 155.671px 161.471px 175.671px 186.246px 213.146px 218.946px 235.046px 249.246px 261.121px 278.746px 294.446px 306.971px " y="2518.25px 2518.25px 2518.25px 2518.25px 2518.25px 2518.25px 2518.25px 2518.25px 2518.25px 2518.25px 2518.25px 2518.25px 2518.25px 2518.25px 2518.25px ">OOKIE_WIRE_DATA</tspan></text>
</g>
<g transform="matrix(0.986529,0,0,1.24734,-548.881,-459.807)">
<path d="M891.165,2388.54L1187.72,2388.54" style="fill:none;stroke:rgb(64,63,73);stroke-width:3.1px;"/>
</g>
<g transform="matrix(0.49129,0,0,1.66616,413.374,1057.2)">
<path d="M1608.99,559.832C1608.99,558.368 1605.36,557.179 1600.88,557.179L655.78,557.179C651.301,557.179 647.664,558.368 647.664,559.832L647.664,942.982C647.664,944.446 651.301,945.635 655.78,945.635L1600.88,945.635C1605.36,945.635 1608.99,944.446 1608.99,942.982L1608.99,559.832Z" style="fill:none;stroke:rgb(247,4,132);stroke-width:8.39px;"/>
</g>
<g transform="matrix(0.49129,0,0,0.365649,411.795,1781.92)">
<rect x="647.664" y="557.179" width="961.33" height="388.456" style="fill:rgb(247,4,132);"/>
</g>
<g transform="matrix(1.12527,0,0,1.24734,-536.656,211.942)">
<text x="1254.57px" y="1470.8px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:41.667px;">InitHell<tspan x="1393.07px " y="1470.8px ">o</tspan></text>
<g transform="matrix(25,0,0,25,1397.15,1512.47)">
</g>
<text x="1273.83px" y="1512.47px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:25px;fill:white;">t<tspan x="1282.95px " y="1512.47px ">y</tspan>pe=0x81</text>
</g>
<g transform="matrix(1.12527,0,0,1.24734,-550.023,408.588)">
<text x="1171.58px" y="1445.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">sidi</text>
<text x="1171.58px" y="1487.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">epki</text>
<text x="1171.58px" y="1528.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">sctr</text>
<text x="1171.58px" y="1570.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">peerid</text>
<text x="1171.58px" y="1612.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">aut<tspan x="1219.81px " y="1612.31px ">h</tspan></text>
</g>
<g transform="matrix(1.12527,0,0,1.24734,-505.817,408.588)">
<text x="1463.37px" y="1445.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">4</text>
<text x="1423.37px" y="1487.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">800</text>
<text x="1423.37px" y="1528.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">188</text>
<text x="1327.57px" y="1570.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:25px;">32 + 16 =</text>
<text x="1443.37px" y="1570.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">48</text>
<text x="1443.37px" y="1612.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">16</text>
<text x="1266.77px" y="1683.14px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">pa<tspan x="1303.71px 1320.84px 1330.54px " y="1683.14px 1683.14px 1683.14px ">ylo</tspan>ad  1056</text>
<g transform="matrix(33.3333,0,0,33.3333,1483.37,1724.81)">
</g>
<text x="1221.01px" y="1724.81px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;fill:rgb(102,101,109);">+ en<tspan x="1286.11px 1303.04px 1320.77px 1330.47px " y="1724.81px 1724.81px 1724.81px 1724.81px ">velo</tspan>pe  1092</text>
</g>
<g transform="matrix(1.33216,0,0,1.24734,-418.853,-527.648)">
<path d="M891.165,2388.54L1187.72,2388.54" style="fill:none;stroke:rgb(64,63,73);stroke-width:2.66px;"/>
</g>
<g transform="matrix(0.49129,0,0,1.66616,959.846,1057.2)">
<path d="M1608.99,559.832C1608.99,558.368 1605.36,557.179 1600.88,557.179L655.78,557.179C651.301,557.179 647.664,558.368 647.664,559.832L647.664,942.982C647.664,944.446 651.301,945.635 655.78,945.635L1600.88,945.635C1605.36,945.635 1608.99,944.446 1608.99,942.982L1608.99,559.832Z" style="fill:none;stroke:rgb(255,166,48);stroke-width:8.39px;"/>
</g>
<g transform="matrix(0.410953,0,0,0.095385,1048.63,2310.36)">
<path d="M1608.99,603.515C1608.99,577.941 1604.65,557.179 1599.29,557.179L657.366,557.179C652.012,557.179 647.664,577.941 647.664,603.515L647.664,899.299C647.664,924.873 652.012,945.635 657.366,945.635L1599.29,945.635C1604.65,945.635 1608.99,924.873 1608.99,899.299L1608.99,603.515Z" style="fill:rgb(255,211,152);"/>
<path d="M1631.81,603.515L1631.81,899.299C1631.81,985.017 1617.24,1054.61 1599.29,1054.61L657.366,1054.61C639.418,1054.61 624.846,985.017 624.846,899.299L624.846,603.515C624.846,517.797 639.418,448.205 657.366,448.205L1599.29,448.205C1617.24,448.205 1631.81,517.797 1631.81,603.515ZM1608.99,603.515C1608.99,577.941 1604.65,557.179 1599.29,557.179L657.366,557.179C652.012,557.179 647.664,577.941 647.664,603.515L647.664,899.299C647.664,924.873 652.012,945.635 657.366,945.635L1599.29,945.635C1604.65,945.635 1608.99,924.873 1608.99,899.299L1608.99,603.515Z" style="fill:rgb(255,211,152);"/>
</g>
<g transform="matrix(0.49129,0,0,0.365649,958.268,1781.92)">
<rect x="647.664" y="557.179" width="961.33" height="388.456" style="fill:rgb(255,166,48);"/>
</g>
<g transform="matrix(1.12527,0,0,1.24734,-187.43,-743.625)">
<rect x="1454.89" y="2496.4" width="25.344" height="20.909" style="fill:rgb(212,226,247);"/>
<path d="M1484.4,2496.4L1484.4,2517.3C1484.4,2519.61 1482.53,2521.47 1480.23,2521.47L1454.89,2521.47C1452.59,2521.47 1450.72,2519.61 1450.72,2517.3L1450.72,2496.4C1450.72,2494.1 1452.59,2492.23 1454.89,2492.23L1480.23,2492.23C1482.53,2492.23 1484.4,2494.1 1484.4,2496.4ZM1480.23,2496.4L1454.89,2496.4L1454.89,2517.3L1480.23,2517.3L1480.23,2496.4Z" style="fill:rgb(212,226,247);"/>
</g>
<g transform="matrix(1.12527,0,0,1.24734,255.507,157.594)">
<rect x="1454.89" y="2496.4" width="25.344" height="20.909" style="fill:rgb(212,226,247);"/>
<path d="M1484.4,2496.4L1484.4,2517.3C1484.4,2519.61 1482.53,2521.47 1480.23,2521.47L1454.89,2521.47C1452.59,2521.47 1450.72,2519.61 1450.72,2517.3L1450.72,2496.4C1450.72,2494.1 1452.59,2492.23 1454.89,2492.23L1480.23,2492.23C1482.53,2492.23 1484.4,2494.1 1484.4,2496.4ZM1480.23,2496.4L1454.89,2496.4L1454.89,2517.3L1480.23,2517.3L1480.23,2496.4Z" style="fill:rgb(212,226,247);"/>
</g>
<g transform="matrix(1.12527,0,0,1.24734,-122.635,-743.625)">
<rect x="1454.89" y="2496.4" width="25.344" height="20.909" style="fill:rgb(253,180,218);"/>
<path d="M1484.4,2496.4L1484.4,2517.3C1484.4,2519.61 1482.53,2521.47 1480.23,2521.47L1454.89,2521.47C1452.59,2521.47 1450.72,2519.61 1450.72,2517.3L1450.72,2496.4C1450.72,2494.1 1452.59,2492.23 1454.89,2492.23L1480.23,2492.23C1482.53,2492.23 1484.4,2494.1 1484.4,2496.4ZM1480.23,2496.4L1454.89,2496.4L1454.89,2517.3L1480.23,2517.3L1480.23,2496.4Z" style="fill:rgb(253,180,218);"/>
</g>
<g transform="matrix(1.12527,0,0,1.24734,350.049,158.841)">
<rect x="1454.89" y="2496.4" width="25.344" height="20.909" style="fill:rgb(253,180,218);"/>
<path d="M1484.4,2496.4L1484.4,2517.3C1484.4,2519.61 1482.53,2521.47 1480.23,2521.47L1454.89,2521.47C1452.59,2521.47 1450.72,2519.61 1450.72,2517.3L1450.72,2496.4C1450.72,2494.1 1452.59,2492.23 1454.89,2492.23L1480.23,2492.23C1482.53,2492.23 1484.4,2494.1 1484.4,2496.4ZM1480.23,2496.4L1454.89,2496.4L1454.89,2517.3L1480.23,2517.3L1480.23,2496.4Z" style="fill:rgb(253,180,218);"/>
</g>
<g transform="matrix(1.12527,0,0,1.24734,-56.47,-743.625)">
<rect x="1454.89" y="2496.4" width="25.344" height="20.909" style="fill:rgb(198,198,201);"/>
<path d="M1484.4,2496.4L1484.4,2517.3C1484.4,2519.61 1482.53,2521.47 1480.23,2521.47L1454.89,2521.47C1452.59,2521.47 1450.72,2519.61 1450.72,2517.3L1450.72,2496.4C1450.72,2494.1 1452.59,2492.23 1454.89,2492.23L1480.23,2492.23C1482.53,2492.23 1484.4,2494.1 1484.4,2496.4ZM1480.23,2496.4L1454.89,2496.4L1454.89,2517.3L1480.23,2517.3L1480.23,2496.4Z" style="fill:rgb(198,198,201);"/>
</g>
<g transform="matrix(1.12527,0,0,1.24734,452.097,158.629)">
<rect x="1454.89" y="2496.4" width="25.344" height="20.909" style="fill:rgb(198,198,201);"/>
<path d="M1484.4,2496.4L1484.4,2517.3C1484.4,2519.61 1482.53,2521.47 1480.23,2521.47L1454.89,2521.47C1452.59,2521.47 1450.72,2519.61 1450.72,2517.3L1450.72,2496.4C1450.72,2494.1 1452.59,2492.23 1454.89,2492.23L1480.23,2492.23C1482.53,2492.23 1484.4,2494.1 1484.4,2496.4ZM1480.23,2496.4L1454.89,2496.4L1454.89,2517.3L1480.23,2517.3L1480.23,2496.4Z" style="fill:rgb(198,198,201);"/>
</g>
<g transform="matrix(1.12527,0,0,1.24734,15.782,211.942)">
<text x="1231.86px" y="1470.8px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:41.667px;">R<tspan x="1259.4px " y="1470.8px ">e</tspan>spHell<tspan x="1405.19px " y="1470.8px ">o</tspan></text>
<g transform="matrix(25,0,0,25,1391.85,1512.47)">
</g>
<text x="1268.53px" y="1512.47px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:25px;fill:white;">t<tspan x="1277.65px " y="1512.47px ">y</tspan>pe=0x82</text>
</g>
<g transform="matrix(1.12527,0,0,1.24734,-3.54999,383.641)">
<text x="1171.58px" y="1445.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">sidr</text>
<text x="1171.58px" y="1487.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">sidi</text>
<text x="1171.58px" y="1528.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">ect<tspan x="1216.61px " y="1528.98px ">i</tspan></text>
<text x="1171.58px" y="1570.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">sct<tspan x="1214.91px " y="1570.64px ">i</tspan></text>
<text x="1171.58px" y="1612.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">biscuit</text>
<g transform="matrix(33.3333,0,0,33.3333,1238.74,1653.98)">
</g>
<text x="1171.58px" y="1653.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">aut<tspan x="1219.81px " y="1653.98px ">h</tspan></text>
</g>
<g transform="matrix(1.12527,0,0,1.24734,5.40653,383.641)">
<text x="1494.7px" y="1445.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">4</text>
<text x="1494.7px" y="1487.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">4</text>
<text x="1454.7px" y="1528.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">768</text>
<text x="1454.7px" y="1570.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">188</text>
<text x="1281px" y="1612.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:25px;">76 + 24 + 16 =</text>
<text x="1454.7px" y="1612.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">116</text>
<text x="1474.7px" y="1653.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">16</text>
<text x="1298.1px" y="1724.81px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">pa<tspan x="1335.03px 1352.16px 1361.86px " y="1724.81px 1724.81px 1724.81px ">ylo</tspan>ad  1096</text>
<g transform="matrix(33.3333,0,0,33.3333,1514.7,1766.48)">
</g>
<text x="1252.33px" y="1766.48px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;fill:rgb(102,101,109);">+ en<tspan x="1317.43px 1334.36px 1352.1px 1361.8px " y="1766.48px 1766.48px 1766.48px 1766.48px ">velo</tspan>pe  1132</text>
</g>
<g transform="matrix(1.12526,-0.00552033,0,1.24736,577.101,1504.92)">
<g transform="matrix(25,0,0,25,1221.4,1439.71)">
</g>
<text x="1171.58px" y="1439.71px" style="font-family:'Nunito-Regular', 'Nunito';font-size:25px;">data</text>
</g>
<g transform="matrix(1.12527,0,0,1.24734,671.631,1498.47)">
<g transform="matrix(25,0,0,25,1238.5,1439.71)">
</g>
<text x="1171.58px" y="1439.71px" style="font-family:'Nunito-Regular', 'Nunito';font-size:25px;">nonc<tspan x="1225.2px " y="1439.71px ">e</tspan></text>
</g>
<g transform="matrix(1.12527,0,0,1.24734,773.678,1498.47)">
<g transform="matrix(25,0,0,25,1281.5,1439.71)">
</g>
<text x="1171.58px" y="1439.71px" style="font-family:'Nunito-Regular', 'Nunito';font-size:25px;">aut<tspan x="1207.75px " y="1439.71px ">h</tspan> c<tspan x="1239.73px " y="1439.71px ">o</tspan>de</text>
</g>
<g transform="matrix(1.33216,0,0,1.24734,127.619,-497.943)">
<path d="M891.165,2388.54L1187.72,2388.54" style="fill:none;stroke:rgb(64,63,73);stroke-width:2.66px;"/>
</g>
<g transform="matrix(0.49129,0,0,1.40614,-133.099,1992.75)">
<path d="M1608.99,560.322C1608.99,558.587 1605.36,557.179 1600.88,557.179L655.78,557.179C651.301,557.179 647.664,558.587 647.664,560.322L647.664,942.492C647.664,944.227 651.301,945.635 655.78,945.635L1600.88,945.635C1605.36,945.635 1608.99,944.227 1608.99,942.492L1608.99,560.322Z" style="fill:none;stroke:rgb(255,166,48);stroke-width:9.75px;"/>
</g>
<g transform="matrix(0.49129,0,0,0.368077,-134.677,2571.24)">
<rect x="647.664" y="557.179" width="961.33" height="388.456" style="fill:rgb(255,166,48);"/>
</g>
<g transform="matrix(1.12527,0,0,1.24734,-1077.16,1002.61)">
<text x="1224.31px" y="1471.18px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:41.667px;">Emp<tspan x="1308.86px 1324.06px " y="1471.18px 1471.18px ">ty</tspan>Data</text>
<g transform="matrix(25,0,0,25,1391.85,1512.85)">
</g>
<text x="1268.53px" y="1512.85px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:25px;fill:white;">t<tspan x="1277.65px " y="1512.85px ">y</tspan>pe=0x84</text>
</g>
<g transform="matrix(1.12527,0,0,1.24734,-1096.5,1200.43)">
<text x="1171.58px" y="1445.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">sidx</text>
<text x="1171.58px" y="1487.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">ctr</text>
<g transform="matrix(33.3333,0,0,33.3333,1238.74,1528.98)">
</g>
<text x="1171.58px" y="1528.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">aut<tspan x="1219.81px " y="1528.98px ">h</tspan></text>
</g>
<g transform="matrix(1.12527,0,0,1.24734,-1029.53,1200.43)">
<text x="1443.14px" y="1445.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">4</text>
<text x="1443.14px" y="1487.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">8</text>
<text x="1423.14px" y="1528.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">16</text>
<text x="1286.55px" y="1599.81px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">pa<tspan x="1323.48px 1340.61px 1350.31px " y="1599.81px 1599.81px 1599.81px ">ylo</tspan>ad  28</text>
<g transform="matrix(33.3333,0,0,33.3333,1463.15,1641.48)">
</g>
<text x="1240.78px" y="1641.48px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;fill:rgb(102,101,109);">+ en<tspan x="1305.88px 1322.81px 1340.55px 1350.25px " y="1641.48px 1641.48px 1641.48px 1641.48px ">velo</tspan>pe  64</text>
</g>
<g transform="matrix(1.33216,0,0,1.24734,-965.326,161.211)">
<path d="M891.165,2388.54L1187.72,2388.54" style="fill:none;stroke:rgb(64,63,73);stroke-width:2.66px;"/>
</g>
<g transform="matrix(0.49129,0,0,1.40614,959.846,1992.75)">
<path d="M1608.99,560.322C1608.99,558.587 1605.36,557.179 1600.88,557.179L655.78,557.179C651.301,557.179 647.664,558.587 647.664,560.322L647.664,942.492C647.664,944.227 651.301,945.635 655.78,945.635L1600.88,945.635C1605.36,945.635 1608.99,944.227 1608.99,942.492L1608.99,560.322Z" style="fill:none;stroke:rgb(255,166,48);stroke-width:9.75px;"/>
</g>
<g transform="matrix(0.49129,0,0,0.368077,958.268,2571.24)">
<rect x="647.664" y="557.179" width="961.33" height="388.456" style="fill:rgb(255,166,48);"/>
</g>
<g transform="matrix(1.12527,0,0,1.24734,15.782,1002.61)">
<text x="1211.79px" y="1471.12px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:42.083px;">C<tspan x="1238.72px " y="1471.12px ">o</tspan>okieR<tspan x="1367.5px " y="1471.12px ">e</tspan>pl<tspan x="1426.83px " y="1471.12px ">y</tspan></text>
<g transform="matrix(25.4167,0,0,25.4167,1392.88,1513.2)">
</g>
<text x="1267.5px" y="1513.2px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:25.417px;fill:white;">t<tspan x="1276.78px " y="1513.2px ">y</tspan>pe=0x86</text>
</g>
<g transform="matrix(1.12527,0,0,1.24734,-1.30896,1200.2)">
<text x="1171.58px" y="1445.94px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.75px;">sidx</text>
<text x="1171.58px" y="1487.61px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.75px;">nonc<tspan x="1243.97px " y="1487.61px ">e</tspan></text>
<g transform="matrix(33.75,0,0,33.75,1267.05,1529.27)">
</g>
<text x="1171.58px" y="1529.27px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.75px;">c<tspan x="1186.87px " y="1529.27px ">o</tspan>okie</text>
</g>
<g transform="matrix(1.12527,0,0,1.24734,65.6578,1200.2)">
<text x="1442.89px" y="1445.94px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.75px;">4</text>
<text x="1422.64px" y="1487.61px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.75px;">24</text>
<text x="1296.21px" y="1529.27px" style="font-family:'Nunito-Regular', 'Nunito';font-size:25.417px;">16 + 16 =</text>
<text x="1422.64px" y="1529.27px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.75px;">32</text>
<text x="1284.34px" y="1600.11px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.75px;">pa<tspan x="1321.73px 1339.08px 1348.9px " y="1600.11px 1600.11px 1600.11px ">ylo</tspan>ad  60</text>
<g transform="matrix(33.75,0,0,33.75,1463.15,1641.77)">
</g>
<text x="1238px" y="1641.77px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.75px;fill:rgb(102,101,109);">+ en<tspan x="1303.91px 1321.06px 1339.01px 1348.83px " y="1641.77px 1641.77px 1641.77px 1641.77px ">velo</tspan>pe  96</text>
</g>
<g transform="matrix(1.33216,0,0,1.24734,129.86,160.982)">
<path d="M891.165,2388.54L1187.72,2388.54" style="fill:none;stroke:rgb(64,63,73);stroke-width:2.66px;"/>
</g>
<g transform="matrix(0.49129,0,0,1.66616,1506.32,1057.2)">
<path d="M1608.99,559.832C1608.99,558.368 1605.36,557.179 1600.88,557.179L655.78,557.179C651.301,557.179 647.664,558.368 647.664,559.832L647.664,942.982C647.664,944.446 651.301,945.635 655.78,945.635L1600.88,945.635C1605.36,945.635 1608.99,944.446 1608.99,942.982L1608.99,559.832Z" style="fill:none;stroke:rgb(247,4,132);stroke-width:8.39px;"/>
</g>
<g transform="matrix(0.410953,0,0,0.095385,1595.1,2285.75)">
<path d="M1608.99,603.515C1608.99,577.941 1604.65,557.179 1599.29,557.179L657.366,557.179C652.012,557.179 647.664,577.941 647.664,603.515L647.664,899.299C647.664,924.873 652.012,945.635 657.366,945.635L1599.29,945.635C1604.65,945.635 1608.99,924.873 1608.99,899.299L1608.99,603.515Z" style="fill:rgb(255,211,152);"/>
<path d="M1631.81,603.515L1631.81,899.299C1631.81,985.017 1617.24,1054.61 1599.29,1054.61L657.366,1054.61C639.418,1054.61 624.846,985.017 624.846,899.299L624.846,603.515C624.846,517.797 639.418,448.205 657.366,448.205L1599.29,448.205C1617.24,448.205 1631.81,517.797 1631.81,603.515ZM1608.99,603.515C1608.99,577.941 1604.65,557.179 1599.29,557.179L657.366,557.179C652.012,557.179 647.664,577.941 647.664,603.515L647.664,899.299C647.664,924.873 652.012,945.635 657.366,945.635L1599.29,945.635C1604.65,945.635 1608.99,924.873 1608.99,899.299L1608.99,603.515Z" style="fill:rgb(255,211,152);"/>
</g>
<g transform="matrix(1.12527,0,0,1.24734,359.526,-769.283)">
<rect x="1454.89" y="2496.4" width="25.344" height="20.909" style="fill:rgb(212,226,247);"/>
<path d="M1484.4,2496.4L1484.4,2517.3C1484.4,2519.61 1482.53,2521.47 1480.23,2521.47L1454.89,2521.47C1452.59,2521.47 1450.72,2519.61 1450.72,2517.3L1450.72,2496.4C1450.72,2494.1 1452.59,2492.23 1454.89,2492.23L1480.23,2492.23C1482.53,2492.23 1484.4,2494.1 1484.4,2496.4ZM1480.23,2496.4L1454.89,2496.4L1454.89,2517.3L1480.23,2517.3L1480.23,2496.4Z" style="fill:rgb(212,226,247);"/>
</g>
<g transform="matrix(1.12527,0,0,1.24734,424.321,-769.283)">
<rect x="1454.89" y="2496.4" width="25.344" height="20.909" style="fill:rgb(253,180,218);"/>
<path d="M1484.4,2496.4L1484.4,2517.3C1484.4,2519.61 1482.53,2521.47 1480.23,2521.47L1454.89,2521.47C1452.59,2521.47 1450.72,2519.61 1450.72,2517.3L1450.72,2496.4C1450.72,2494.1 1452.59,2492.23 1454.89,2492.23L1480.23,2492.23C1482.53,2492.23 1484.4,2494.1 1484.4,2496.4ZM1480.23,2496.4L1454.89,2496.4L1454.89,2517.3L1480.23,2517.3L1480.23,2496.4Z" style="fill:rgb(253,180,218);"/>
</g>
<g transform="matrix(1.12527,0,0,1.24734,490.486,-769.283)">
<rect x="1454.89" y="2496.4" width="25.344" height="20.909" style="fill:rgb(198,198,201);"/>
<path d="M1484.4,2496.4L1484.4,2517.3C1484.4,2519.61 1482.53,2521.47 1480.23,2521.47L1454.89,2521.47C1452.59,2521.47 1450.72,2519.61 1450.72,2517.3L1450.72,2496.4C1450.72,2494.1 1452.59,2492.23 1454.89,2492.23L1480.23,2492.23C1482.53,2492.23 1484.4,2494.1 1484.4,2496.4ZM1480.23,2496.4L1454.89,2496.4L1454.89,2517.3L1480.23,2517.3L1480.23,2496.4Z" style="fill:rgb(198,198,201);"/>
</g>
<g transform="matrix(0.49129,0,0,0.365649,1504.74,1781.92)">
<rect x="647.664" y="557.179" width="961.33" height="388.456" style="fill:rgb(247,4,132);"/>
</g>
<g transform="matrix(1.12527,0,0,1.24734,568.22,211.942)">
<text x="1251.12px" y="1470.8px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:41.667px;">InitC<tspan x="1337.33px " y="1470.8px ">o</tspan>nf</text>
<g transform="matrix(25,0,0,25,1386.55,1512.47)">
</g>
<text x="1263.23px" y="1512.47px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:25px;fill:white;">t<tspan x="1272.35px " y="1512.47px ">y</tspan>pe=0x83</text>
</g>
<g transform="matrix(1.12527,0,0,1.24734,542.923,463.055)">
<text x="1171.58px" y="1445.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">sidi</text>
<text x="1171.58px" y="1487.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">sidr</text>
<text x="1171.58px" y="1528.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">biscuit</text>
<g transform="matrix(33.3333,0,0,33.3333,1238.74,1570.64)">
</g>
<text x="1171.58px" y="1570.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">aut<tspan x="1219.81px " y="1570.64px ">h</tspan></text>
</g>
<g transform="matrix(1.12527,0,0,1.24734,587.128,463.055)">
<text x="1463.37px" y="1445.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">4</text>
<text x="1463.37px" y="1487.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">4</text>
<text x="1249.67px" y="1528.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:25px;">76 + 24 + 16 =</text>
<text x="1423.37px" y="1528.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">116</text>
<text x="1443.37px" y="1570.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">16</text>
<text x="1286.77px" y="1641.48px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">pa<tspan x="1323.71px 1340.84px 1350.54px " y="1641.48px 1641.48px 1641.48px ">ylo</tspan>ad  140</text>
<g transform="matrix(33.3333,0,0,33.3333,1483.37,1683.14)">
</g>
<text x="1241.01px" y="1683.14px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;fill:rgb(102,101,109);">+ en<tspan x="1306.11px 1323.04px 1340.77px 1350.47px " y="1683.14px 1683.14px 1683.14px 1683.14px ">velo</tspan>pe  176</text>
</g>
<g transform="matrix(1.33216,0,0,1.24734,674.092,-525.153)">
<path d="M891.165,2388.54L1187.72,2388.54" style="fill:none;stroke:rgb(64,63,73);stroke-width:2.66px;"/>
</g>
<g transform="matrix(0.49129,0,0,1.40614,413.374,1992.75)">
<path d="M1608.99,560.322C1608.99,558.587 1605.36,557.179 1600.88,557.179L655.78,557.179C651.301,557.179 647.664,558.587 647.664,560.322L647.664,942.492C647.664,944.227 651.301,945.635 655.78,945.635L1600.88,945.635C1605.36,945.635 1608.99,944.227 1608.99,942.492L1608.99,560.322Z" style="fill:none;stroke:rgb(247,4,132);stroke-width:9.75px;"/>
</g>
<g transform="matrix(0.49129,0,0,0.368077,411.795,2571.24)">
<rect x="647.664" y="557.179" width="961.33" height="388.456" style="fill:rgb(247,4,132);"/>
</g>
<g transform="matrix(1.12527,0,0,1.24734,-524.725,1002.61)">
<text x="1279.66px" y="1471.18px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:41.667px;">Data</text>
<g transform="matrix(25,0,0,25,1386.55,1512.85)">
</g>
<text x="1263.23px" y="1512.85px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:25px;fill:white;">t<tspan x="1272.35px " y="1512.85px ">y</tspan>pe=0x85</text>
</g>
<g transform="matrix(1.12527,0,0,1.24734,-550.023,1200.57)">
<text x="1171.58px" y="1445.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">sidx</text>
<text x="1171.58px" y="1487.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">ctr</text>
<g transform="matrix(33.3333,0,0,33.3333,1290.6,1528.98)">
</g>
<text x="1171.58px" y="1528.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">data</text>
</g>
<g transform="matrix(1.12527,0,0,1.24734,-586.775,1200.57)">
<text x="1535.32px" y="1445.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">4</text>
<text x="1535.32px" y="1487.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">8</text>
<text x="1398.39px" y="1528.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:25px;">v<tspan x="1411.02px " y="1528.98px ">a</tspan>riabl<tspan x="1474.12px " y="1528.98px ">e</tspan> +</text>
<text x="1515.32px" y="1528.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">16</text>
<text x="1268.24px" y="1599.81px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">pa<tspan x="1305.18px 1322.31px 1332.01px " y="1599.81px 1599.81px 1599.81px ">ylo</tspan>ad</text>
<text x="1396.24px" y="1599.81px" style="font-family:'Nunito-Regular', 'Nunito';font-size:25px;">v<tspan x="1408.87px " y="1599.81px ">a</tspan>riabl<tspan x="1471.97px " y="1599.81px ">e</tspan> +</text>
<text x="1515.32px" y="1599.81px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">28</text>
<text x="1222.48px" y="1641.48px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;fill:rgb(102,101,109);">+ en<tspan x="1287.58px 1304.51px 1322.24px 1331.94px " y="1641.48px 1641.48px 1641.48px 1641.48px ">velo</tspan>pe</text>
<text x="1396.24px" y="1641.48px" style="font-family:'Nunito-Regular', 'Nunito';font-size:25px;">v<tspan x="1408.87px " y="1641.48px ">a</tspan>riabl<tspan x="1471.97px " y="1641.48px ">e</tspan> +</text>
<g transform="matrix(33.3333,0,0,33.3333,1555.32,1641.48)">
</g>
<text x="1515.32px" y="1641.48px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;fill:rgb(102,101,109);">64</text>
</g>
<g transform="matrix(1.33216,0,0,1.24734,-416.123,162.22)">
<path d="M891.165,2388.54L1187.72,2388.54" style="fill:none;stroke:rgb(64,63,73);stroke-width:2.66px;"/>
</g>
<g transform="matrix(0.400209,0,0,1.19089,1603.98,2115.3)">
<path d="M1608.99,560.89C1608.99,558.842 1604.53,557.179 1599.03,557.179L657.627,557.179C652.128,557.179 647.664,558.842 647.664,560.89L647.664,941.924C647.664,943.972 652.128,945.635 657.627,945.635L1599.03,945.635C1604.53,945.635 1608.99,943.972 1608.99,941.924L1608.99,560.89Z" style="fill:white;stroke:rgb(255,211,152);stroke-width:11.57px;"/>
</g>
<g transform="matrix(0.400209,0,0,0.196676,1603.98,2669.25)">
<rect x="647.664" y="557.179" width="961.33" height="388.456" style="fill:rgb(255,211,152);"/>
</g>
<g transform="matrix(1.12527,0,0,1.24734,550.082,1014.76)">
<g transform="matrix(41.6667,0,0,41.6667,1401.28,1457.77)">
</g>
<text x="1279.11px" y="1457.77px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:41.667px;">biscuit</text>
</g>
<g transform="matrix(1.12527,0,0,1.24734,588.6,1106.02)">
<text x="1398.83px" y="1445.94px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.75px;">32</text>
<text x="1398.83px" y="1487.61px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.75px;">12</text>
<text x="1398.83px" y="1529.27px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.75px;">32</text>
<text x="1283.47px" y="1600.11px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.75px;">biscuit  76</text>
<text x="1241.85px" y="1641.77px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.75px;fill:rgb(102,101,109);">+ nonc<tspan x="1343.21px " y="1641.77px ">e</tspan>  100</text>
<g transform="matrix(33.75,0,0,33.75,1450.58,1683.44)">
</g>
<text x="1183.8px" y="1683.44px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.75px;fill:rgb(102,101,109);">+ aut<tspan x="1261.6px " y="1683.44px ">h</tspan> c<tspan x="1304.76px " y="1683.44px ">o</tspan>de  116</text>
</g>
<g transform="matrix(1.05033,0,0,1.24734,960.732,66.8014)">
<path d="M891.165,2388.54L1187.72,2388.54" style="fill:none;stroke:rgb(64,63,73);stroke-width:3.02px;"/>
</g>
<g transform="matrix(1.12527,0,0,1.24734,578.408,1106.02)">
<text x="1171.58px" y="1445.94px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.75px;">peerid</text>
<text x="1171.58px" y="1487.61px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.75px;">no</text>
<g transform="matrix(33.75,0,0,33.75,1204.08,1529.27)">
</g>
<text x="1171.58px" y="1529.27px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.75px;">ck</text>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 273 KiB

After

Width:  |  Height:  |  Size: 272 KiB

View File

@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 1890 1086" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:1.5;">
<g id="ArtBoard1" transform="matrix(0.888676,0,0,0.801704,-157.443,-1585.2)">
<rect x="177.165" y="1977.29" width="2125.98" height="1353.42" style="fill:none;"/>
<g transform="matrix(0.888676,0,0,0.801704,-157.443,-1585.2)">
<rect id="ArtBoard1" x="177.165" y="1977.29" width="2125.98" height="1353.42" style="fill:none;"/>
<clipPath id="_clip1">
<rect x="177.165" y="1977.29" width="2125.98" height="1353.42"/>
<rect id="ArtBoard11" serif:id="ArtBoard1" x="177.165" y="1977.29" width="2125.98" height="1353.42"/>
</clipPath>
<g clip-path="url(#_clip1)">
<g transform="matrix(1.12527,0,0,1.24734,177.165,1977.29)">
@@ -72,7 +72,7 @@
<text x="1423.43px" y="1695.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">16</text>
<g transform="matrix(33.3333,0,0,33.3333,1463.43,1766.48)">
</g>
<text x="1226.13px" y="1766.48px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">pack<tspan x="1295.16px " y="1766.48px ">a</tspan>ge  n + 36</text>
<text x="1213.53px" y="1766.48px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">en<tspan x="1250.03px 1266.96px 1284.7px 1294.4px " y="1766.48px 1766.48px 1766.48px 1766.48px ">velo</tspan>pe  n + 36</text>
</g>
<g transform="matrix(1.12527,0,0,1.24734,-1007.2,213.348)">
<text x="1228.7px" y="1470.55px" style="font-family:'Nunito-Medium', 'Nunito';font-weight:500;font-size:41.667px;fill:white;">En<tspan x="1276.75px 1298px 1320.25px 1332.58px " y="1470.55px 1470.55px 1470.55px 1470.55px ">velo</tspan>pe</text>
@@ -115,7 +115,7 @@
<text x="1171.58px" y="1445.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">sidi</text>
<text x="1171.58px" y="1487.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">epki</text>
<text x="1171.58px" y="1528.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">sctr</text>
<text x="1171.58px" y="1570.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">pidi_<tspan x="1241.84px " y="1570.64px ">c</tspan>t</text>
<text x="1171.58px" y="1570.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">pidiC</text>
<text x="1171.58px" y="1612.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">aut<tspan x="1219.81px " y="1612.31px ">h</tspan></text>
</g>
<g transform="matrix(1.12527,0,0,1.24734,-506.344,409.368)">
@@ -136,14 +136,14 @@
<g transform="matrix(0.49129,0,0,1.66616,959.319,1057.98)">
<path d="M1608.99,559.832C1608.99,558.368 1605.36,557.179 1600.88,557.179L655.78,557.179C651.301,557.179 647.664,558.368 647.664,559.832L647.664,942.982C647.664,944.446 651.301,945.635 655.78,945.635L1600.88,945.635C1605.36,945.635 1608.99,944.446 1608.99,942.982L1608.99,559.832Z" style="fill:none;stroke:rgb(255,166,48);stroke-width:8.39px;"/>
</g>
<g transform="matrix(0.410953,0,0,0.095385,1048.1,2363.41)">
<g transform="matrix(0.410953,0,0,0.095385,1048.1,2311.14)">
<path d="M1608.99,603.515C1608.99,577.941 1604.65,557.179 1599.29,557.179L657.366,557.179C652.012,557.179 647.664,577.941 647.664,603.515L647.664,899.299C647.664,924.873 652.012,945.635 657.366,945.635L1599.29,945.635C1604.65,945.635 1608.99,924.873 1608.99,899.299L1608.99,603.515Z" style="fill:rgb(255,211,152);"/>
<path d="M1631.81,603.515L1631.81,899.299L1631.15,930.502L1629.25,959.805L1626.24,986.218L1622.29,1009.11L1617.49,1028.01L1611.96,1042.35L1605.83,1051.45L1599.29,1054.61L657.366,1054.61L650.833,1051.45L644.697,1042.35L639.166,1028.01L634.372,1009.11L630.416,986.218L627.414,959.805L625.507,930.502L624.846,899.299L624.846,603.515L625.507,572.312L627.414,543.009L630.416,516.596L634.372,493.7L639.166,474.808L644.697,460.468L650.833,451.364L657.366,448.205L1599.29,448.205L1605.83,451.364L1611.96,460.468L1617.49,474.808L1622.29,493.7L1626.24,516.596L1629.25,543.009L1631.15,572.312L1631.81,603.515ZM1608.99,603.515C1608.99,577.941 1604.65,557.179 1599.29,557.179L657.366,557.179C652.012,557.179 647.664,577.941 647.664,603.515L647.664,899.299C647.664,924.873 652.012,945.635 657.366,945.635L1599.29,945.635C1604.65,945.635 1608.99,924.873 1608.99,899.299L1608.99,603.515Z" style="fill:rgb(255,211,152);"/>
<path d="M1631.81,603.515L1631.81,899.299C1631.81,985.017 1617.24,1054.61 1599.29,1054.61L657.366,1054.61C639.418,1054.61 624.846,985.017 624.846,899.299L624.846,603.515C624.846,517.797 639.418,448.205 657.366,448.205L1599.29,448.205C1617.24,448.205 1631.81,517.797 1631.81,603.515ZM1608.99,603.515C1608.99,577.941 1604.65,557.179 1599.29,557.179L657.366,557.179C652.012,557.179 647.664,577.941 647.664,603.515L647.664,899.299C647.664,924.873 652.012,945.635 657.366,945.635L1599.29,945.635C1604.65,945.635 1608.99,924.873 1608.99,899.299L1608.99,603.515Z" style="fill:rgb(255,211,152);"/>
</g>
<g transform="matrix(0.49129,0,0,0.365649,957.741,1782.7)">
<rect x="647.664" y="557.179" width="961.33" height="388.456" style="fill:rgb(255,166,48);"/>
</g>
<g transform="matrix(1.12527,0,0,1.24734,-161.376,-690.576)">
<g transform="matrix(1.12527,0,0,1.24734,-187.957,-742.844)">
<rect x="1454.89" y="2496.4" width="25.344" height="20.909" style="fill:rgb(212,226,247);"/>
<path d="M1484.4,2496.4L1484.4,2517.3C1484.4,2519.61 1482.53,2521.47 1480.23,2521.47L1454.89,2521.47C1452.59,2521.47 1450.72,2519.61 1450.72,2517.3L1450.72,2496.4C1450.72,2494.1 1452.59,2492.23 1454.89,2492.23L1480.23,2492.23C1482.53,2492.23 1484.4,2494.1 1484.4,2496.4ZM1480.23,2496.4L1454.89,2496.4L1454.89,2517.3L1480.23,2517.3L1480.23,2496.4Z" style="fill:rgb(212,226,247);"/>
</g>
@@ -151,7 +151,7 @@
<rect x="1454.89" y="2496.4" width="25.344" height="20.909" style="fill:rgb(212,226,247);"/>
<path d="M1484.4,2496.4L1484.4,2517.3C1484.4,2519.61 1482.53,2521.47 1480.23,2521.47L1454.89,2521.47C1452.59,2521.47 1450.72,2519.61 1450.72,2517.3L1450.72,2496.4C1450.72,2494.1 1452.59,2492.23 1454.89,2492.23L1480.23,2492.23C1482.53,2492.23 1484.4,2494.1 1484.4,2496.4ZM1480.23,2496.4L1454.89,2496.4L1454.89,2517.3L1480.23,2517.3L1480.23,2496.4Z" style="fill:rgb(212,226,247);"/>
</g>
<g transform="matrix(1.12527,0,0,1.24734,-109.871,-690.576)">
<g transform="matrix(1.12527,0,0,1.24734,-123.162,-742.844)">
<rect x="1454.89" y="2496.4" width="25.344" height="20.909" style="fill:rgb(253,180,218);"/>
<path d="M1484.4,2496.4L1484.4,2517.3C1484.4,2519.61 1482.53,2521.47 1480.23,2521.47L1454.89,2521.47C1452.59,2521.47 1450.72,2519.61 1450.72,2517.3L1450.72,2496.4C1450.72,2494.1 1452.59,2492.23 1454.89,2492.23L1480.23,2492.23C1482.53,2492.23 1484.4,2494.1 1484.4,2496.4ZM1480.23,2496.4L1454.89,2496.4L1454.89,2517.3L1480.23,2517.3L1480.23,2496.4Z" style="fill:rgb(253,180,218);"/>
</g>
@@ -159,7 +159,7 @@
<rect x="1454.89" y="2496.4" width="25.344" height="20.909" style="fill:rgb(253,180,218);"/>
<path d="M1484.4,2496.4L1484.4,2517.3C1484.4,2519.61 1482.53,2521.47 1480.23,2521.47L1454.89,2521.47C1452.59,2521.47 1450.72,2519.61 1450.72,2517.3L1450.72,2496.4C1450.72,2494.1 1452.59,2492.23 1454.89,2492.23L1480.23,2492.23C1482.53,2492.23 1484.4,2494.1 1484.4,2496.4ZM1480.23,2496.4L1454.89,2496.4L1454.89,2517.3L1480.23,2517.3L1480.23,2496.4Z" style="fill:rgb(253,180,218);"/>
</g>
<g transform="matrix(1.12527,0,0,1.24734,-56.9969,-690.576)">
<g transform="matrix(1.12527,0,0,1.24734,-56.9969,-742.844)">
<rect x="1454.89" y="2496.4" width="25.344" height="20.909" style="fill:rgb(198,198,201);"/>
<path d="M1484.4,2496.4L1484.4,2517.3C1484.4,2519.61 1482.53,2521.47 1480.23,2521.47L1454.89,2521.47C1452.59,2521.47 1450.72,2519.61 1450.72,2517.3L1450.72,2496.4C1450.72,2494.1 1452.59,2492.23 1454.89,2492.23L1480.23,2492.23C1482.53,2492.23 1484.4,2494.1 1484.4,2496.4ZM1480.23,2496.4L1454.89,2496.4L1454.89,2517.3L1480.23,2517.3L1480.23,2496.4Z" style="fill:rgb(198,198,201);"/>
</g>
@@ -178,17 +178,19 @@
<text x="1171.58px" y="1487.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">sidi</text>
<text x="1171.58px" y="1528.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">ect<tspan x="1216.61px " y="1528.98px ">i</tspan></text>
<text x="1171.58px" y="1570.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">sct<tspan x="1214.91px " y="1570.64px ">i</tspan></text>
<text x="1171.58px" y="1612.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">aut<tspan x="1219.81px " y="1612.31px ">h</tspan></text>
<text x="1171.58px" y="1653.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">b<tspan x="1190.01px 1196.74px 1211.78px 1226.21px 1243.91px 1250.64px 1261.78px 1276.71px 1291.14px " y="1653.98px 1653.98px 1653.98px 1653.98px 1653.98px 1653.98px 1653.98px 1653.98px 1653.98px ">iscuit_ct</tspan></text>
<text x="1171.58px" y="1612.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">biscuit</text>
<g transform="matrix(33.3333,0,0,33.3333,1238.74,1653.98)">
</g>
<text x="1171.58px" y="1653.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">aut<tspan x="1219.81px " y="1653.98px ">h</tspan></text>
</g>
<g transform="matrix(1.12527,0,0,1.24734,4.87963,384.421)">
<text x="1494.7px" y="1445.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">4</text>
<text x="1494.7px" y="1487.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">4</text>
<text x="1454.7px" y="1528.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">768</text>
<text x="1454.7px" y="1570.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">188</text>
<text x="1474.7px" y="1612.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">16</text>
<text x="1306.8px" y="1653.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:25px;">76+24+16 =</text>
<text x="1454.7px" y="1653.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">116</text>
<text x="1281px" y="1612.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:25px;">76 + 24 + 16 =</text>
<text x="1454.7px" y="1612.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">116</text>
<text x="1474.7px" y="1653.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">16</text>
<text x="1298.1px" y="1724.81px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">pa<tspan x="1335.03px 1352.16px 1361.86px " y="1724.81px 1724.81px 1724.81px ">ylo</tspan>ad  1096</text>
<g transform="matrix(33.3333,0,0,33.3333,1514.7,1766.48)">
</g>
@@ -273,7 +275,7 @@
<text x="1422.64px" y="1612.61px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.75px;">32</text>
<g transform="matrix(33.75,0,0,33.75,1463.15,1683.44)">
</g>
<text x="1279.71px" y="1683.44px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.75px;">pack<tspan x="1349.61px " y="1683.44px ">a</tspan>ge  64</text>
<text x="1284.34px" y="1683.44px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.75px;">pa<tspan x="1321.73px 1339.08px 1348.9px " y="1683.44px 1683.44px 1683.44px ">ylo</tspan>ad  64</text>
</g>
<g transform="matrix(1.33216,0,0,1.24734,129.333,240.128)">
<path d="M891.165,2388.54L1187.72,2388.54" style="fill:none;stroke:rgb(64,63,73);stroke-width:2.66px;"/>
@@ -283,13 +285,13 @@
</g>
<g transform="matrix(0.410953,0,0,0.095385,1594.58,2286.53)">
<path d="M1608.99,603.515C1608.99,577.941 1604.65,557.179 1599.29,557.179L657.366,557.179C652.012,557.179 647.664,577.941 647.664,603.515L647.664,899.299C647.664,924.873 652.012,945.635 657.366,945.635L1599.29,945.635C1604.65,945.635 1608.99,924.873 1608.99,899.299L1608.99,603.515Z" style="fill:rgb(255,211,152);"/>
<path d="M1631.81,603.515L1631.81,899.299L1631.15,930.502L1629.25,959.805L1626.24,986.218L1622.29,1009.11L1617.49,1028.01L1611.96,1042.35L1605.83,1051.45L1599.29,1054.61L657.366,1054.61L650.833,1051.45L644.697,1042.35L639.166,1028.01L634.372,1009.11L630.416,986.218L627.414,959.805L625.507,930.502L624.846,899.299L624.846,603.515L625.507,572.312L627.414,543.009L630.416,516.596L634.372,493.7L639.166,474.808L644.697,460.468L650.833,451.364L657.366,448.205L1599.29,448.205L1605.83,451.364L1611.96,460.468L1617.49,474.808L1622.29,493.7L1626.24,516.596L1629.25,543.009L1631.15,572.312L1631.81,603.515ZM1608.99,603.515C1608.99,577.941 1604.65,557.179 1599.29,557.179L657.366,557.179C652.012,557.179 647.664,577.941 647.664,603.515L647.664,899.299C647.664,924.873 652.012,945.635 657.366,945.635L1599.29,945.635C1604.65,945.635 1608.99,924.873 1608.99,899.299L1608.99,603.515Z" style="fill:rgb(255,211,152);"/>
<path d="M1631.81,603.515L1631.81,899.299C1631.81,985.017 1617.24,1054.61 1599.29,1054.61L657.366,1054.61C639.418,1054.61 624.846,985.017 624.846,899.299L624.846,603.515C624.846,517.797 639.418,448.205 657.366,448.205L1599.29,448.205C1617.24,448.205 1631.81,517.797 1631.81,603.515ZM1608.99,603.515C1608.99,577.941 1604.65,557.179 1599.29,557.179L657.366,557.179C652.012,557.179 647.664,577.941 647.664,603.515L647.664,899.299C647.664,924.873 652.012,945.635 657.366,945.635L1599.29,945.635C1604.65,945.635 1608.99,924.873 1608.99,899.299L1608.99,603.515Z" style="fill:rgb(255,211,152);"/>
</g>
<g transform="matrix(1.12527,0,0,1.24734,385.58,-768.503)">
<g transform="matrix(1.12527,0,0,1.24734,358.999,-768.503)">
<rect x="1454.89" y="2496.4" width="25.344" height="20.909" style="fill:rgb(212,226,247);"/>
<path d="M1484.4,2496.4L1484.4,2517.3C1484.4,2519.61 1482.53,2521.47 1480.23,2521.47L1454.89,2521.47C1452.59,2521.47 1450.72,2519.61 1450.72,2517.3L1450.72,2496.4C1450.72,2494.1 1452.59,2492.23 1454.89,2492.23L1480.23,2492.23C1482.53,2492.23 1484.4,2494.1 1484.4,2496.4ZM1480.23,2496.4L1454.89,2496.4L1454.89,2517.3L1480.23,2517.3L1480.23,2496.4Z" style="fill:rgb(212,226,247);"/>
</g>
<g transform="matrix(1.12527,0,0,1.24734,437.085,-768.503)">
<g transform="matrix(1.12527,0,0,1.24734,423.794,-768.503)">
<rect x="1454.89" y="2496.4" width="25.344" height="20.909" style="fill:rgb(253,180,218);"/>
<path d="M1484.4,2496.4L1484.4,2517.3C1484.4,2519.61 1482.53,2521.47 1480.23,2521.47L1454.89,2521.47C1452.59,2521.47 1450.72,2519.61 1450.72,2517.3L1450.72,2496.4C1450.72,2494.1 1452.59,2492.23 1454.89,2492.23L1480.23,2492.23C1482.53,2492.23 1484.4,2494.1 1484.4,2496.4ZM1480.23,2496.4L1454.89,2496.4L1454.89,2517.3L1480.23,2517.3L1480.23,2496.4Z" style="fill:rgb(253,180,218);"/>
</g>
@@ -309,7 +311,7 @@
<g transform="matrix(1.12527,0,0,1.24734,542.396,463.835)">
<text x="1171.58px" y="1445.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">sidi</text>
<text x="1171.58px" y="1487.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">sidr</text>
<text x="1171.58px" y="1528.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">b<tspan x="1190.01px 1196.74px 1211.78px 1226.21px 1243.91px 1250.64px 1261.78px 1276.71px 1291.14px " y="1528.98px 1528.98px 1528.98px 1528.98px 1528.98px 1528.98px 1528.98px 1528.98px 1528.98px ">iscuit_ct</tspan></text>
<text x="1171.58px" y="1528.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">biscuit</text>
<g transform="matrix(33.3333,0,0,33.3333,1238.74,1570.64)">
</g>
<text x="1171.58px" y="1570.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">aut<tspan x="1219.81px " y="1570.64px ">h</tspan></text>
@@ -317,7 +319,7 @@
<g transform="matrix(1.12527,0,0,1.24734,586.601,463.835)">
<text x="1463.37px" y="1445.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">4</text>
<text x="1463.37px" y="1487.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">4</text>
<text x="1275.47px" y="1528.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:25px;">76+24+16 =</text>
<text x="1249.67px" y="1528.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:25px;">76 + 24 + 16 =</text>
<text x="1423.37px" y="1528.98px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">116</text>
<text x="1443.37px" y="1570.64px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">16</text>
<text x="1286.77px" y="1641.48px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">pa<tspan x="1323.71px 1340.84px 1350.54px " y="1641.48px 1641.48px 1641.48px ">ylo</tspan>ad  140</text>

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Some files were not shown because too many files have changed in this diff Show More