Compare commits

..

41 Commits

Author SHA1 Message Date
Benjamin Lipp
6af6fb6b2a fix: pterm can resolve to NAT
Some checks failed
rosenpass-ciphers - primitives - benchmark / prim-benchmark (i686-linux) (push) Has been cancelled
rosenpass-ciphers - primitives - benchmark / prim-benchmark (x86_64-linux) (push) Has been cancelled
rosenpass - protocol - benchmark / proto-benchmark (i686-linux) (push) Has been cancelled
rosenpass - protocol - benchmark / proto-benchmark (x86_64-linux) (push) Has been cancelled
rosenpass-ciphers - primitives - benchmark / ciphers-primitives-bench-status (push) Has been cancelled
rosenpass - protocol - benchmark / ciphers-protocol-bench-status (push) Has been cancelled
2025-11-25 16:00:16 +01:00
Benjamin Lipp
e3b43a59bf fix: transcription errors in grammar relating to processes 2025-11-25 15:59:29 +01:00
Benjamin Lipp
3942bfa65e chore: add comment indicating CryptoVerif terms 2025-11-25 15:58:45 +01:00
Benjamin Lipp
7b1a62b6bb feat: do not try to reject reserved words
Some checks failed
rosenpass-ciphers - primitives - benchmark / prim-benchmark (i686-linux) (push) Has been cancelled
rosenpass-ciphers - primitives - benchmark / prim-benchmark (x86_64-linux) (push) Has been cancelled
rosenpass - protocol - benchmark / proto-benchmark (i686-linux) (push) Has been cancelled
rosenpass - protocol - benchmark / proto-benchmark (x86_64-linux) (push) Has been cancelled
rosenpass-ciphers - primitives - benchmark / ciphers-primitives-bench-status (push) Has been cancelled
rosenpass - protocol - benchmark / ciphers-protocol-bench-status (push) Has been cancelled
Co-authored-by: Anja Rabich <a.rabich@uni-luebeck.de>
2025-11-18 17:55:32 +01:00
Benjamin Lipp
d1a33981b1 feat: add missing option terms 2025-11-18 16:15:20 +01:00
Benjamin Lipp
f20fd1acc3 feat: module declaration, WIP: missing ProVerif option terms
Some checks failed
rosenpass-ciphers - primitives - benchmark / prim-benchmark (i686-linux) (push) Has been cancelled
rosenpass-ciphers - primitives - benchmark / prim-benchmark (x86_64-linux) (push) Has been cancelled
rosenpass - protocol - benchmark / proto-benchmark (i686-linux) (push) Has been cancelled
rosenpass - protocol - benchmark / proto-benchmark (x86_64-linux) (push) Has been cancelled
rosenpass-ciphers - primitives - benchmark / ciphers-primitives-bench-status (push) Has been cancelled
rosenpass - protocol - benchmark / ciphers-protocol-bench-status (push) Has been cancelled
Co-authored-by: Anja Rabich <a.rabich@uni-luebeck.de>
2025-10-14 18:01:13 +02:00
Benjamin Lipp
3ce0d262d9 feat: add parser for multi-line comments, without nesting
Co-authored-by: Anja Rabich <a.rabich@uni-luebeck.de>
2025-10-14 17:31:31 +02:00
Anja Rabich
a389e3c222 WIP: lark parser for awk
Co-authored-by: Benjamin Lipp <blipp@rosenpass.eu>
2025-09-30 17:46:33 +02:00
Benjamin Lipp
cb16bd44bb feat(WIP): integrate marzipan.awk into Python
Some checks failed
rosenpass-ciphers - primitives - benchmark / prim-benchmark (i686-linux) (push) Has been cancelled
rosenpass-ciphers - primitives - benchmark / prim-benchmark (x86_64-linux) (push) Has been cancelled
rosenpass - protocol - benchmark / proto-benchmark (i686-linux) (push) Has been cancelled
rosenpass - protocol - benchmark / proto-benchmark (x86_64-linux) (push) Has been cancelled
rosenpass-ciphers - primitives - benchmark / ciphers-primitives-bench-status (push) Has been cancelled
rosenpass - protocol - benchmark / ciphers-protocol-bench-status (push) Has been cancelled
The LLM-generated Python code showed us that the replacement of aliases,
or, as a preparatory step, the tokenization, is something for LARK.

Co-authored-by: Anja Rabich <a.rabich@uni-luebeck.de>
2025-09-16 18:00:01 +02:00
Benjamin Lipp
3f4c7c2786 feat: add CLI param for configurable output/target directory
Co-authored-by: Anja Rabich <a.rabich@uni-luebeck.de>
2025-09-16 16:47:32 +02:00
Anja Rabich
475f4593f9 feat: improve exception handling and error codes + refactor run_proverif
Some checks failed
rosenpass-ciphers - primitives - benchmark / prim-benchmark (i686-linux) (push) Has been cancelled
rosenpass-ciphers - primitives - benchmark / prim-benchmark (x86_64-linux) (push) Has been cancelled
rosenpass - protocol - benchmark / proto-benchmark (i686-linux) (push) Has been cancelled
rosenpass - protocol - benchmark / proto-benchmark (x86_64-linux) (push) Has been cancelled
rosenpass-ciphers - primitives - benchmark / ciphers-primitives-bench-status (push) Has been cancelled
rosenpass - protocol - benchmark / ciphers-protocol-bench-status (push) Has been cancelled
Co-authored-by: Benjamin Lipp <blipp@rosenpass.eu>
2025-09-02 17:56:13 +02:00
Anja Rabich
13c5edbe44 fix: change awk mode from append to write
Co-authored-by: Benjamin Lipp <blipp@rosenpass.eu>
2025-09-02 16:35:46 +02:00
Benjamin Lipp
b1ac5d9244 feat(WIP): clean up code and TODOs, add clean command
Some checks failed
rosenpass-ciphers - primitives - benchmark / prim-benchmark (i686-linux) (push) Has been cancelled
rosenpass-ciphers - primitives - benchmark / prim-benchmark (x86_64-linux) (push) Has been cancelled
rosenpass - protocol - benchmark / proto-benchmark (i686-linux) (push) Has been cancelled
rosenpass - protocol - benchmark / proto-benchmark (x86_64-linux) (push) Has been cancelled
rosenpass-ciphers - primitives - benchmark / ciphers-primitives-bench-status (push) Has been cancelled
rosenpass - protocol - benchmark / ciphers-protocol-bench-status (push) Has been cancelled
Co-authored-by: Anja Rabich <a.rabich@uni-luebeck.de>
2025-08-12 18:02:20 +02:00
Anja Rabich
a4ff3d4eb5 feat: WIP clean-up TODOs
Some checks failed
rosenpass-ciphers - primitives - benchmark / prim-benchmark (i686-linux) (push) Has been cancelled
rosenpass-ciphers - primitives - benchmark / prim-benchmark (x86_64-linux) (push) Has been cancelled
rosenpass - protocol - benchmark / proto-benchmark (i686-linux) (push) Has been cancelled
rosenpass - protocol - benchmark / proto-benchmark (x86_64-linux) (push) Has been cancelled
rosenpass-ciphers - primitives - benchmark / ciphers-primitives-bench-status (push) Has been cancelled
rosenpass - protocol - benchmark / ciphers-protocol-bench-status (push) Has been cancelled
Co-authored-by: Benjamin Lipp <blipp@rosenpass.eu>
2025-08-05 17:57:07 +02:00
Anja Rabich
19ebce79f1 Merge branch 'main' into analyze_py 2025-08-05 16:43:19 +02:00
Benjamin Lipp
a5ae83e726 chore: add TODOs 2025-07-22 17:42:13 +02:00
Karolin Varner
9327c2c4f3 chore: Add code review 2025-07-22 17:10:28 +02:00
Benjamin Lipp
b140c56359 feat: move analyze to Python, including parallel execution
Co-authored-by: Anja Rabich <a.rabich@uni-luebeck.de>
2025-07-15 17:35:30 +02:00
Anja Rabich
d20bb137c9 feat: metaverif function
Co-Authored-By: Benjamin Lipp <blipp@rosenpass.eu>
2025-07-01 17:37:38 +02:00
Anja Rabich
c259be76c8 WIP: metaverif part 2
Co-Authored-By: Benjamin Lipp <blipp@rosenpass.eu>
2025-07-01 17:08:11 +02:00
Anja Rabich
73d180c4cf WIP: metaverif in python
Co-Authored-By: Benjamin Lipp <blipp@rosenpass.eu>
2025-06-17 18:01:03 +02:00
Benjamin Lipp
d44a96e6b6 fix: add +x flag in mode of marzipan/src/analyze.sh 2025-06-17 16:30:31 +02:00
Benjamin Lipp
ff20fbbe3a WIP: move metaverif to Python
Co-Authored-By: Anja Rabich <a.rabich@uni-luebeck.de>
2025-06-10 18:06:33 +02:00
Benjamin Lipp
5232ab3a8e feat: move parsing of RESULT lines to Python
Co-Authored-By: Anja Rabich <a.rabich@uni-luebeck.de>
2025-06-10 17:45:21 +02:00
Benjamin Lipp
2e27753f4a feat: move pretty_output to Python
* Remove pretty_output_line from Bash
* Remove pretty_output_line from click CLI

Co-Authored-By: Anja Rabich <a.rabich@uni-luebeck.de>
2025-06-10 17:13:42 +02:00
Benjamin Lipp
2628adbac8 feat(WIP): pretty output in Python
Work on repairing the regexes in pretty_output

Co-Authored-By: Anja Rabich <a.rabich@uni-luebeck.de>
2025-06-03 18:00:27 +02:00
Benjamin Lipp
744cf6fb50 feat: pretty output line 2025-06-03 16:22:56 +02:00
Benjamin Lipp
4bdc464b5b chore: plan TODOs for the next times
Co-Authored-By: Anja Rabich <a.rabich@uni-luebeck.de>
2025-05-06 17:40:10 +02:00
Benjamin Lipp
eb64f50d99 chore: update TODO, remove unused code
Co-Authored-By: Anja Rabich <a.rabich@uni-luebeck.de>
2025-05-06 17:28:25 +02:00
Benjamin Lipp
73b04cdc12 feat: move awk prep call to Python
Co-Authored-By: Anja Rabich <a.rabich@uni-luebeck.de>
2025-05-06 17:25:58 +02:00
Benjamin Lipp
437c591b2d chore: update TODO 2025-05-06 17:09:27 +02:00
Benjamin Lipp
7cbd6576d4 feat: move cpp call to Python 2025-05-06 17:08:21 +02:00
Benjamin Lipp
ac5a5cf76d chore: clarify path in README 2025-05-06 16:34:59 +02:00
Benjamin Lipp
18359ef3f4 chore: clean up unused log parameter 2025-05-06 16:34:35 +02:00
Anja Rabich
3e161d8c8d feat: add clean_warnings() in __init__.py
chore: update TODO.md

Co-Authored-By: Benjamin Lipp <blipp@rosenpass.eu>
2025-04-22 18:09:14 +02:00
Benjamin Lipp
56db757de3 chore: add TODO 2025-04-08 17:54:29 +02:00
Benjamin Lipp
5ff3bc944e chore: add README for marzipan 2025-04-08 17:52:07 +02:00
Benjamin Lipp
fb93258fcc feat: fix issue with empty extra_args 2025-04-08 17:44:37 +02:00
Benjamin Lipp
9ab120843a try nix shell 2025-04-08 16:43:31 +02:00
Benjamin Lipp
25f2abac80 WIP 2025-02-20 15:04:24 +01:00
Benjamin Lipp
c7ec12be9a feat: add nix setup for marzipan 2025-02-20 15:04:24 +01:00
131 changed files with 9958 additions and 5499 deletions

View File

@@ -21,13 +21,13 @@ jobs:
matrix: matrix:
system: ["x86_64-linux", "i686-linux"] system: ["x86_64-linux", "i686-linux"]
runs-on: ubicloud-standard-2 runs-on: ubuntu-latest
defaults: defaults:
run: run:
shell: bash shell: bash
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
# Install nix # Install nix
@@ -93,7 +93,7 @@ jobs:
ciphers-primitives-bench-status: ciphers-primitives-bench-status:
if: ${{ always() }} if: ${{ always() }}
needs: [prim-benchmark] needs: [prim-benchmark]
runs-on: ubicloud-standard-2 runs-on: ubuntu-latest
steps: steps:
- name: Successful - name: Successful
if: ${{ !(contains(needs.*.result, 'failure')) }} if: ${{ !(contains(needs.*.result, 'failure')) }}

View File

@@ -21,13 +21,13 @@ jobs:
matrix: matrix:
system: ["x86_64-linux", "i686-linux"] system: ["x86_64-linux", "i686-linux"]
runs-on: ubicloud-standard-2 runs-on: ubuntu-latest
defaults: defaults:
run: run:
shell: bash shell: bash
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
# Install nix # Install nix
@@ -80,7 +80,7 @@ jobs:
ciphers-protocol-bench-status: ciphers-protocol-bench-status:
if: ${{ always() }} if: ${{ always() }}
needs: [proto-benchmark] needs: [proto-benchmark]
runs-on: ubicloud-standard-2 runs-on: ubuntu-latest
steps: steps:
- name: Successful - name: Successful
if: ${{ !(contains(needs.*.result, 'failure')) }} if: ${{ !(contains(needs.*.result, 'failure')) }}

View File

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

View File

@@ -30,7 +30,7 @@ jobs:
runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }} runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v5 uses: actions/checkout@v4
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
- name: Build (no push) and Load - name: Build (no push) and Load
@@ -128,7 +128,7 @@ jobs:
runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }} runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v5 uses: actions/checkout@v4
- name: Docker meta - name: Docker meta
id: meta id: meta
@@ -173,7 +173,7 @@ jobs:
touch "${{ runner.temp }}/digests/${digest#sha256:}" touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest - name: Upload digest
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v4
with: with:
name: digests-rp-${{ matrix.arch }} name: digests-rp-${{ matrix.arch }}
path: ${{ runner.temp }}/digests/* path: ${{ runner.temp }}/digests/*
@@ -193,7 +193,7 @@ jobs:
runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }} runs-on: ${{ matrix.arch == 'arm64' && 'ubuntu-24.04-arm' || 'ubuntu-latest' }}
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v5 uses: actions/checkout@v4
- name: Docker meta - name: Docker meta
id: meta id: meta
@@ -237,7 +237,7 @@ jobs:
touch "${{ runner.temp }}/digests/${digest#sha256:}" touch "${{ runner.temp }}/digests/${digest#sha256:}"
- name: Upload digest - name: Upload digest
uses: actions/upload-artifact@v5 uses: actions/upload-artifact@v4
with: with:
name: digests-rosenpass-${{ matrix.arch }} name: digests-rosenpass-${{ matrix.arch }}
path: ${{ runner.temp }}/digests/* path: ${{ runner.temp }}/digests/*
@@ -255,7 +255,7 @@ jobs:
target: [rp, rosenpass] target: [rp, rosenpass]
steps: steps:
- name: Download digests - name: Download digests
uses: actions/download-artifact@v5 uses: actions/download-artifact@v4
with: with:
path: ${{ runner.temp }}/digests path: ${{ runner.temp }}/digests
pattern: digests-${{ matrix.target }}-* pattern: digests-${{ matrix.target }}-*

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

@@ -19,7 +19,7 @@ jobs:
needs: needs:
- aarch64-darwin---rosenpass - aarch64-darwin---rosenpass
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
@@ -38,7 +38,7 @@ jobs:
- aarch64-darwin---rp - aarch64-darwin---rp
- aarch64-darwin---rosenpass-oci-image - aarch64-darwin---rosenpass-oci-image
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
@@ -54,7 +54,7 @@ jobs:
- warp-macos-13-arm64-6x - warp-macos-13-arm64-6x
needs: [] needs: []
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
@@ -70,7 +70,7 @@ jobs:
- warp-macos-13-arm64-6x - warp-macos-13-arm64-6x
needs: [] needs: []
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
@@ -87,7 +87,7 @@ jobs:
needs: needs:
- aarch64-darwin---rosenpass - aarch64-darwin---rosenpass
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
@@ -102,7 +102,7 @@ jobs:
runs-on: runs-on:
- warp-macos-13-arm64-6x - warp-macos-13-arm64-6x
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable

View File

@@ -19,7 +19,7 @@ jobs:
needs: needs:
- i686-linux---rosenpass - i686-linux---rosenpass
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
@@ -35,7 +35,7 @@ jobs:
- ubicloud-standard-2-ubuntu-2204 - ubicloud-standard-2-ubuntu-2204
needs: [] needs: []
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
@@ -52,7 +52,7 @@ jobs:
needs: needs:
- i686-linux---rosenpass - i686-linux---rosenpass
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
@@ -67,7 +67,7 @@ jobs:
runs-on: runs-on:
- ubicloud-standard-2-ubuntu-2204 - ubicloud-standard-2-ubuntu-2204
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
@@ -76,8 +76,7 @@ jobs:
name: rosenpass name: rosenpass
authToken: ${{ secrets.CACHIX_AUTH_TOKEN }} authToken: ${{ secrets.CACHIX_AUTH_TOKEN }}
- name: Check - name: Check
run: | run: nix flake check . --print-build-logs
nix flake check . --print-build-logs
x86_64-linux---default: x86_64-linux---default:
name: Build x86_64-linux.default name: Build x86_64-linux.default
runs-on: runs-on:
@@ -85,7 +84,7 @@ jobs:
needs: needs:
- x86_64-linux---rosenpass - x86_64-linux---rosenpass
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
@@ -102,7 +101,7 @@ jobs:
needs: needs:
- x86_64-linux---proverif-patched - x86_64-linux---proverif-patched
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
@@ -118,7 +117,7 @@ jobs:
- ubicloud-standard-2-ubuntu-2204 - ubicloud-standard-2-ubuntu-2204
needs: [] needs: []
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
@@ -137,7 +136,7 @@ jobs:
- x86_64-linux---rosenpass-static-oci-image - x86_64-linux---rosenpass-static-oci-image
- x86_64-linux---rp-static - x86_64-linux---rp-static
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
@@ -159,7 +158,7 @@ jobs:
# - run: | # - run: |
# DEBIAN_FRONTEND=noninteractive # 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 # 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 # - uses: cachix/install-nix-action@v30
# with: # with:
# nix_path: nixpkgs=channel:nixos-unstable # nix_path: nixpkgs=channel:nixos-unstable
@@ -177,7 +176,7 @@ jobs:
- ubicloud-standard-2-ubuntu-2204 - ubicloud-standard-2-ubuntu-2204
needs: [] needs: []
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
@@ -196,7 +195,7 @@ jobs:
- run: | - run: |
DEBIAN_FRONTEND=noninteractive 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 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 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
@@ -217,7 +216,7 @@ jobs:
- run: | - run: |
DEBIAN_FRONTEND=noninteractive 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 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 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
@@ -236,7 +235,7 @@ jobs:
needs: needs:
- x86_64-linux---rosenpass - x86_64-linux---rosenpass
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
@@ -256,7 +255,7 @@ jobs:
- run: | - run: |
DEBIAN_FRONTEND=noninteractive 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 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 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
@@ -274,7 +273,7 @@ jobs:
- ubicloud-standard-2-ubuntu-2204 - ubicloud-standard-2-ubuntu-2204
needs: [] needs: []
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
@@ -290,7 +289,7 @@ jobs:
- ubicloud-standard-2-ubuntu-2204 - ubicloud-standard-2-ubuntu-2204
needs: [] needs: []
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
@@ -307,7 +306,7 @@ jobs:
needs: needs:
- x86_64-linux---rosenpass-static - x86_64-linux---rosenpass-static
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
@@ -323,7 +322,7 @@ jobs:
- ubicloud-standard-2-ubuntu-2204 - ubicloud-standard-2-ubuntu-2204
needs: [] needs: []
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
@@ -338,7 +337,7 @@ jobs:
runs-on: runs-on:
- ubicloud-standard-2-ubuntu-2204 - ubicloud-standard-2-ubuntu-2204
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
@@ -353,7 +352,7 @@ jobs:
runs-on: ubicloud-standard-2-ubuntu-2204 runs-on: ubicloud-standard-2-ubuntu-2204
if: ${{ github.ref == 'refs/heads/main' }} if: ${{ github.ref == 'refs/heads/main' }}
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable

View File

@@ -16,7 +16,7 @@ jobs:
cargo-test-mac: cargo-test-mac:
runs-on: warp-macos-13-arm64-6x runs-on: warp-macos-13-arm64-6x
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/cache@v4 - uses: actions/cache@v4
with: with:
path: | path: |

View File

@@ -16,7 +16,7 @@ jobs:
prettier: prettier:
runs-on: ubicloud-standard-2-ubuntu-2204 runs-on: ubicloud-standard-2-ubuntu-2204
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actionsx/prettier@v3 - uses: actionsx/prettier@v3
with: with:
args: --check . args: --check .
@@ -25,7 +25,7 @@ jobs:
name: Shellcheck name: Shellcheck
runs-on: ubicloud-standard-2-ubuntu-2204 runs-on: ubicloud-standard-2-ubuntu-2204
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- name: Run ShellCheck - name: Run ShellCheck
uses: ludeeus/action-shellcheck@master uses: ludeeus/action-shellcheck@master
@@ -33,7 +33,7 @@ jobs:
name: Rust code formatting name: Rust code formatting
runs-on: ubicloud-standard-2-ubuntu-2204 runs-on: ubicloud-standard-2-ubuntu-2204
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/cache@v4 - uses: actions/cache@v4
with: with:
path: | path: |
@@ -56,7 +56,7 @@ jobs:
cargo-bench: cargo-bench:
runs-on: ubicloud-standard-2-ubuntu-2204 runs-on: ubicloud-standard-2-ubuntu-2204
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/cache@v4 - uses: actions/cache@v4
with: with:
path: | path: |
@@ -77,14 +77,14 @@ jobs:
steps: steps:
- name: Install mandoc - name: Install mandoc
run: sudo apt-get install -y mandoc run: sudo apt-get install -y mandoc
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- name: Check rp.1 - name: Check rp.1
run: doc/check.sh doc/rp.1 run: doc/check.sh doc/rp.1
cargo-audit: cargo-audit:
runs-on: ubicloud-standard-2-ubuntu-2204 runs-on: ubicloud-standard-2-ubuntu-2204
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions-rs/audit-check@v1 - uses: actions-rs/audit-check@v1
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
@@ -92,7 +92,7 @@ jobs:
cargo-clippy: cargo-clippy:
runs-on: ubicloud-standard-2-ubuntu-2204 runs-on: ubicloud-standard-2-ubuntu-2204
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/cache@v4 - uses: actions/cache@v4
with: with:
path: | path: |
@@ -111,7 +111,7 @@ jobs:
cargo-doc: cargo-doc:
runs-on: ubicloud-standard-2-ubuntu-2204 runs-on: ubicloud-standard-2-ubuntu-2204
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/cache@v4 - uses: actions/cache@v4
with: with:
path: | path: |
@@ -130,7 +130,7 @@ jobs:
cargo-test: cargo-test:
runs-on: ubicloud-standard-2-ubuntu-2204 runs-on: ubicloud-standard-2-ubuntu-2204
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/cache@v4 - uses: actions/cache@v4
with: with:
path: | path: |
@@ -149,7 +149,7 @@ jobs:
runs-on: runs-on:
- ubicloud-standard-2-ubuntu-2204 - ubicloud-standard-2-ubuntu-2204
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/cache@v4 - uses: actions/cache@v4
with: with:
path: | path: |
@@ -171,7 +171,7 @@ jobs:
cargo-fuzz: cargo-fuzz:
runs-on: ubicloud-standard-2-ubuntu-2204 runs-on: ubicloud-standard-2-ubuntu-2204
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/cache@v4 - uses: actions/cache@v4
with: with:
path: | path: |
@@ -206,7 +206,7 @@ jobs:
env: env:
RUSTUP_TOOLCHAIN: nightly RUSTUP_TOOLCHAIN: nightly
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/cache@v4 - uses: actions/cache@v4
with: with:
path: | path: |

View File

@@ -16,7 +16,7 @@ jobs:
multi-peer: multi-peer:
runs-on: ubicloud-standard-2-ubuntu-2204 runs-on: ubicloud-standard-2-ubuntu-2204
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- run: cargo build --bin rosenpass --release - run: cargo build --bin rosenpass --release
- run: python misc/generate_configs.py - run: python misc/generate_configs.py
- run: chmod +x .ci/run-regression.sh - run: chmod +x .ci/run-regression.sh
@@ -27,7 +27,7 @@ jobs:
boot-race: boot-race:
runs-on: ubicloud-standard-2-ubuntu-2204 runs-on: ubicloud-standard-2-ubuntu-2204
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- run: cargo build --bin rosenpass --release - run: cargo build --bin rosenpass --release
- run: chmod +x .ci/boot_race/run.sh - run: chmod +x .ci/boot_race/run.sh
- run: cargo run --release --bin rosenpass gen-keys .ci/boot_race/a.toml - run: cargo run --release --bin rosenpass gen-keys .ci/boot_race/a.toml

View File

@@ -11,7 +11,7 @@ jobs:
runs-on: runs-on:
- ubuntu-latest - ubuntu-latest
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
- uses: cachix/cachix-action@v15 - uses: cachix/cachix-action@v15
with: with:
@@ -30,7 +30,7 @@ jobs:
runs-on: runs-on:
- macos-13 - macos-13
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
- uses: cachix/cachix-action@v15 - uses: cachix/cachix-action@v15
with: with:
@@ -49,7 +49,7 @@ jobs:
runs-on: runs-on:
- ubuntu-latest - ubuntu-latest
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
with: with:
nix_path: nixpkgs=channel:nixos-unstable nix_path: nixpkgs=channel:nixos-unstable
@@ -69,7 +69,7 @@ jobs:
name: Build and upload DEB and RPM packages name: Build and upload DEB and RPM packages
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: cachix/install-nix-action@v30 - uses: cachix/install-nix-action@v30
- uses: cachix/cachix-action@v15 - uses: cachix/cachix-action@v15
with: with:

View File

@@ -13,13 +13,13 @@ jobs:
name: Deny dependencies with vulnerabilities or incompatible licenses name: Deny dependencies with vulnerabilities or incompatible licenses
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: EmbarkStudios/cargo-deny-action@v2 - uses: EmbarkStudios/cargo-deny-action@v2
cargo-supply-chain: cargo-supply-chain:
name: Supply Chain Report name: Supply Chain Report
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
- uses: actions/cache@v4 - uses: actions/cache@v4
with: with:
path: | path: |
@@ -53,7 +53,7 @@ jobs:
permissions: permissions:
contents: write contents: write
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v4
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/cache@v4 - uses: actions/cache@v4
@@ -150,7 +150,7 @@ jobs:
fi fi
echo "IN_DEPENDABOT_PR_CONTEXT=$IN_DEPENDABOT_PR_CONTEXT" >> $GITHUB_ENV echo "IN_DEPENDABOT_PR_CONTEXT=$IN_DEPENDABOT_PR_CONTEXT" >> $GITHUB_ENV
shell: bash shell: bash
- uses: actions/checkout@v5 - uses: actions/checkout@v4
if: env.IN_DEPENDABOT_PR_CONTEXT == 'true' if: env.IN_DEPENDABOT_PR_CONTEXT == 'true'
with: with:
token: ${{ secrets.CI_BOT_PAT }} token: ${{ secrets.CI_BOT_PAT }}

189
Cargo.lock generated
View File

@@ -110,9 +110,9 @@ dependencies = [
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.98" version = "1.0.96"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" checksum = "6b964d184e89d9b6b67dd2715bc8e74cf3107fb2b529990c90cf517326150bf4"
dependencies = [ dependencies = [
"backtrace", "backtrace",
] ]
@@ -126,34 +126,6 @@ dependencies = [
"derive_arbitrary", "derive_arbitrary",
] ]
[[package]]
name = "assert_tv"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4aa42a8e0531efffd0fe96c6feef83221dc673c34b4ba2c2c9cbcd499511acba"
dependencies = [
"anyhow",
"assert_tv_macros",
"base64",
"log",
"serde",
"serde_json",
"serde_yaml",
"toml",
"zstd",
]
[[package]]
name = "assert_tv_macros"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c7b50043d3ecb7bc6e5e60dc6704757b7f9a9903d2c5ca13f8d62d494c68333"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.98",
]
[[package]] [[package]]
name = "atomic-polyfill" name = "atomic-polyfill"
version = "1.0.3" version = "1.0.3"
@@ -185,12 +157,6 @@ dependencies = [
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
[[package]]
name = "base64"
version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]] [[package]]
name = "base64ct" name = "base64ct"
version = "1.6.0" version = "1.6.0"
@@ -1428,9 +1394,9 @@ dependencies = [
[[package]] [[package]]
name = "libfuzzer-sys" name = "libfuzzer-sys"
version = "0.4.10" version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5037190e1f70cbeef565bd267599242926f724d3b8a9f510fd7e0b540cfa4404" checksum = "cf78f52d400cf2d84a3a973a78a592b4adc535739e0a5597a0da6f0c357adc75"
dependencies = [ dependencies = [
"arbitrary", "arbitrary",
"cc", "cc",
@@ -1453,7 +1419,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"windows-targets 0.48.5", "windows-targets 0.52.6",
] ]
[[package]] [[package]]
@@ -1474,9 +1440,9 @@ dependencies = [
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.27" version = "0.4.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
[[package]] [[package]]
name = "memchr" name = "memchr"
@@ -2075,8 +2041,6 @@ name = "rosenpass"
version = "0.3.0-dev" version = "0.3.0-dev"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"assert_tv",
"base64",
"clap", "clap",
"clap_complete", "clap_complete",
"clap_mangen", "clap_mangen",
@@ -2104,10 +2068,8 @@ dependencies = [
"rosenpass-wireguard-broker", "rosenpass-wireguard-broker",
"rustix", "rustix",
"serde", "serde",
"serde_json",
"serial_test", "serial_test",
"signal-hook", "signal-hook",
"signal-hook-mio",
"stacker", "stacker",
"static_assertions", "static_assertions",
"tempfile", "tempfile",
@@ -2190,38 +2152,6 @@ dependencies = [
"rosenpass-util", "rosenpass-util",
] ]
[[package]]
name = "rosenpass-rp"
version = "0.2.1"
dependencies = [
"anyhow",
"base64ct",
"ctrlc-async",
"env_logger",
"futures",
"futures-util",
"genetlink",
"libc",
"log",
"netlink-packet-core",
"netlink-packet-generic",
"netlink-packet-wireguard",
"rosenpass",
"rosenpass-cipher-traits",
"rosenpass-ciphers",
"rosenpass-secret-memory",
"rosenpass-util",
"rosenpass-wireguard-broker",
"rtnetlink",
"serde",
"stacker",
"tempfile",
"tokio",
"toml",
"x25519-dalek",
"zeroize",
]
[[package]] [[package]]
name = "rosenpass-secret-memory" name = "rosenpass-secret-memory"
version = "0.1.0" version = "0.1.0"
@@ -2229,8 +2159,6 @@ dependencies = [
"allocator-api2", "allocator-api2",
"allocator-api2-tests", "allocator-api2-tests",
"anyhow", "anyhow",
"assert_tv",
"base64",
"base64ct", "base64ct",
"log", "log",
"memsec", "memsec",
@@ -2238,8 +2166,6 @@ dependencies = [
"rand 0.8.5", "rand 0.8.5",
"rosenpass-to", "rosenpass-to",
"rosenpass-util", "rosenpass-util",
"serde",
"serde_json",
"tempfile", "tempfile",
"zeroize", "zeroize",
] ]
@@ -2258,13 +2184,11 @@ dependencies = [
"anyhow", "anyhow",
"base64ct", "base64ct",
"libcrux-test-utils", "libcrux-test-utils",
"log",
"mio", "mio",
"rustix", "rustix",
"static_assertions", "static_assertions",
"tempfile", "tempfile",
"thiserror 1.0.69", "thiserror 1.0.69",
"tokio",
"typenum", "typenum",
"uds", "uds",
"zerocopy 0.7.35", "zerocopy 0.7.35",
@@ -2295,6 +2219,35 @@ dependencies = [
"zerocopy 0.7.35", "zerocopy 0.7.35",
] ]
[[package]]
name = "rp"
version = "0.2.1"
dependencies = [
"anyhow",
"base64ct",
"ctrlc-async",
"futures",
"futures-util",
"genetlink",
"netlink-packet-core",
"netlink-packet-generic",
"netlink-packet-wireguard",
"rosenpass",
"rosenpass-cipher-traits",
"rosenpass-ciphers",
"rosenpass-secret-memory",
"rosenpass-util",
"rosenpass-wireguard-broker",
"rtnetlink",
"serde",
"stacker",
"tempfile",
"tokio",
"toml",
"x25519-dalek",
"zeroize",
]
[[package]] [[package]]
name = "rtnetlink" name = "rtnetlink"
version = "0.14.1" version = "0.14.1"
@@ -2417,9 +2370,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.140" version = "1.0.139"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" checksum = "44f86c3acccc9c65b153fe1b85a3be07fe5515274ec9f0653b4a0875731c72a6"
dependencies = [ dependencies = [
"itoa", "itoa",
"memchr", "memchr",
@@ -2436,19 +2389,6 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "serde_yaml"
version = "0.9.34+deprecated"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
dependencies = [
"indexmap",
"itoa",
"ryu",
"serde",
"unsafe-libyaml",
]
[[package]] [[package]]
name = "serial_test" name = "serial_test"
version = "3.2.0" version = "3.2.0"
@@ -2492,25 +2432,14 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]] [[package]]
name = "signal-hook" name = "signal-hook"
version = "0.3.18" version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
dependencies = [ dependencies = [
"libc", "libc",
"signal-hook-registry", "signal-hook-registry",
] ]
[[package]]
name = "signal-hook-mio"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd"
dependencies = [
"libc",
"mio",
"signal-hook",
]
[[package]] [[package]]
name = "signal-hook-registry" name = "signal-hook-registry"
version = "1.4.2" version = "1.4.2"
@@ -2568,9 +2497,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]] [[package]]
name = "stacker" name = "stacker"
version = "0.1.21" version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cddb07e32ddb770749da91081d8d0ac3a16f1a569a18b20348cd371f5dead06b" checksum = "d9156ebd5870ef293bfb43f91c7a74528d363ec0d424afe24160ed5a4343d08a"
dependencies = [ dependencies = [
"cc", "cc",
"cfg-if", "cfg-if",
@@ -2806,12 +2735,6 @@ dependencies = [
"subtle", "subtle",
] ]
[[package]]
name = "unsafe-libyaml"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
[[package]] [[package]]
name = "utf8parse" name = "utf8parse"
version = "0.2.2" version = "0.2.2"
@@ -3351,31 +3274,3 @@ dependencies = [
"quote", "quote",
"syn 2.0.98", "syn 2.0.98",
] ]
[[package]]
name = "zstd"
version = "0.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
dependencies = [
"zstd-safe",
]
[[package]]
name = "zstd-safe"
version = "7.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
dependencies = [
"zstd-sys",
]
[[package]]
name = "zstd-sys"
version = "2.0.15+zstd.1.5.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237"
dependencies = [
"cc",
"pkg-config",
]

View File

@@ -46,16 +46,14 @@ memsec = { git = "https://github.com/rosenpass/memsec.git", rev = "aceb9baee8aec
] } ] }
rand = "0.8.5" rand = "0.8.5"
typenum = "1.17.0" typenum = "1.17.0"
log = { version = "0.4.27" } log = { version = "0.4.22" }
clap = { version = "4.5.23", features = ["derive"] } clap = { version = "4.5.23", features = ["derive"] }
clap_mangen = "0.2.29" clap_mangen = "0.2.29"
clap_complete = "4.5.40" clap_complete = "4.5.40"
serde = { version = "1.0.217", features = ["derive"] } serde = { version = "1.0.217", features = ["derive"] }
arbitrary = { version = "1.4.1", features = ["derive"] } arbitrary = { version = "1.4.1", features = ["derive"] }
anyhow = { version = "1.0.98", features = ["backtrace", "std"] } anyhow = { version = "1.0.95", features = ["backtrace", "std"] }
mio = { version = "1.0.3", features = ["net", "os-poll"] } 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 = [ oqs-sys = { version = "0.9.1", default-features = false, features = [
'classic_mceliece', 'classic_mceliece',
'kyber', 'kyber',
@@ -81,20 +79,18 @@ hex = { version = "0.4.3" }
heck = { version = "0.5.0" } heck = { version = "0.5.0" }
libc = { version = "0.2" } libc = { version = "0.2" }
uds = { git = "https://github.com/rosenpass/uds" } uds = { git = "https://github.com/rosenpass/uds" }
signal-hook = "0.3.17"
lazy_static = "1.5" lazy_static = "1.5"
#Dev dependencies #Dev dependencies
assert_tv = { version = "0.6.4" }
base64 = { version = "0.22.1" }
serial_test = "3.2.0" serial_test = "3.2.0"
tempfile = "3" tempfile = "3"
stacker = "0.1.21" stacker = "0.1.17"
libfuzzer-sys = "0.4" libfuzzer-sys = "0.4"
test_bin = "0.4.0" test_bin = "0.4.0"
criterion = "0.5.1" criterion = "0.5.1"
allocator-api2-tests = "0.2.15" allocator-api2-tests = "0.2.15"
procspawn = { version = "1.0.1", features = ["test-support"] } procspawn = { version = "1.0.1", features = ["test-support"] }
serde_json = { version = "1.0.140" }
#Broker dependencies (might need cleanup or changes) #Broker dependencies (might need cleanup or changes)
wireguard-uapi = { version = "3.0.0", features = ["xplatform"] } wireguard-uapi = { version = "3.0.0", features = ["xplatform"] }

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 epkit:kem_pk; // epki
new sctrt:bits; // sctr new sctrt:bits; // sctr
new pidi_ct:bits; // pidi_ct new pidiCt:bits; // pidiC
new autht:bits; // auth new autht:bits; // auth
NEW_TRUSTED_SEED(seski_trusted_seed) 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) = 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(septi_trusted_seed)
NEW_TRUSTED_SEED(sspti_trusted_seed) NEW_TRUSTED_SEED(sspti_trusted_seed)
new last_cookie:key; new last_cookie:key;

View File

@@ -19,7 +19,7 @@ fun CookieMsg(
COOKIE_EV(event MCAT(eventLbl, _UnderLoadEV) (spkm, spkt, last_cookie);) \ COOKIE_EV(event MCAT(eventLbl, _UnderLoadEV) (spkm, spkt, last_cookie);) \
msgB <- Envelope(mac1, RH2b(rh)); \ msgB <- Envelope(mac1, RH2b(rh)); \
mac2_key <- create_mac2_key(sskm, spkt) \ 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 \ if Envelope(mac2_key, msgB) = mac2 then \
COOKIE_EV(event MCAT(eventLbl, _CookieValidated) (spkm, last_cookie);) \ COOKIE_EV(event MCAT(eventLbl, _CookieValidated) (spkm, last_cookie);) \
innerFunc \ innerFunc \

View File

@@ -143,10 +143,10 @@ letfun ENCRYPT_AND_MIX(ct, pt) \
// TODO: Migrate kems to use binary ciphertexts directly // TODO: Migrate kems to use binary ciphertexts directly
#define ENCAPS_AND_MIX(ct, pk, shk) \ #define ENCAPS_AND_MIX(ct, pk, shk) \
ct <- kem_enc(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) \ #define DECAPS_AND_MIX(sk, pk, ct) \
DUMMY(shk) <- kem_dec(sk, ct); \ DUMMY(shk) <- kem_dec(sk, ct); \
MIX3(kem_pk2b(pk), k2b(DUMMY(shk)), ct) MIX3(kem_pk2b(pk), ct, k2b(DUMMY(shk)))
// biscuits // 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). ) MTX_EV( event ICSent(RespHello_t, InitConf_t, key, kem_sk, kem_pk). )
SES_EV( event InitiatorSession(RespHello_t, key). ) SES_EV( event InitiatorSession(RespHello_t, key). )
let Oresp_hello(HS_DECL_ARGS) = let Oresp_hello(HS_DECL_ARGS) =
in(C, Cresp_hello(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_ct, auth); rh <- RespHello(sidr, sidi, ecti, scti, biscuit, auth);
/* try */ let ic = ( /* try */ let ic = (
ck_ini <- ck; ck_ini <- ck;
RESPHELLO_CONSUME() RESPHELLO_CONSUME()
@@ -124,7 +124,7 @@ let Oinit_hello() =
call <- Cinit_hello(sidr, biscuit_no, Ssskm, Spsk, Sspkt, Septi, Sspti, ih); call <- Cinit_hello(sidr, biscuit_no, Ssskm, Spsk, Sspkt, Septi, Sspti, ih);
#endif #endif
// TODO: This is ugly // 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() SETUP_HANDSHAKE_STATE()
eski <- kem_sk0; eski <- kem_sk0;
epti <- rng_key(setup_seed(Septi)); // RHR4 epti <- rng_key(setup_seed(Septi)); // RHR4

View File

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

View File

@@ -40,7 +40,7 @@ pub struct InferKeyedHash<Static, const KEY_LEN: usize, const HASH_LEN: usize>
where where
Static: KeyedHash<KEY_LEN, HASH_LEN>, Static: KeyedHash<KEY_LEN, HASH_LEN>,
{ {
pub _phantom_keyed_hasher: PhantomData<Static>, pub _phantom_keyed_hasher: PhantomData<*const Static>,
} }
impl<Static, const KEY_LEN: usize, const HASH_LEN: usize> InferKeyedHash<Static, KEY_LEN, HASH_LEN> impl<Static, const KEY_LEN: usize, const HASH_LEN: usize> InferKeyedHash<Static, KEY_LEN, HASH_LEN>

View File

@@ -1,10 +1,9 @@
# syntax=docker/dockerfile:1 # syntax=docker/dockerfile:1
ARG BASE_IMAGE=debian:bookworm-slim ARG BASE_IMAGE=debian:bookworm-slim
ARG CHEF_IMAGE=rust:slim-bookworm
# Stage 1: Base image with cargo-chef installed # Stage 1: Base image with cargo-chef installed
FROM ${CHEF_IMAGE} AS chef FROM rust:latest AS chef
RUN cargo install cargo-chef RUN cargo install cargo-chef
# install software required for liboqs-rust # install software required for liboqs-rust
RUN apt-get update && apt-get install -y clang cmake && rm -rf /var/lib/apt/lists/* RUN apt-get update && apt-get install -y clang cmake && rm -rf /var/lib/apt/lists/*

122
flake.lock generated
View File

@@ -18,24 +18,6 @@
"type": "github" "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": { "nix-vm-test": {
"inputs": { "inputs": {
"nixpkgs": [ "nixpkgs": [
@@ -56,27 +38,6 @@
"type": "github" "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": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1728193676, "lastModified": 1728193676,
@@ -98,58 +59,11 @@
"flake-utils": "flake-utils", "flake-utils": "flake-utils",
"nix-vm-test": "nix-vm-test", "nix-vm-test": "nix-vm-test",
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"rosenpassOld": "rosenpassOld",
"rust-overlay": "rust-overlay_2",
"treefmt-nix": "treefmt-nix_2"
}
},
"rosenpassOld": {
"inputs": {
"flake-utils": "flake-utils_2",
"nix-vm-test": "nix-vm-test_2",
"nixpkgs": [
"nixpkgs"
],
"rust-overlay": "rust-overlay", "rust-overlay": "rust-overlay",
"treefmt-nix": "treefmt-nix" "treefmt-nix": "treefmt-nix"
},
"locked": {
"lastModified": 1754748821,
"narHash": "sha256-mMggTZDC97lLvKNOLtDz3GBjjxXFD++e1s0RZsVH/vI=",
"owner": "rosenpass",
"repo": "rosenpass",
"rev": "916a9ebb7133f0b22057fb097a473217f261928a",
"type": "github"
},
"original": {
"owner": "rosenpass",
"repo": "rosenpass",
"rev": "916a9ebb7133f0b22057fb097a473217f261928a",
"type": "github"
} }
}, },
"rust-overlay": { "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": { "inputs": {
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"
@@ -184,43 +98,7 @@
"type": "github" "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": { "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": { "inputs": {
"nixpkgs": [ "nixpkgs": [
"nixpkgs" "nixpkgs"

View File

@@ -13,10 +13,6 @@
treefmt-nix.url = "github:numtide/treefmt-nix"; treefmt-nix.url = "github:numtide/treefmt-nix";
treefmt-nix.inputs.nixpkgs.follows = "nixpkgs"; 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";
}; };
outputs = outputs =
@@ -27,7 +23,6 @@
nix-vm-test, nix-vm-test,
rust-overlay, rust-overlay,
treefmt-nix, treefmt-nix,
rosenpassOld,
... ...
}@inputs: }@inputs:
nixpkgs.lib.foldl (a: b: nixpkgs.lib.recursiveUpdate a b) { } [ nixpkgs.lib.foldl (a: b: nixpkgs.lib.recursiveUpdate a b) { } [
@@ -186,35 +181,9 @@
rustfmt 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 = 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-rosenpass = pkgs.testers.runNixOSTest ./tests/systemd/rosenpass.nix;
systemd-rp = pkgs.testers.runNixOSTest ./tests/systemd/rp.nix; systemd-rp = pkgs.testers.runNixOSTest ./tests/systemd/rp.nix;
formatting = treefmtEval.config.build.check self; formatting = treefmtEval.config.build.check self;

8
marzipan/README.md Normal file
View File

@@ -0,0 +1,8 @@
# Rewriting analyze.sh in Python
* `../analyze.sh` is the old script
* `src/__init__.py` is the new script
* call the old script from the Rosenpass repository's root directory with `./analyze.sh`
* call the new script from the marzipan directory:
* `nix run .# -- analyze $repo` where `$repo` is the absolute(?) path to the root directory of the Rosenpass repository.

64
marzipan/TODO.md Normal file
View File

@@ -0,0 +1,64 @@
# TODO for the project of rewriting Marzipan
## Done
* ~~figure out why ProVerif is started on the non-processed mpv file~~
* ~~rework rebound warnings (`clean_warnings` Bash function)~~
```bash
rosenpass$ rosenpass-marzipan run-proverif target/proverif/03_identity_hiding_responder.entry.o.pv target/proverif/03_identity_hiding_responder.entry.log
```
* ~~provide log parameter to `rosenpass-marzipan`-call~~ (no, it was intentionally not used)
* ~~cpp pre-processing stuff~~
* ~~awk pre-processing stuff~~
* ~~`pretty_output` Bash function~~
* ~~pretty_output_line~~
* ~~click function intervention weirdness~~
* ~~why is everything red in the pretty output? (see line 96 in __init__.py)~~
* ~~awk RESULT flush in marzipan()~~
* ~~move the whole metaverif function to Python~~
* ~move the whole analyze function to Python~
* ~find the files~
* ~start subprocesses in parallel~
* ~wait for them to finish~
* ~~rebase from main~~
* ~~see if we still need the `extra_args is None` check in `_run_proverif`~`
* ~~set colors differently to prevent injection attack~~
* ~~by calling a function~~
* ~~by prepared statements~~
* ~~standalone function parse_result_line is no longer necessary~~
* ~~is the clean function still necessary?~~
* ~~implement better main function for click~~
* ~~why does analyze fail when the target/proverif directory is not empty?~~
* ~~return an exit status that is meaningful for CI~~
* ~~exception handling in analyze() and in run_proverif()~~
* ~~refactor filtering in run_proverif (see karo's comment)~~
* ~configurable target directory~
* ~lark parser: multiline comments, how???~
## Next Steps
* integrate marzipan.awk into Python, somehow
* options term special cases (c.f. manual page 133, starting with "fun" term)
* complete with CryptoVerif options
* error when trying with: `nix run .# -- parse ../target/proverif/01_secrecy.entry.i.pv`
* `in(C, Cinit_conf(Ssskm, Spsk, Sspkt, ic));`
* ^
* rewrite marzipan.awk into Python/LARK
* define a LARK grammar for marzipan.awk rules
* write python code for processing marzipan rules, e.g. alias replacement (step: i.pv->o.pv)
* do not assume that the repo path has subdir marzipan
* do not assume that the repo path has subdir analysis
* rewrite cpp into Python/LARK (step: mpv->i.pv)
* integrate the Nix flake into the main Nix flake
* pull the gawk dependency into the Nix flake
* think about next steps
* integrate this upstream, into the CI?
* “make it beautiful” steps? more resiliency to working directory?
* rewrite our awk usages into Python/…?
* yes, possibly as extension to the LARK grammar
* and rewrite the AST within Python
* reconstruct ProVerif input file for ProVerif
* rewrite our CPP usages into Python/…?
* low priority: nested comments in ProVerif code
“it replaces the Bash script and is idiomatic Python code”

190
marzipan/flake.lock generated Normal file
View File

@@ -0,0 +1,190 @@
{
"nodes": {
"flake-utils": {
"inputs": {
"systems": "systems"
},
"locked": {
"lastModified": 1731533236,
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide",
"repo": "flake-utils",
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "flake-utils",
"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-github-actions": {
"inputs": {
"nixpkgs": [
"poetry2nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1729742964,
"narHash": "sha256-B4mzTcQ0FZHdpeWcpDYPERtyjJd/NIuaQ9+BV1h+MpA=",
"owner": "nix-community",
"repo": "nix-github-actions",
"rev": "e04df33f62cdcf93d73e9a04142464753a16db67",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "nix-github-actions",
"type": "github"
}
},
"nixpkgs": {
"locked": {
"lastModified": 1736166416,
"narHash": "sha256-U47xeACNBpkSO6IcCm0XvahsVXpJXzjPIQG7TZlOToU=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "b30f97d8c32d804d2d832ee837d0f1ca0695faa5",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixpkgs-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_2": {
"locked": {
"lastModified": 1730157240,
"narHash": "sha256-P8wF4ag6Srmpb/gwskYpnIsnspbjZlRvu47iN527ABQ=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "75e28c029ef2605f9841e0baa335d70065fe7ae2",
"type": "github"
},
"original": {
"owner": "NixOS",
"ref": "nixos-unstable-small",
"repo": "nixpkgs",
"type": "github"
}
},
"poetry2nix": {
"inputs": {
"flake-utils": "flake-utils_2",
"nix-github-actions": "nix-github-actions",
"nixpkgs": "nixpkgs_2",
"systems": "systems_3",
"treefmt-nix": "treefmt-nix"
},
"locked": {
"lastModified": 1736280331,
"narHash": "sha256-mkVHnky9h/s2EA+t9eEC8qxgcNTE3V+vb/9XgG4fCig=",
"owner": "nix-community",
"repo": "poetry2nix",
"rev": "4d260d908f3d95fa4b3ef6a98781ff64e1eede22",
"type": "github"
},
"original": {
"owner": "nix-community",
"repo": "poetry2nix",
"type": "github"
}
},
"root": {
"inputs": {
"flake-utils": "flake-utils",
"nixpkgs": "nixpkgs",
"poetry2nix": "poetry2nix"
}
},
"systems": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
"owner": "nix-systems",
"repo": "default",
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
"type": "github"
},
"original": {
"owner": "nix-systems",
"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"
}
},
"systems_3": {
"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": [
"poetry2nix",
"nixpkgs"
]
},
"locked": {
"lastModified": 1730120726,
"narHash": "sha256-LqHYIxMrl/1p3/kvm2ir925tZ8DkI0KA10djk8wecSk=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "9ef337e492a5555d8e17a51c911ff1f02635be15",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "treefmt-nix",
"type": "github"
}
}
},
"root": "root",
"version": 7
}

18
marzipan/flake.nix Normal file
View File

@@ -0,0 +1,18 @@
{
inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
inputs.poetry2nix.url = "github:nix-community/poetry2nix";
inputs.flake-utils.url = "github:numtide/flake-utils";
outputs = (inputs:
let scoped = (scope: scope.result);
in scoped rec {
inherit (builtins) removeAttrs;
result = (import ./nix/init.nix) {
scoped = scoped;
flake.self = inputs.self;
flake.inputs = removeAttrs inputs ["self"];
};
}
);
}

1220
marzipan/nix/hyuga/poetry.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,16 @@
[tool.poetry]
name = "hyuga-language-server-installer"
version = "0.1.0"
description = ""
authors = []
[tool.poetry.dependencies]
python = ">=3.12,<3.13"
[tool.poetry.group.dev.dependencies]
hyuga = "^1.0.0"
poetry = "^2.0.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

32
marzipan/nix/init.nix Normal file
View File

@@ -0,0 +1,32 @@
outer_ctx: outer_ctx.scoped rec {
inherit (builtins) trace;
ctx = outer_ctx // { inherit config; };
inherit (ctx) scoped;
inherit (ctx.flake.inputs) nixpkgs flake-utils;
inherit (nixpkgs.lib) genAttrs zipAttrsWith;
inherit (nixpkgs.lib.debug) traceVal;
inherit (flake-utils.lib) allSystems eachSystem;
result = {
devShells = eachSupportedSystem (system: (setupSystem system).devShells);
packages = eachSupportedSystem (system: (setupSystem system).packages);
apps = eachSupportedSystem (system: (setupSystem system).apps);
};
setupSystem = (system_name: scoped rec {
result = (import ./system.nix) (ctx // {
system.name = system_name;
system.pkgs = nixpkgs.legacyPackages.${system_name};
});
});
config = {
supportedSystems = allSystems;
poetry.projectDir = ctx.flake.self;
};
eachSupportedSystem = genAttrs config.supportedSystems;
}

47
marzipan/nix/system.nix Normal file
View File

@@ -0,0 +1,47 @@
ctx: ctx.scoped rec {
inherit (ctx.system) pkgs;
inherit (ctx.flake.inputs) poetry2nix flake-utils;
inherit (pkgs) mkShellNoCC writeShellApplication;
inherit (flake-utils.lib) mkApp;
poetryCtx = poetry2nix.lib.mkPoetry2Nix { inherit pkgs; };
inherit (poetryCtx) mkPoetryEnv mkPoetryApplication;
deps = [poetryEnv];
dev-deps = []
++ deps
++ [poetryHyugaEnv]
++ (with pkgs; [poetry]);
poetryCfg = ctx.config.poetry // { overrides = poetryOverrides; };
poetryEnv = mkPoetryEnv poetryCfg;
poetryHyugaCfg = poetryCfg // { projectDir = ./hyuga; };
poetryHyugaEnv = mkPoetryEnv poetryHyugaCfg;
poetryOverrides = poetryCtx.defaultPoetryOverrides.extend (final: prev: {
hyuga = prev.hyuga.overridePythonAttrs (old: {
buildInputs = []
++ (old.buildInputs or [ ])
++ [ final.poetry-core ];
preferWheel = true;
}
);
});
result.packages.default = mkPoetryApplication poetryCfg;
result.devShells.default = mkShellNoCC {
packages = dev-deps;
};
result.apps.replPython = mkShellApp "python-repl" ''python'';
result.apps.replHy = mkShellApp "hy-repl" ''hy'';
mkShellApp = (name: script: mkApp {
drv = writeShellApplication {
inherit name;
text = script;
runtimeInputs = dev-deps;
};
});
}

1415
marzipan/poetry.lock generated Normal file

File diff suppressed because it is too large Load Diff

31
marzipan/pyproject.toml Normal file
View File

@@ -0,0 +1,31 @@
[tool.poetry]
name = "rosenpass-marzipan"
version = "0.1.0"
description = ""
authors = ["Author Name <author@example.com>"]
# readme = "README.md"
# license = "BSD"
packages = [
{ include = "**/*.[hp]y", from = "src", to = "rosenpass_marzipan" },
{ include = "**/*.sh", from = "src", to = "rosenpass_marzipan" },
#{ include = "**/*.lark", from = "src", to = "rosenpass_marzipan" },
]
[tool.poetry.scripts]
rosenpass-marzipan = 'rosenpass_marzipan:main'
[tool.poetry.dependencies]
python = ">=3.12,<3.13"
hy = "^1.0.0"
lark = "^1.2.2"
hyrule = "^0.8.0"
ipython = "^8.32.0"
click = "^8.1.8"
rich = "^13.9.4"
[tool.poetry.group.dev.dependencies]
poetry = "^2.0.0"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

281
marzipan/src/__init__.py Normal file
View File

@@ -0,0 +1,281 @@
from .util import pkgs, setup_exports, export, rename
from .parser import *
# from rich.console import Console
import click
target_subdir = "target/proverif"
(__all__, export) = setup_exports()
export(setup_exports)
console = pkgs.rich.console.Console()
logger = pkgs.logging.getLogger(__name__)
@click.group()
def main():
pkgs.logging.basicConfig(level=pkgs.logging.DEBUG)
def eprint(*args, **kwargs):
print(*args, **{"file": pkgs.sys.stderr, **kwargs})
def exc(argv, **kwargs):
eprint("$", *argv)
command = pkgs.subprocess.run(argv, **kwargs)
if command.returncode != 0:
logger.error("subprocess with terminated with non-zero return code.")
eprint("", *argv)
exit(command.returncode)
if command.stdout is not None:
return command.stdout.decode("utf-8")
return ""
def exc_piped(argv, **kwargs):
eprint("$", *argv)
return pkgs.subprocess.Popen(argv, **kwargs)
def clean_line(prev_line, line):
line = line.rstrip()
if pkgs.re.match(r"^Warning: identifier \w+ rebound.$", line) or prev_line is None:
return None
return prev_line
def run_proverif(file, extra_args=[]):
params = ["proverif", "-test", *extra_args, file]
logger.debug(params)
process = exc_piped(
params,
stderr=pkgs.subprocess.PIPE,
stdout=pkgs.subprocess.PIPE,
text=True,
bufsize=1,
)
try:
prev_line = None
for line in process.stdout:
cleaned_line = clean_line(prev_line, line)
prev_line = line
if cleaned_line is not None:
yield cleaned_line
if prev_line is not None:
yield prev_line
except Exception as e:
# When does this happen? Should the error even be ignored? Metaverif should probably just abort here, right? --karo
logger.error(f"Proverif generated an exception with {params}: {e}")
exit(1)
finally:
process.stdout.close()
return_code = process.wait()
if return_code != 0:
logger.error(
f"Proverif exited with a non-zero error code {params}: {return_code}"
)
exit(return_code)
def cpp(file, cpp_prep):
logger.debug(f"_cpp: {file}, {cpp_prep}")
file_path = pkgs.pathlib.Path(file)
dirname = file_path.parent
cwd = pkgs.pathlib.Path.cwd()
params = ["cpp", "-P", f"-I{dirname}", file, "-o", cpp_prep]
return exc(params, stderr=pkgs.sys.stderr)
def awk(repo_path, cpp_prep, awk_prep):
params = [
"awk",
"-f",
str(pkgs.os.path.join(repo_path, "marzipan/marzipan.awk")),
cpp_prep,
]
with open(awk_prep, "w") as file:
exc(params, stderr=pkgs.sys.stderr, stdout=file)
file.write("\nprocess main")
def pretty_output_line(prefix, mark, color, text):
content = f"{mark} {text}"
console.print(prefix, style="grey42", end="", no_wrap=True)
console.print(content, style=color)
def pretty_output_init(file_path):
expected = []
descs = []
with open(file_path, "r") as file:
content = file.read()
# Process lemmas first
result = pkgs.re.findall(r"@(lemma)(?=\s+\"([^\"]*)\")", content)
if result:
# The regex only returns lemmas. For lemmas, we always expect the result 'true' from ProVerif.
expected.extend([True for _ in range(len(result))])
descs.extend([e[1] for e in result])
# Then process regular queries
result = pkgs.re.findall(r'@(query|reachable)(?=\s+"[^\"]*")', content)
if result:
# For queries, we expect 'true' from ProVerif, for reachable, we expect 'false'.
expected.extend([e == "@query" for e in result])
reachable_result = pkgs.re.findall(
r'@(query|reachable)\s+"([^\"]*)"', content
)
descs.extend([e[1] for e in reachable_result])
ta = pkgs.time.time()
res = 0
ctr = 0
return (ta, res, ctr, expected, descs)
def pretty_output_step(file_path, line, expected, descs, res, ctr, ta):
tz = pkgs.time.time()
# Output from ProVerif contains a trailing newline, which we do not have in the expected output. Remove it for meaningful matching.
outp_clean_raw = line.rstrip()
if outp_clean_raw == "true":
outp_clean = True
elif outp_clean_raw == "false":
outp_clean = False
else:
outp_clean = outp_clean_raw
if outp_clean == expected[ctr]:
pretty_output_line(f"{int(tz - ta)}s ", "", "green", descs[ctr])
else:
res = 1
pretty_output_line(f"{int(tz - ta)}s ", "", "red", descs[ctr])
ctr += 1
ta = tz
return (res, ctr, ta)
def pretty_output(file_path):
(ta, res, ctr, expected, descs) = pretty_output_init(file_path)
for line in pkgs.sys.stdin:
(res, ctr, ta) = pretty_output_step(
file_path, line, expected, descs, res, ctr, ta
)
def get_target_dir(path, output):
if output is not None and not output == "":
return pkgs.pathlib.Path(output)
else:
return pkgs.os.path.join(path, target_subdir)
@main.command()
@click.option("--output", "output", required=False)
@click.argument("repo_path")
def analyze(repo_path, output):
target_dir = get_target_dir(repo_path, output)
pkgs.os.makedirs(target_dir, exist_ok=True)
entries = []
analysis_dir = pkgs.os.path.join(repo_path, "analysis")
entries.extend(sorted(pkgs.glob.glob(str(analysis_dir) + "/*.entry.mpv")))
with pkgs.concurrent.futures.ProcessPoolExecutor() as executor:
futures = {
executor.submit(metaverif, repo_path, target_dir, entry): entry
for entry in entries
}
for future in pkgs.concurrent.futures.as_completed(futures):
cmd = futures[future]
logger.info(f"Metaverif {cmd} finished.")
print("all processes finished.")
@main.command()
@click.option("--output", "output", required=False)
@click.argument("repo_path")
def clean(repo_path, output):
cleans_failed = 0
target_dir = get_target_dir(repo_path, output)
if pkgs.os.path.isdir(target_dir):
for filename in pkgs.os.listdir(target_dir):
file_path = pkgs.os.path.join(target_dir, filename)
if pkgs.os.path.isfile(file_path) and pkgs.os.path.splitext(file_path)[
1
] in [".pv", ".log"]:
try:
pkgs.os.remove(file_path)
except Exception as e:
print(f"Error deleting {file_path}: {str(e)}")
cleans_failed += 1
if cleans_failed > 0:
print(f"{cleans_failed} could not be deleted.")
exit(1)
def metaverif(repo_path, tmpdir, file):
print(f"Start metaverif on {file}")
# Extract the name using regex
name_match = pkgs.re.search(r"([^/]*)(?=\.mpv)", file)
if name_match:
name = name_match.group(0) # Get the matched name
# Create the file paths
cpp_prep = pkgs.os.path.join(tmpdir, f"{name}.i.pv")
awk_prep = pkgs.os.path.join(tmpdir, f"{name}.o.pv")
# Output the results
print(f"Name: {name}")
print(f"CPP Prep Path: {cpp_prep}")
print(f"AWK Prep Path: {awk_prep}")
cpp(file, cpp_prep)
awk(repo_path, cpp_prep, awk_prep)
log_file = pkgs.os.path.join(tmpdir, f"{name}.log")
ta, res, ctr, expected, descs = pretty_output_init(cpp_prep)
with open(log_file, "a") as log:
generator = run_proverif(awk_prep)
for line in generator:
log.write(line)
# parse-result-line:
match = pkgs.re.search(r"^RESULT .* \b(true|false)\b\.$", line)
if match:
result = match.group(1)
# pretty-output:
res, ctr, ta = pretty_output_step(
cpp_prep, result, expected, descs, res, ctr, ta
)
else:
logger.error(
f"No match found for the filename {file}: extension should be .mpv"
)
exit(1)
@main.command()
@click.argument("file_path")
def parse(file_path):
parse_main(file_path)
if __name__ == "__main__":
main()

104
marzipan/src/analyze.sh Executable file
View File

@@ -0,0 +1,104 @@
#!/usr/bin/env bash
exc() {
echo >&2 "\$" "$@"
"$@"
}
run_proverif() {
local file; file="$1"; shift
local log; log="$1"; shift # intentionally unused
exc rosenpass-marzipan run-proverif "${file}" "${@}"
}
clean_warnings() {
exc rosenpass-marzipan clean-warnings
}
color_red='red'
color_green='green'
color_gray='gray'
color_clear=''
checkmark="✔"
cross="❌"
pretty_output() {
exc rosenpass-marzipan pretty-output "${@}"
}
metaverif() {
local file; file="$1"; shift
local name; name="$(echo "${file}" | grep -Po '[^/]*(?=\.mpv)')"
local cpp_prep; cpp_prep="${tmpdir}/${name}.i.pv"
local awk_prep; awk_prep="${tmpdir}/${name}.o.pv"
exc rosenpass-marzipan cpp ${file} ${cpp_prep}
exc rosenpass-marzipan awk-prep ${cpp_prep} ${awk_prep}
local log; log="${tmpdir}/${name}.log"
{
run_proverif "${awk_prep}" "$@" \
| clean_warnings \
| tee "${log}" \
| exc rosenpass-marzipan parse-result-line \
| pretty_output "${cpp_prep}"
} || {
echo "TODO: Commented out some debug output"
#if ! grep -q "^Verification summary" "${log}"; then
# echo -ne "\033[0\r"
# cat "${log}"
#fi
}
}
analyze() {
mkdir -p "${tmpdir}"
entries=()
readarray -t -O "${#entries[@]}" entries < <(
find analysis -iname '*.entry.mpv' | sort)
local entry
local procs; procs=()
for entry in "${entries[@]}"; do
echo "call metaverif"
# TODO: commented out for testing
#exc rosenpass-marzipan metaverif "${tmpdir}" "${entry}" >&2 & procs+=("$!")
exc rosenpass-marzipan metaverif "${tmpdir}" "${entry}" >&2
done
# TODO: commented out for testing
# for entry in "${procs[@]}"; do
# exc wait -f "${entry}"
# done
}
err_usage() {
echo >&1 "USAGE: ${0} analyze PATH"
echo >&1 "The script will cd into PATH and continue there."
exit 1
}
main() {
set -e -o pipefail
local cmd="$1"; shift || err_usage
local dir="$1"; shift || err_usage
cd -- "${dir}"
tmpdir="target/proverif"
echo "call main"
case "${cmd}" in
analyze) analyze ;;
clean_warnings) clean_warnings ;;
*) err_usage
esac
}
# Do not execute main if sourced
(return 0 2>/dev/null) || main "$@"

467
marzipan/src/parser.py Normal file
View File

@@ -0,0 +1,467 @@
import sys
from lark import Lark, Token, Transformer, exceptions, tree
# taken from Page 17 in the ProVerif manual
# At the moment, we do not reject a ProVerif model that uses reserved words as identifier,
# because this caused problems with the LARK grammar. We plan to check this in a later
# processing step.
reserved_words = [
"among",
"axiom",
"channel",
"choice",
"clauses",
"const",
"def",
"diff",
"do",
"elimtrue",
"else",
"equation",
"equivalence", # no rule yet (this is CryptoVerif-specific)
"event",
"expand",
"fail",
"for",
"forall",
"foreach",
"free",
"fun",
"get",
"if",
"implementation", # no rule yet (this is CryptoVerif-specific)
"in",
"inj-event",
"insert",
"lemma",
"let",
"letfun",
"letproba",
"new",
"noninterf",
"noselect",
"not",
"nounif",
"or",
"otherwise",
"out",
"param",
"phase",
"pred",
"proba",
"process",
"proof",
"public_vars",
"putbegin",
"query",
"reduc",
"restriction",
"secret",
"select",
"set",
"suchthat",
"sync",
"table",
"then",
"type",
"weaksecret",
"yield",
]
ident_regex = (
"/^" + "".join(f"(?!{w}$)" for w in reserved_words) + "[a-zA-Z][a-zA-Z0-9À-ÿ'_]*/"
)
proverif_grammar = Lark(
grammar="""
PROCESS: "process"
start: decl* PROCESS process
YIELD: "yield"
channel: CHANNEL
CHANNEL: "channel"
"""
+ "IDENT: /[a-zA-Z][a-zA-Z0-9À-ÿ'_]*/"
+ """
ZERO: "0"
INFIX: "||"
| "&&"
| "="
| "<>"
| "<="
| ">="
| "<"
| ">"
typeid: channel
| IDENT
_non_empty_seq{x}: x ("," x)*
_maybe_empty_seq{x}: [ _non_empty_seq{x} ]
OPTIONS_FUN_CONST: "data" | "private" | "typeConverter"
OPTIONS_FUN: OPTIONS_FUN_CONST
OPTIONS_CONST: OPTIONS_FUN_CONST
OPTIONS_FREE_REDUC: "private"
OPTIONS_PRED: "memberOptim" | "block"
OPTIONS_PROCESS: "precise"
OPTIONS_QUERY_LEMMA_AXIOM: "noneSat" | "discardSat" | "instantiateSat" | "fullSat" | "noneVerif" | "discardVerif" | "instantiateVerif" | "fullVerif"
OPTIONS_AXIOM: OPTIONS_QUERY_LEMMA_AXIOM
OPTIONS_QUERY_LEMMA: OPTIONS_QUERY_LEMMA_AXIOM | "induction" | "noInduction"
OPTIONS_LEMMA: OPTIONS_QUERY_LEMMA_AXIOM | "maxSubset"
OPTIONS_QUERY: OPTIONS_QUERY_LEMMA_AXIOM | "proveAll"
OPTIONS_QUERY_SECRET: "reachability" | "pv_reachability" | "real_or_random" | "pv_real_or_random" | "/cv_[a-zA-Z0-9À-ÿ'_]*/"
OPTIONS_RESTRICTION: "removeEvents" | "keepEvents" | "keep" # transl_option_lemma_query in pitsyntax.ml
OPTIONS_EQUATION: "convergent" | "linear" # check_equations in pitsyntax.ml
OPTIONS_TYPE: "fixed" | "bounded" # TODO(blipp): complete this. These are only for compatibility with CryptoVerif and are ignored
options{idents}: [ "[" _non_empty_seq{idents} "]" ]
process: ZERO
| YIELD
| IDENT [ "(" _maybe_empty_seq{pterm} ")" ]
| bracketed_process
| piped_process
| replicated_process
| replicated_process_bounds
| sample_process
| if_process
| in_process
| out_process
| let_process
| insert_process
| get_process
| event_process
| phase
| sync
bracketed_process: "(" process ")"
piped_process: process "|" process
replicated_process: "!" process
replicated_process_bounds: "!" IDENT "<=" IDENT process
| "foreach" IDENT "<=" IDENT "do" process
sample_process: "new" IDENT [ "[" _maybe_empty_seq{IDENT} "]" ] ":" typeid [";" process]
| IDENT "<-R" typeid [";" process]
let_process: "let" pattern "=" pterm ["in" process [ "else" process ]]
| IDENT [":" typeid] "<-" pterm [";" process]
| "let" typedecl "suchthat" pterm options{OPTIONS_PROCESS} [ "in" process [ "else" process ] ]
if_process: "if" pterm "then" process [ "else" process ]
in_process: "in" "(" pterm "," pattern ")" options{OPTIONS_PROCESS} [ ";" process ]
get_process: IDENT "(" _maybe_empty_seq{pattern} ")" [ "suchthat" pterm ] options{OPTIONS_PROCESS} [ "in" process [ "else" process ] ]
out_process: "out" "(" pterm "," pterm ")" [ ";" process ]
insert_process: "insert" IDENT "(" _maybe_empty_seq{pterm} ")" [ ";" process ]
event_process: "event" IDENT [ "(" _maybe_empty_seq{pterm} ")" ] [ ";" process ]
term: IDENT
| NAT
| "(" _maybe_empty_seq{term} ")"
| IDENT "(" _maybe_empty_seq{term} ")"
| term ( "+" | "-" ) NAT
| NAT "+" term
| term INFIX term
| "not" "(" term ")"
query: gterm ["public_vars" _non_empty_seq{IDENT}] [";" query]
| "secret" IDENT ["public_vars" _non_empty_seq{IDENT}] options{OPTIONS_QUERY_SECRET} [";" query]
| "putbegin" "event" ":" _non_empty_seq{IDENT} [";" query] // Opportunistically left a space between "event" and ":", ProVerif might not accept it with spaces.
| "putbegin" "inj-event" ":" _non_empty_seq{IDENT} [";" query]
lemma: gterm [";" lemma]
| gterm "for" "{" "public_vars" _non_empty_seq{IDENT} "}" [";" lemma]
| gterm "for" "{" "secret" IDENT [ "public_vars" _non_empty_seq{IDENT}] "[real_or_random]" "}" [";" lemma]
gterm: ident_gterm
| fun_gterm
| choice_gterm
| infix_gterm
| arith_gterm
| arith2_gterm
| event_gterm
| injevent_gterm
| implies_gterm
| paren_gterm
| sample_gterm
| let_gterm
ident_gterm: IDENT
fun_gterm: IDENT "(" _maybe_empty_seq{gterm} ")" ["phase" NAT] ["@" IDENT]
choice_gterm: "choice" "[" gterm "," gterm "]"
infix_gterm: gterm INFIX gterm
arith_gterm: gterm ( "+" | "-" ) NAT
arith2_gterm: NAT "+" gterm
event_gterm: "event" "(" _maybe_empty_seq{gterm} ")" ["@" IDENT]
injevent_gterm: "inj-event" "(" _maybe_empty_seq{gterm} ")" ["@" IDENT]
implies_gterm: gterm "==>" gterm
paren_gterm: "(" _maybe_empty_seq{gterm} ")"
sample_gterm: "new" IDENT [ "[" [ gbinding ] "]" ]
let_gterm: "let" IDENT "=" gterm "in" gterm
gbinding: "!" NAT "=" gterm [";" gbinding]
| IDENT "=" gterm [";" gbinding]
nounifdecl: "let" IDENT "=" gformat "in" nounifdecl
| IDENT ["(" _maybe_empty_seq{gformat} ")" ["phase" NAT]]
gformat: IDENT
| "*" IDENT
| IDENT "(" _maybe_empty_seq{gformat} ")"
| "choice" "[" gformat "," gformat "]"
| "not" "(" _maybe_empty_seq{gformat} ")"
| "new" IDENT [ "[" [ fbinding ] "]" ]
| "let" IDENT "=" gformat "in" gformat
fbinding: "!" NAT "=" gformat [";" fbinding]
| IDENT "=" gformat [";" fbinding]
nounifoption: "hypothesis"
| "conclusion"
| "ignoreAFewTimes"
| "inductionOn" "=" IDENT
| "inductionOn" "=" "{" _non_empty_seq{IDENT} "}"
pterm: IDENT
| NAT
| "(" _maybe_empty_seq{pterm} ")"
| IDENT "(" _maybe_empty_seq{pterm} ")"
| choice_pterm
| pterm ("+" | "-") NAT
| NAT "+" pterm
| pterm INFIX pterm
| not_pterm
| sample_pterm
| if_pterm
| let_pterm
| insert_pterm
| get_pterm
| event_pterm
choice_pterm: "choice[" pterm "," pterm "]"
if_pterm: "if" pterm "then" pterm [ "else" pterm ]
not_pterm: "not" "(" pterm ")"
let_pterm: "let" pattern "=" pterm "in" pterm [ "else" pterm ]
| IDENT [":" typeid] "<-" pterm ";" pterm
| "let" typedecl "suchthat" pterm "in" pterm [ "else" pterm ]
sample_pterm: "new" IDENT [ "[" _maybe_empty_seq{IDENT} "]" ] ":" typeid [";" pterm]
| IDENT "<-R" typeid [";" pterm]
insert_pterm: "insert" IDENT "(" _maybe_empty_seq{pterm} ")" ";" pterm
event_pterm: "event" IDENT [ "(" _maybe_empty_seq{pterm} ")" ] ";" pterm
get_pterm: IDENT "(" _maybe_empty_seq{pattern} ")" [ "suchthat" pterm ] options{OPTIONS_PROCESS} [ "in" pterm [ "else" pterm ] ]
pattern: IDENT [":" typeid]
| "_" [ ":" typeid ]
| NAT
| pattern "+" NAT
| NAT "+" pattern
| "(" _maybe_empty_seq{pattern} ")"
| IDENT "(" _maybe_empty_seq{pattern} ")"
| "=" pterm
mayfailterm: term
| "fail"
mayfailterm_seq: "(" _non_empty_seq{mayfailterm} ")"
typedecl: _non_empty_seq{IDENT} ":" typeid [ "," typedecl ]
failtypedecl: _non_empty_seq{IDENT} ":" typeid [ "or fail" ] [ "," failtypedecl ]
decl: type_decl
| channel_decl
| free_decl
| const_decl
| fun_decl
| letfun_decl
| reduc_decl
| fun_reduc_decl
| equation_decl
| pred_decl
| table_decl
| let_decl
| set_settings_decl
| event_decl
| query_decl
| axiom_decl
| restriction_decl
| lemma_decl
| noninterf_decl
| weaksecret_decl
| not_decl
| select_decl
| noselect_decl
| nounif_decl
| elimtrue_decl
| clauses_decl
| module_decl
#| param_decl
#| proba_decl
#| letproba_decl
#| proof_decl
#| def_decl
#| expand_decl
type_decl: "type" IDENT options{OPTIONS_TYPE} "."
channel_decl: "channel" _non_empty_seq{IDENT} "."
free_decl: "free" _non_empty_seq{IDENT} ":" typeid options{OPTIONS_FREE_REDUC} "."
const_decl: "const" _non_empty_seq{IDENT} ":" typeid options{OPTIONS_FUN_CONST} "."
fun_decl: "fun" IDENT "(" _maybe_empty_seq{typeid} ")" ":" typeid options{OPTIONS_FUN_CONST} "."
letfun_decl: "letfun" IDENT [ "(" [ typedecl ] ")" ] "=" pterm "."
reduc_decl: "reduc" eqlist options{OPTIONS_FREE_REDUC} "."
fun_reduc_decl: "fun" IDENT "(" _maybe_empty_seq{typeid} ")" ":" typeid "reduc" mayfailreduc options{OPTIONS_FUN_CONST} "."
equation_decl: "equation" eqlist options{OPTIONS_EQUATION} "."
pred_decl: "pred" IDENT [ "(" [ _maybe_empty_seq{typeid} ] ")" ] options{OPTIONS_PRED} "."
table_decl: IDENT "(" _maybe_empty_seq{typeid} ")" "."
let_decl: "let" IDENT [ "(" [ typedecl ] ")" ] "=" process "."
BOOL : "true" | "false"
NONE: "none"
FULL: "full"
ALL: "all"
FUNC: IDENT
ignoretype_options: BOOL | ALL | NONE | "attacker"
boolean_settings_names: "privateCommOnPublicTerms"
| "rejectChoiceTrueFalse"
| "rejectNoSimplif"
| "allowDiffPatterns"
| "inductionQueries"
| "inductionLemmas"
| "movenew"
| "movelet"
| "stopTerm"
| "removeEventsForLemma"
| "simpEqAll"
| "eqInNames"
| "preciseLetExpand"
| "expandSimplifyIfCst"
| "featureFuns"
| "featureNames"
| "featurePredicates"
| "featureEvents"
| "featureTables"
| "featureDepth"
| "featureWidth"
| "simplifyDerivation"
| "abbreviateDerivation"
| "explainDerivation"
| "unifyDerivation"
| "reconstructDerivation"
| "displayDerivation"
| "traceBacktracking"
| "interactiveSwapping"
| "color"
| "verboseLemmas"
| "abbreviateClauses"
| "removeUselessClausesBeforeDisplay"
| "verboseEq"
| "verboseDestructors"
| "verboseTerm"
| "verboseStatistics"
| "verboseRules"
| "verboseBase"
| "verboseRedundant"
| "verboseCompleted"
| "verboseGoalReachable"
_decl_pair{name, value}: "set" name "=" value "."
set_settings_boolean_decl: _decl_pair{boolean_settings_names, BOOL}
ignore_types_values: BOOL | "all" | "none" | "attacker"
simplify_process_values: BOOL | "interactive"
precise_actions_values: BOOL | "trueWithoutArgsInNames"
redundant_hyp_elim_values: BOOL | "beginOnly"
reconstruct_trace_values: BOOL | "n"
attacker_values: "active" | "passive"
key_compromise_values: "none" | "approx" | "strict"
predicates_implementable: "check" | "nocheck"
application_values: "instantiate" | "full" | "none" | "discard"
max_values: "none" | "n"
sel_fun_values: "TermMaxsize" | "Term"| "NounifsetMaxsize" | "Nounifset"
redundancy_elim_values: "best" | "simple" | "no"
nounif_ignore_a_few_times_values: "none" | "auto" | "all"
nounif_ignore_ntimes_values: "n"
trace_display_values: "short" | "long" | "none"
verbose_clauses_values: "none" | "explained" | "short"
set_settings_decl: set_settings_boolean_decl
| _decl_pair{"ignoreTypes", ignore_types_values}
| _decl_pair{"simplifyProcess", simplify_process_values}
| _decl_pair{"preciseActions", precise_actions_values}
| _decl_pair{"redundantHypElim", redundant_hyp_elim_values}
| _decl_pair{"reconstructTrace", reconstruct_trace_values}
| _decl_pair{"attacker", attacker_values}
| _decl_pair{"keyCompromise", key_compromise_values}
| _decl_pair{"predicatesImplementable", predicates_implementable}
| _decl_pair{"saturationApplication", application_values}
| _decl_pair{"verificationApplication", application_values}
| _decl_pair{"maxDepth", max_values}
| _decl_pair{"maxHyp", max_values}
| _decl_pair{"selFun", sel_fun_values}
| _decl_pair{"redundancyElim", redundancy_elim_values}
| _decl_pair{"nounifIgnoreAFewTimes", nounif_ignore_a_few_times_values}
| _decl_pair{"nounifIgnoreNtimes", nounif_ignore_ntimes_values}
| _decl_pair{"traceDisplay", trace_display_values}
| _decl_pair{"verboseClauses", verbose_clauses_values}
| set_strategy
| set_symb_order
_swap_strategy_seq{x}: x ("->" x)*
set_strategy: "set" "swapping" "=" _swap_strategy_seq{TAG} "."
_symb_ord_seq{x}: x (">" x)*
set_symb_order: "set" "symbOrder" "=" _symb_ord_seq{FUNC} "."
event_decl: "event" IDENT ["(" _maybe_empty_seq{typeid} ")"] "."
query_decl: "query" [ typedecl ";"] query options{OPTIONS_QUERY} "."
axiom_decl: "axiom" [ typedecl ";"] lemma options{OPTIONS_AXIOM} "."
restriction_decl: "restriction" [ typedecl ";"] lemma options{OPTIONS_RESTRICTION} "."
lemma_decl: "lemma" [ typedecl ";"] lemma options{OPTIONS_LEMMA} "."
noninterf_decl: [ typedecl ";"] _maybe_empty_seq{nidecl} "."
weaksecret_decl: "weaksecret" IDENT "."
not_decl: "not" [ typedecl ";"] gterm "."
INT: NAT | "-" NAT
select_decl: "select" [ typedecl ";"] nounifdecl [ "/" INT ] [ "[" _non_empty_seq{nounifoption} "]" ] "."
noselect_decl: "noselect" [ typedecl ";"] nounifdecl [ "/" INT ] [ "[" _non_empty_seq{nounifoption} "]" ] "."
nounif_decl: "nounif" [ typedecl ";"] nounifdecl [ "/" INT ] [ "["_non_empty_seq{nounifoption} "]" ] "."
elimtrue_decl: "elimtrue" [ failtypedecl ";" ] term "."
clauses_decl: "clauses" clauses "."
module_decl: "@module" " " IDENT
# TODO: finish defining these (comes from Cryptoverif)
#param_decl: "param" _non_empty_seq{IDENT} options "."
#proba_decl: "proba" IDENT ["(...)"] options "."
#letproba_decl: "letproba" IDENT ["(...)"] "= ..." "."
#proof_decl: "proof" "{" proof "}"
#def_decl: "def" IDENT "(" _maybe_empty_seq{typeid} ")" "{" decl* "}"
#expand_decl: "expand" IDENT "(" _maybe_empty_seq{typeid} ")" "."
nidecl: IDENT [ "among" "(" _non_empty_seq{term} ")" ]
equality: term "=" term
| "let" IDENT "=" term "in" equality
mayfailequality: IDENT mayfailterm_seq "=" mayfailterm
eqlist: [ "forall" typedecl ";" ] equality [ ";" eqlist ]
clause: term
| term "->" term
| term "<->" term
| term "<=>" term
clauses: [ "forall" failtypedecl ";" ] clause [ ";" clauses ]
mayfailreduc: [ "forall" failtypedecl ";" ] mayfailequality [ "otherwise" mayfailreduc ]
NAT: DIGIT+
phase: "phase" NAT [";" process]
TAG: IDENT
sync: "sync" NAT ["[" TAG "]"] [";" process]
COMMENT: /\(\*(\*(?!\))|[^*])*\*\)/
%import common (WORD, DIGIT, NUMBER, WS) // imports from terminal library
%ignore WS // Disregard spaces in text
%ignore COMMENT
""",
debug=True,
# lexer_callbacks={"COMMENT": comments.append},
)
# COMMENT: /\(\*(\*(?!\))|[^*])*\*\)/
# COMMENT: "(*" /(\*(?!\))|[^*])*/ "*)"
# comment: /\(\*(?:(?!\(\*|\*\)).|(?R))*\*\)/
# TODO Open ProVerif compatibility questions
# TODO * does it allow leading zeros for NAT?
# TODO * tag is not defined? is it ident?
# TODO * are spaces between "event" and ":" allowed?
# TODO * spaces between "nat" and "("? "choice" and "["?
def parsertest(input):
parsetree = proverif_grammar.parse(input)
# tree.pydot__tree_to_png(parsetree, name + ".png")
return parsetree
def parse_main(file_path):
with open(file_path, "r") as f:
content = f.read()
# print(content)
parsertest(content)

130
marzipan/src/util.py Normal file
View File

@@ -0,0 +1,130 @@
from typing import Callable, Any, Tuple, List, TypeVar
from types import ModuleType as Module
from importlib import import_module
from dataclasses import dataclass
T = TypeVar('T')
def setup_exports() -> Tuple[List[str], Callable[[T], T]]:
__all__ = []
"""
Helper to provide an export() function with little boilerplate.
```
from marzipan.util import setup_exports
(__all__, export) = setup_exports()
```
"""
def export(what: T) -> T:
match what:
case str():
__all__.append(what)
case object(__name__ = name):
__all__.append(name)
case _:
raise TypeError(
f"Unsupported export type `{what}`: Export is neither `str` nor has it an attribute named `__name__`.")
return what
return (__all__, export)
(__all__, export) = setup_exports()
export(setup_exports)
@export
def rename(name: str) -> Callable[[T], T]:
def rename_impl(v: T) -> T:
v.__name__ = name
return v
return rename_impl
@export
def attempt(fn):
# TODO: Documentation tests
"""
Call a function returning a tuple of (result, exception).
The following example uses safe_call to implement a checked_divide
function that returns None if the division by zero is caught.
```python
try_divide = attempt(lambda a, b: a/b)
def checked_divide(a, b):
match try_divide(a, b):
case (result, None):
return result
case (None, ZeroDivisionError()):
return None
case _:
raise RuntimeError("Unreachable")
assert(checked_divide(1, 0) == None)
assert(checked_divide(0, 1) == 0)
assert(checked_divide(1, 1) == 1)
```
"""
def retfn(*args, **kwargs):
try:
return (fn(*args, **kwargs), None)
except Exception as e:
return (None, e)
retfn.__name__ = f"try_{fn.__name__}"
return retfn
@export
def scoped(fn: Callable[[], Any]) -> Any:
"""
Scoped variable assignment.
Just an alias for `call`. Use as a decorator to immediately call a function,
assigning the return value to the function name.
"""
return fn()
@export
def try_import(name : str) -> Tuple[Module | None, Exception | None]:
return attempt(import_module)(name)
@dataclass(frozen=True)
class Pkgs:
__mod__: Module | None
__prefix__: str | None
def __get__(self, k: str):
return getattr(self, k)
def __getattribute__(self, k: str):
match k:
case "__mod__" | "__prefix__" | "__class__":
# Access the underlying module value
return super().__getattribute__(k)
match self:
case Pkgs(None, None):
# Import package from root
return Pkgs(import_module(k), k)
# Try importing a subpackage
name = f"{self.__prefix__}.{k}"
match try_import(name):
case (child, None):
# Imported subpackage
return Pkgs(child, name)
case (_, ModuleNotFoundError()):
# No such module; access module property instead
return getattr(self.__mod__, k)
case (_, err):
# Unknown error, pass error on
raise err
@scoped
@export
def pkgs() -> Pkgs:
"""
Global package scope.
`pkgs.marzipan` imports the package `marzipan`
"""
return Pkgs(None, None)

265
marzipan/test-gpt-oss-2.py Normal file
View File

@@ -0,0 +1,265 @@
#!/usr/bin/env python3
# Below is a **more “Pythonic”** rewrite of the original AWKtoPython translator.
# The logic is exactly the same the same error messages, line numbers and exit
# codes but the code is organized into small, reusable functions, uses
# `dataclasses`, type hints, `Path.read_text()`, `re.sub()` and other idiomatic
# constructs. It is also easier to read and to extend.
"""
py_awk_translator.py
A linebyline preprocessor that implements the same behaviour as the
original AWK script you posted (handling @module, @alias, @longalias,
privatevariable expansion, @query/@reachable/@lemma checks and tokenwise
alias substitution).
Usage
python3 py_awk_translator.py file1.pv file2.pv
# or
cat file.pv | python3 py_awk_translator.py
"""
from __future__ import annotations
import re
import sys
from dataclasses import dataclass, field
from pathlib import Path
from typing import Dict, Iterable
# ----------------------------------------------------------------------
# Helper utilities
# ----------------------------------------------------------------------
TOKEN_RE = re.compile(r"[0-9A-Za-z_']")
def is_token_char(ch: str) -> bool:
"""Return True if *ch* can be part of an identifier token."""
return bool(TOKEN_RE.fullmatch(ch))
def die(msg: str, fname: str, lineno: int) -> None:
"""Print an error to stderr and exit with status1 (exactly like AWK)."""
sys.stderr.write(f"{fname}:{lineno}: {msg}\n")
sys.exit(1)
# ----------------------------------------------------------------------
# Core translator holds the mutable state that the AWK script kept in
# global variables.
# ----------------------------------------------------------------------
@dataclass
class Translator:
"""Collects state while processing a file linebyline."""
# final output buffer
out: list[str] = field(default_factory=list)
# current @module name (used when expanding "~")
module: str = ""
# simple oneline aliases: name → replacement text
aliases: Dict[str, str] = field(default_factory=dict)
# multiline alias handling
long_name: str = ""
long_value: str = ""
# error flag mirrors the AWK variable `err`
err: int = 0
# ------------------------------------------------------------------
# Public entry point for a single line
# ------------------------------------------------------------------
def process(self, raw: str, fname: str, lineno: int) -> None:
"""Apply all transformation rules to *raw* and store the result."""
line = raw.rstrip("\n") # keep a copy for error messages
original = line # keep the untouched line for later
# --------------------------------------------------------------
# 1⃣ @module
# --------------------------------------------------------------
if line.startswith("@module"):
parts = line.split(maxsplit=1)
self.module = parts[1] if len(parts) > 1 else ""
self.aliases.clear()
line = ""
# --------------------------------------------------------------
# 2⃣ @alias
# --------------------------------------------------------------
elif line.startswith("@alias"):
for token in line.split()[1:]:
if "=" in token:
name, value = token.split("=", 1)
self.aliases[name] = value
line = ""
# --------------------------------------------------------------
# 3⃣ @long-aliasend
# --------------------------------------------------------------
elif line.startswith("@long-alias-end"):
if not self.long_name:
die("Long alias not started", fname, lineno)
# collapse multiple spaces → single space, strip trailing space
self.long_value = re.sub(r" +", " ", self.long_value).strip()
self.aliases[self.long_name] = self.long_value
self.long_name = self.long_value = ""
line = ""
# --------------------------------------------------------------
# 4⃣ @long-alias (start)
# --------------------------------------------------------------
elif line.startswith("@long-alias"):
parts = line.split(maxsplit=1)
self.long_name = parts[1] if len(parts) > 1 else ""
self.long_value = ""
line = ""
# --------------------------------------------------------------
# 5⃣ PRIVATE__ detection (illegal use of "~")
# --------------------------------------------------------------
elif "PRIVATE__" in line:
die(
"Used private variable without ~:\n\n"
f" {lineno} > {original}",
fname,
lineno,
)
# --------------------------------------------------------------
# 6⃣ @query / @reachable / @lemma validation
# --------------------------------------------------------------
elif re.search(r"@(query|reachable|lemma)", line):
if not re.search(r'@(query|reachable|lemma)\s+"[^"]*"', line):
die(
"@query or @reachable statement without parameter:\n\n"
f" {lineno} > {original}",
fname,
lineno,
)
# replace the quoted part with blanks (preserve line length)
m = re.search(r'@(query|reachable|lemma)\s+"[^"]*"', line)
start, end = m.span()
line = line[:start] + " " * (end - start) + line[end:]
# --------------------------------------------------------------
# 7⃣ Expand "~" to the privatevariable prefix
# --------------------------------------------------------------
if "~" in line:
line = line.replace("~", f"PRIVATE__{self.module}__")
# --------------------------------------------------------------
# 8⃣ Tokenwise alias substitution (the long AWK loop)
# --------------------------------------------------------------
line = self._expand_aliases(line)
# --------------------------------------------------------------
# 9⃣ Accumulate a multiline alias, if we are inside one
# --------------------------------------------------------------
if self.long_name:
self.long_value += line + " "
line = "" # the line itself must not appear in output
# --------------------------------------------------------------
# 🔟 Store the (possibly empty) line for final output
# --------------------------------------------------------------
self.out.append(line + "\n")
# ------------------------------------------------------------------
# Helper that implements the tokenwise alias replacement
# ------------------------------------------------------------------
def _expand_aliases(self, text: str) -> str:
"""Replace every wholetoken alias in *text* with its value."""
i = 0
result = ""
while i < len(text):
# a = previous char, c = current char
a = text[i - 1] if i > 0 else ""
c = text[i]
# If we are already inside a token, just move forward
if i > 0 and is_token_char(a):
i += 1
continue
# If the current char does not start a token, skip it
if not is_token_char(c):
i += 1
continue
# ----------------------------------------------------------
# At a token boundary try to match any alias
# ----------------------------------------------------------
matched = False
for name, value in self.aliases.items():
if text.startswith(name, i):
after = text[i + len(name) : i + len(name) + 1]
if is_token_char(after): # name is only a prefix
continue
# Alias matches replace it
result += text[:i] + value
text = text[i + len(name) :] # continue scanning the suffix
i = 0
matched = True
break
if not matched:
i += 1
return result + text
# ------------------------------------------------------------------
# Finalisation
# ------------------------------------------------------------------
def finish(self) -> None:
"""Write the accumulated output to stdout (unless an error occurred)."""
if self.err == 0:
sys.stdout.write("".join(self.out))
# ----------------------------------------------------------------------
# Commandline driver
# ----------------------------------------------------------------------
def _process_path(path: Path, translator: Translator) -> None:
"""Read *path* linebyline and feed it to *translator*."""
for lineno, raw in enumerate(path.read_text(encoding="utf-8").splitlines(True), start=1):
translator.process(raw, str(path), lineno)
def main() -> None:
translator = Translator()
# No file arguments → read from stdin (named "<stdin>")
if len(sys.argv) == 1:
# stdin may contain multiple lines; we treat it as a single “virtual”
# file so that line numbers are still correct.
for lineno, raw in enumerate(sys.stdin, start=1):
translator.process(raw, "<stdin>", lineno)
else:
for name in sys.argv[1:]:
p = Path(name)
if not p.is_file():
sys.stderr.write(f"File not found: {name}\n")
sys.exit(1)
_process_path(p, translator)
translator.finish()
if __name__ == "__main__":
main()
## What makes this version more Pythonic?
# | Aspect | Original style | Refactored style |
# |--------|----------------|------------------|
# | **State handling** | Global variables (`buf`, `module`, …) | `@dataclass Translator` encapsulates all mutable state |
# | **Regularexpression reuse** | Recompiled on every call (`match`, `gsub`) | Compiled once (`TOKEN_RE`) and reused |
# | **String manipulation** | Manual `substr`, concatenation in loops | Slicing, `str.replace`, `re.sub` for clarity |
# | **Loop logic** | `for (i=1; i<length($0); i+=1)` with many manual index tricks | A single `while` loop with earlycontinue guards; the inner aliassearch is a clean `for name, value in self.aliases.items()` |
# | **Error handling** | `print(... > "/dev/stderr")` and `exit(1)` | Dedicated `die()` helper that writes to `stderr` and exits |
# | **File I/O** | Manual `while (getline ...)` in AWK → `for` over `sys.stdin` / `Path.read_text()` | Uses `Path.read_text()` and `enumerate` for line numbers |
# | **Readability** | Mixed AWKstyle comments, oneliner `if` statements | Docstrings, section comments, type hints, and small helper methods |
# | **Extensibility** | Adding a new rule required editing a monolithic block | New rules can be added as separate `elif` blocks or new methods without touching the core loop |
# The script can be saved as `py_awk_translator.py`, made executable (`chmod +x py_awk_translator.py`), and used exactly like the original AWK program while being easier to maintain and understand.

292
marzipan/test-gpt-oss.py Normal file
View File

@@ -0,0 +1,292 @@
#!/usr/bin/env python3
# **Python3 translation of the AWK script**
# Below is a dropin replacement that can be used the same way as the original
# `awk` program (give it one or more file names, or let it read from *stdin*).
# All the logic of the AWK version is kept the only difference is that the
# code is now ordinary, readable Python3.
"""
translate_awk_to_py.py
A linebyline translator for the “@module / @alias / @longalias …”
preprocessor that was originally written in AWK. The behaviour is
identical to the AWK script you posted, including the exact error
messages and exit codes.
Usage
python3 translate_awk_to_py.py file1.pv file2.pv
# or
cat file.pv | python3 translate_awk_to_py.py
The script prints the transformed source to *stdout* and writes any
diagnostic messages to *stderr* (exactly like the AWK version).
"""
import sys
import re
from pathlib import Path
# ----------------------------------------------------------------------
# Helper functions
# ----------------------------------------------------------------------
def istok(ch: str) -> bool:
"""Return True if *ch* is a token character (alnum, '_' or ''')."""
return bool(re.match(r"[0-9a-zA-Z_']", ch))
def error(msg: str, fname: str, lineno: int) -> None:
"""Print an error message to stderr and exit with status 1."""
sys.stderr.write(f"{fname}:{lineno}: {msg}\n")
sys.exit(1)
# ----------------------------------------------------------------------
# Main processing class (keeps the same global state as the AWK script)
# ----------------------------------------------------------------------
class Translator:
def __init__(self):
self.buf = "" # final output buffer
self.module = "" # current @module name
self.err = 0 # error flag (mirrors AWK's)
self.long_alias_name = "" # name of a multiline alias
self.long_alias_value = "" # accumulated value of that alias
self.aliases: dict[str, str] = {} # simple oneline aliases
# ----------------------------------| AWK rule | Python implementation |
# |----------|-----------------------|
# | `BEGIN` block initialise variables | `Translator.__init__` |
# | `@module` line set `module`, clear `aliases` | first `if` in `process_line` |
# | `@alias` line split `name=value` pairs into `aliases` | second `elif` |
# | `@long-alias` / `@long-alias-end` handling | third/fourth `elif` blocks + the `if self.long_alias_name` section |
# | Detection of illegal `PRIVATE__` usage | `elif "PRIVATE__" in orig_line` (the same string that the AWK script would have produced after the `~` replacement) |
# | Validation of `@query|@reachable|@lemma` statements | `elif re.search(r"@(query|reachable|lemma)", …)` |
# | Replacement of `~` with `PRIVATE__<module>__` | `line.replace("~", …)` |
# | Tokenwise alias substitution (the long `for (i=1; …)` loop) | the `while i < len(line): …` loop that restarts from the beginning after each successful replacement |
# | Accumulating the final output in `buf` | `self.buf += line + "\n"` |
# | `END` block print buffer if no error | `Translator.finish()` |
# The script can be saved as `translate_awk_to_py.py`, made executable (`chmod +x translate_awk_to_py.py`) and used exactly like the original AWK program. All error messages, line numbers and exit codes are identical, so any surrounding tooling that expects the AWK behaviour will continue to work.--------------------------------
# Linebyline processing (mirrors the order of the AWK rules)
# ------------------------------------------------------------------
def process_line(self, line: str, fname: str, lineno: int) -> None:
"""Transform *line* according to all the rules."""
# keep the original line for error reporting
orig_line = line.rstrip("\n")
# ------------------------------------------------------------------
# 1) @module
# ------------------------------------------------------------------
if orig_line.startswith("@module"):
parts = orig_line.split()
if len(parts) >= 2:
self.module = parts[1]
else:
self.module = ""
self.aliases.clear()
line = "" # AWK does: $0 = ""
# fall through nothing else on this line matters
# ------------------------------------------------------------------
# 2) @alias
# ------------------------------------------------------------------
elif orig_line.startswith("@alias"):
# everything after the keyword is a list of name=value pairs
for token in orig_line.split()[1:]:
if "=" in token:
name, value = token.split("=", 1)
self.aliases[name] = value
line = ""
# ------------------------------------------------------------------
# 3) @long-alias-end
# ------------------------------------------------------------------
elif orig_line.startswith("@long-alias-end"):
if not self.long_alias_name:
error("Long alias not started", fname, lineno)
# compress multiple spaces to a single space
self.long_alias_value = re.sub(r" +", " ", self.long_alias_value)
self.aliases[self.long_alias_name] = self.long_alias_value.strip()
# reset the temporary variables
self.long_alias_name = ""
self.long_alias_value = ""
line = ""
# ------------------------------------------------------------------
# 4) @long-alias (start of a multiline alias)
# ------------------------------------------------------------------
elif orig_line.startswith("@long-alias"):
parts = orig_line.split()
if len(parts) >= 2:
self.long_alias_name = parts[1]
self.long_alias_value = ""
else:
self.long_alias_name = ""
self.long_alias_value = ""
line = ""
# ------------------------------------------------------------------
# 5) PRIVATE__ detection (illegal use of "~")
# ------------------------------------------------------------------
elif "PRIVATE__" in orig_line:
# The AWK version looks for the literal string PRIVATE__ (which
# appears only after the "~" replacement). We keep the same
# behaviour.
error(
"Used private variable without ~:\n\n"
f" {lineno} > {orig_line}",
fname,
lineno,
)
# ------------------------------------------------------------------
# 6) @query / @reachable / @lemma validation
# ------------------------------------------------------------------
elif re.search(r"@(query|reachable|lemma)", orig_line):
# Must contain a quoted string after the keyword
if not re.search(r'@(query|reachable|lemma)\s+"[^"]*"', orig_line):
error(
"@query or @reachable statement without parameter:\n\n"
f" {lineno} > {orig_line}",
fname,
lineno,
)
# Replace the quoted part with spaces (preserve line length)
m = re.search(r'@(query|reachable|lemma)\s+"[^"]*"', orig_line)
start, end = m.start(), m.end()
pre = orig_line[:start]
mat = orig_line[start:end]
post = orig_line[end:]
mat_spaced = " " * len(mat)
line = pre + mat_spaced + post
# ------------------------------------------------------------------
# 7) Replace "~" with the privatevariable prefix
# ------------------------------------------------------------------
else:
# No special rule matched yet we keep the line asis for now.
line = orig_line
# ------------------------------------------------------------------
# 8) Insert the privatevariable prefix (if any "~" is present)
# ------------------------------------------------------------------
if "~" in line:
line = line.replace("~", f"PRIVATE__{self.module}__")
# ------------------------------------------------------------------
# 9) Alias substitution (tokenwise, exactly like the AWK loop)
# ------------------------------------------------------------------
# The algorithm walks through the line character by character,
# looking for the start of a token. When a token matches a key in
# *self.aliases* it is replaced by the stored value and the scan
# restarts from the beginning of the (now shorter) line.
i = 0
minibuf = ""
while i < len(line):
# a = previous character, c = current character
a = line[i - 1] if i > 0 else ""
c = line[i]
# If we are already inside a token, just move on
if i > 0 and istok(a):
i += 1
continue
# If the current character does NOT start a token, skip it
if not istok(c):
i += 1
continue
# --------------------------------------------------------------
# We are at a token boundary try to match any alias
# --------------------------------------------------------------
matched = False
for alias, value in self.aliases.items():
klen = len(alias)
token = line[i : i + klen]
after = line[i + klen : i + klen + 1] # char after the token
if token != alias:
continue
if istok(after): # alias is only a prefix of a longer token
continue
# ---- alias matches -------------------------------------------------
matched = True
prefix = line[:i] # everything before the token
suffix = line[i + klen :] # everything after the token
minibuf += prefix + value
line = suffix # continue scanning the suffix
i = 0 # restart from the beginning
break
if not matched:
# No alias matched keep the current character and move on
i += 1
# Append whatever is left of the line after the last replacement
line = minibuf + line
# ------------------------------------------------------------------
# 10) If we are inside a multiline alias, accumulate the line
# ------------------------------------------------------------------
if self.long_alias_name:
self.long_alias_value += line + " "
line = "" # the line itself must not appear in the output
# ------------------------------------------------------------------
# 11) Append the (possibly empty) line to the global buffer
# ------------------------------------------------------------------
self.buf += line + "\n"
# ------------------------------------------------------------------
# Final output
# ------------------------------------------------------------------
def finish(self) -> None:
"""Print the accumulated buffer if no error occurred."""
if self.err == 0:
sys.stdout.write(self.buf)
# ----------------------------------------------------------------------
# Entry point
# ----------------------------------------------------------------------
def main() -> None:
translator = Translator()
# If no file name is given we read from stdin (named "<stdin>")
if len(sys.argv) == 1:
translator.process_line(sys.stdin.read(), "<stdin>", 1)
else:
for fname in sys.argv[1:]:
path = Path(fname)
try:
with path.open(encoding="utf-8") as f:
for lineno, raw in enumerate(f, start=1):
translator.process_line(raw, str(path), lineno)
except FileNotFoundError:
sys.stderr.write(f"File not found: {fname}\n")
sys.exit(1)
translator.finish()
if __name__ == "__main__":
main()
### How the Python version mirrors the AWK script
# | AWK rule | Python implementation |
# |----------|-----------------------|
# | `BEGIN` block initialise variables | `Translator.__init__` |
# | `@module` line set `module`, clear `aliases` | first `if` in `process_line` |
# | `@alias` line split `name=value` pairs into `aliases` | second `elif` |
# | `@long-alias` / `@long-alias-end` handling | third/fourth `elif` blocks + the `if self.long_alias_name` section |
# | Detection of illegal `PRIVATE__` usage | `elif "PRIVATE__" in orig_line` (the same string that the AWK script would have produced after the `~` replacement) |
# | Validation of `@query|@reachable|@lemma` statements | `elif re.search(r"@(query|reachable|lemma)", …)` |
# | Replacement of `~` with `PRIVATE__<module>__` | `line.replace("~", …)` |
# | Tokenwise alias substitution (the long `for (i=1; …)` loop) | the `while i < len(line): …` loop that restarts from the beginning after each successful replacement |
# | Accumulating the final output in `buf` | `self.buf += line + "\n"` |
# | `END` block print buffer if no error | `Translator.finish()` |
# The script can be saved as `translate_awk_to_py.py`, made executable (`chmod +x translate_awk_to_py.py`) and used exactly like the original AWK program. All error messages, line numbers and exit codes are identical, so any surrounding tooling that expects the AWK behaviour will continue to work.

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"?> <?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"> <!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;"> <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)"> <g 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;"/> <rect id="ArtBoard1" x="177.165" y="177.165" width="2125.98" height="1687.51" style="fill:none;"/>
<clipPath id="_clip1"> <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> </clipPath>
<g clip-path="url(#_clip1)"> <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)"> <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);"/> <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>

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"?> <?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"> <!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;"> <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)"> <g 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;"/> <rect id="ArtBoard1" x="368.192" y="177.165" width="2962.52" height="2125.98" style="fill:none;"/>
<clipPath id="_clip1"> <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> </clipPath>
<g clip-path="url(#_clip1)"> <g clip-path="url(#_clip1)">
<g transform="matrix(0.990987,0,0,0.996959,368.192,177.165)"> <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)"> <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;"/> <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>
<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)"> <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);"/> <rect x="347.192" y="384.367" width="1575.08" height="57.695" style="fill:rgb(255,229,193);"/>
</g> </g>
@@ -91,9 +94,6 @@
<g transform="matrix(1.1024,0,0,1.21164,9.17461,375.544)"> <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);"/> <rect x="347.192" y="384.367" width="1575.08" height="57.695" style="fill:rgb(253,180,218);"/>
</g> </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)"> <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);"/> <rect x="347.192" y="384.367" width="1575.08" height="57.695" style="fill:rgb(255,229,193);"/>
</g> </g>
@@ -310,7 +310,7 @@
<g transform="matrix(0.990987,0,0,0.996959,400.873,805.267)"> <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 transform="matrix(29.1667,0,0,29.1667,209.923,19.398)">
</g> </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>
<g transform="matrix(0.990987,0,0,0.996959,556.294,805.267)"> <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> <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> <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>
<g transform="matrix(0.990987,0,0,0.996959,1406.03,735.765)"> <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> </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>
<g transform="matrix(0.990987,0,0,0.996959,944.05,805.321)"> <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)"> <g transform="matrix(29.1667,0,0,29.1667,492.12,19.3437)">
@@ -362,9 +362,9 @@
</g> </g>
<g transform="matrix(0.990987,0,0,0.996959,1343.8,805.267)"> <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> <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> </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>
<g transform="matrix(0.990987,0,0,0.996959,1428.98,860.915)"> <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)"> <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> <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>
<g transform="matrix(0.990987,0,0,0.996959,598.806,1534.07)"> <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> </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>
<g transform="matrix(0.990987,0,0,0.996959,589.076,1605.36)"> <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)"> <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> <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>
<g transform="matrix(0.990987,0,0,0.996959,1231.61,1534.18)"> <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> </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>
<g transform="matrix(0.990987,0,0,0.996959,1413.83,1606.73)"> <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> <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> <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>
<g transform="matrix(0.990987,0,0,0.996959,1414.45,1937)"> <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> <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,356.978,15.7199)"> <g transform="matrix(29.1667,0,0,29.1667,332.212,15.727)">
</g> </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>
<g transform="matrix(0.990987,0,0,0.996959,1420.02,1985.2)"> <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)"> <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;"/> <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> </g>
<g transform="matrix(1.11927,0,0,0.265077,-31.9199,146.07)"> <g transform="matrix(1.04736,0,0,0.265077,49.2217,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="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.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;"/> <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>
<g transform="matrix(1.11927,0,0,0.265077,-31.9199,912.386)"> <g transform="matrix(1.04736,0,0,0.265077,49.2217,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="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.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;"/> <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>
<g transform="matrix(1.11927,0,0,0.265077,-31.9199,1569.58)"> <g transform="matrix(1.04736,0,0,0.265077,49.2217,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="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.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;"/> <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>
<g transform="matrix(0.990987,0,0,0.996959,-393.972,-1123.82)"> <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> </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>
<g transform="matrix(0.990987,0,0,0.996959,-477.45,-357.502)"> <g transform="matrix(0.990987,0,0,0.996959,-433.456,-357.502)">
<g transform="matrix(50,0,0,50,2231.1,1491.35)"> <g transform="matrix(50,0,0,50,2155.26,1491.35)">
</g> </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>
<g transform="matrix(0.990987,0,0,0.996959,-393.972,299.694)"> <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> </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>
<g transform="matrix(0.990987,0,0,0.996959,467.587,-208.686)"> <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);"/> <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"?> <?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"> <!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;"> <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)"> <g 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;"/> <rect id="ArtBoard1" x="177.165" y="1977.29" width="2125.98" height="1353.42" style="fill:none;"/>
<clipPath id="_clip1"> <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> </clipPath>
<g clip-path="url(#_clip1)"> <g clip-path="url(#_clip1)">
<g transform="matrix(1.12527,0,0,1.24734,177.165,1977.29)"> <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> <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 transform="matrix(33.3333,0,0,33.3333,1463.43,1766.48)">
</g> </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>
<g transform="matrix(1.12527,0,0,1.24734,-1007.2,213.348)"> <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> <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="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="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="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> <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>
<g transform="matrix(1.12527,0,0,1.24734,-506.344,409.368)"> <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)"> <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;"/> <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>
<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="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>
<g transform="matrix(0.49129,0,0,0.365649,957.741,1782.7)"> <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);"/> <rect x="647.664" y="557.179" width="961.33" height="388.456" style="fill:rgb(255,166,48);"/>
</g> </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);"/> <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);"/> <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>
@@ -151,7 +151,7 @@
<rect x="1454.89" y="2496.4" width="25.344" height="20.909" style="fill:rgb(212,226,247);"/> <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);"/> <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>
<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);"/> <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);"/> <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>
@@ -159,7 +159,7 @@
<rect x="1454.89" y="2496.4" width="25.344" height="20.909" style="fill:rgb(253,180,218);"/> <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);"/> <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>
<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);"/> <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);"/> <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>
@@ -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="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="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="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="1612.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">biscuit</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> <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>
<g transform="matrix(1.12527,0,0,1.24734,4.87963,384.421)"> <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="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="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="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="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="1281px" y="1612.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:25px;">76 + 24 + 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="1612.31px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.333px;">116</text>
<text x="1454.7px" y="1653.98px" 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> <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 transform="matrix(33.3333,0,0,33.3333,1514.7,1766.48)">
</g> </g>
@@ -273,7 +275,7 @@
<text x="1422.64px" y="1612.61px" style="font-family:'Nunito-Regular', 'Nunito';font-size:33.75px;">32</text> <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 transform="matrix(33.75,0,0,33.75,1463.15,1683.44)">
</g> </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>
<g transform="matrix(1.33216,0,0,1.24734,129.333,240.128)"> <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;"/> <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>
<g transform="matrix(0.410953,0,0,0.095385,1594.58,2286.53)"> <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="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>
<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);"/> <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);"/> <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>
<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);"/> <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);"/> <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>
@@ -309,7 +311,7 @@
<g transform="matrix(1.12527,0,0,1.24734,542.396,463.835)"> <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="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="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 transform="matrix(33.3333,0,0,33.3333,1238.74,1570.64)">
</g> </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> <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)"> <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="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="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="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="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> <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

View File

@@ -179,22 +179,25 @@
@techreport{mceliece, @techreport{mceliece,
title = {{C}lassic {M}c{E}liece: conservative code-based cryptography}, title = {{C}lassic {M}c{E}liece: conservative code-based cryptography},
author = {Martin R. Albrecht and Daniel J. Bernstein and Tung Chou and Carlos Cid and Jan Gilcher and Tanja Lange and Varun Maram and Ingo von Maurich and Rafael Misoczki and Ruben Niederhagen and Kenneth G. Paterson and Edoardo Persichetti and Christiane Peters and Peter Schwabe and Nicolas Sendrier and Jakub Szefer and Cen Jung Tjhai and Martin Tomlinson and Wen Wang}, author = {Martin R. Albrecht and Daniel J. Bernstein and Tung Chou and Carlos Cid and Jan Gilcher and Tanja Lange and Varun Maram and Ingo von Maurich and Rafael Misoczki and Ruben Niederhagen and Kenneth G. Paterson and Edoardo Persichetti and Christiane Peters and Peter Schwabe and Nicolas Sendrier and Jakub Szefer and Cen Jung Tjhai and Martin Tomlinson and Wen Wang},
year = 2020, year = 2022,
month = 10, month = 10,
day = 10, day = 23,
type = {NIST Post-Quantum Cryptography Round 3 Submission}, type = {NIST Post-Quantum Cryptography Round 4 Submission},
url={https://classic.mceliece.org/nist/mceliece-20201010.pdf}, url = {https://classic.mceliece.org/}
} }
@techreport{kyber, @techreport{kyber,
title={CRYSTALS-Kyber algorithm specifications and supporting documentation}, title = {CRYSTALS-Kyber},
author={Avanzi, Roberto and Bos, Joppe and Ducas, L{\'e}o and Kiltz, Eike and Lepoint, Tancr{\`e}de and Lyubashevsky, Vadim and Schanck, John M and Schwabe, Peter and Seiler, Gregor and Stehl{\'e}, Damien and others}, author = {Roberto Avanzi and Joppe Bos and Léo Ducas and Eike Kiltz and Tancrède Lepoint and
year = 2021, Vadim Lyubashevsky and John M. Schanck and Peter Schwabe and Gregor Seiler and Damien Stehlé},
month = 08, year = 2020,
day = 04, month = 10,
url = {https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf} day = 1,
type = {NIST Post-Quantum Cryptography Selected Algorithm},
url = {https://pq-crystals.org/kyber/}
} }
@misc{SHAKE256, @misc{SHAKE256,
author = "National Institute of Standards and Technology", author = "National Institute of Standards and Technology",
title = "FIPS PUB 202: SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions", title = "FIPS PUB 202: SHA-3 Standard: Permutation-Based Hash and Extendable-Output Functions",
@@ -203,18 +206,3 @@
doi = {10.6028/NIST.FIPS.202} doi = {10.6028/NIST.FIPS.202}
} }
@misc{boneh_shoup_graduate,
title = "A graduate course in applied cryptography",
author = "Dan Boneh and Victor Shoup",
url = "https://toc.cryptobook.us/",
year = {2023},
}
@inproceedings{hmac,
title={Keying hash functions for message authentication},
author={Bellare, Mihir and Canetti, Ran and Krawczyk, Hugo},
booktitle={Annual international cryptology conference},
pages={1--15},
year={1996},
organization={Springer}
}

View File

@@ -21,10 +21,10 @@ abstract: |
\enlargethispage{5mm} \enlargethispage{5mm}
\setupimage{label=img:KeyExchangeProt,width=.9\linewidth} \setupimage{label=img:KeyExchangeProt,width=.9\linewidth}
![Rosenpass Key Exchange Protocol](graphics/rosenpass-wp-key-exchange-protocol.svg) ![Rosenpass Key Exchange Protocol](graphics/rosenpass-wp-key-exchange-protocol-rgb.svg)
\setupimage{label=img:MessageTypes} \setupimage{label=img:MessageTypes}
![Rosenpass Message Types](graphics/rosenpass-wp-message-types.svg) ![Rosenpass Message Types](graphics/rosenpass-wp-message-types-rgb.svg)
\clearpage \clearpage
@@ -68,13 +68,11 @@ All symmetric keys and hash values used in Rosenpass are 32 bytes long.
### Hash {#hash} ### Hash {#hash}
A keyed hash function with one 32-byte input, one variable-size input, and one 32-byte output. As keyed hash function we offer two options that can be configured on a peer-basis, with Blake2b being the default: A keyed hash function with one 32-byte input, one variable-size input, and one 32-byte output. As keyed hash function we offer two options that can be configured on a peer-basis, with Blake2s being the default:
1. an **incorrect** HMAC construction [@rfc_hmac] with BLAKE2b [@rfc_blake2] as the inner hash function. See Sec. \ref{incorrect-hmac} for details. 1. the HMAC construction [@rfc_hmac] with BLAKE2s [@rfc_blake2] as the inner hash function.
2. the SHAKE256 extendable output function (XOF) [@SHAKE256] truncated to a 32-byte output. The result is produced be concatenating the 32-byte input with the variable-size input in this order. 2. the SHAKE256 extendable output function (XOF) [@SHAKE256] truncated to a 32-byte output. The result is produced be concatenating the 32-byte input with the variable-size input in this order.
The use of BLAKE2b is being phased out.
```pseudorust ```pseudorust
hash(key, data) -> key hash(key, data) -> key
``` ```
@@ -100,7 +98,7 @@ XAEAD::dec(key, nonce, ciphertext, additional_data) -> plaintext
### SKEM {#skem} ### SKEM {#skem}
“Key Encapsulation Mechanism” (KEM) is the name of an interface widely used in post-quantum-secure protocols. KEMs can be seen as asymmetric encryption specifically for symmetric keys. Rosenpass uses two different KEMs. SKEM is the key encapsulation mechanism used with the static keypairs in Rosenpass. The public keys of these keypairs are not transmitted over the wire during the protocol. We use Classic McEliece 460896\footnote{The exact Classic McEliece version is from the NIST-Competition, Round 3: \par https://classic.mceliece.org/nist/mceliece-20201010.tar.gz}[@mceliece] which claims to be as hard to break as 192-bit AES. As one of the oldest post-quantum-secure KEMs, it enjoys wide trust among cryptographers, but it has not been chosen for standardization by NIST. Its ciphertexts and secret keys are small (188 bytes and 13568 bytes), and its public keys are large (524160 bytes). This fits our use case: public keys are exchanged out-of-band, and only the small ciphertexts have to be transmitted during the handshake. “Key Encapsulation Mechanism” (KEM) is the name of an interface widely used in post-quantum-secure protocols. KEMs can be seen as asymmetric encryption specifically for symmetric keys. Rosenpass uses two different KEMs. SKEM is the key encapsulation mechanism used with the static keypairs in Rosenpass. The public keys of these keypairs are not transmitted over the wire during the protocol. We use Classic McEliece 460896 [@mceliece] which claims to be as hard to break as 192-bit AES. As one of the oldest post-quantum-secure KEMs, it enjoys wide trust among cryptographers, but it has not been chosen for standardization by NIST. Its ciphertexts and private keys are small (188 bytes and 13568 bytes), and its public keys are large (524160 bytes). This fits our use case: public keys are exchanged out-of-band, and only the small ciphertexts have to be transmitted during the handshake.
```pseudorust ```pseudorust
SKEM::enc(public_key) -> (ciphertext, shared_key) SKEM::enc(public_key) -> (ciphertext, shared_key)
@@ -109,7 +107,7 @@ SKEM::dec(secret_key, ciphertext) -> shared_key
### EKEM ### EKEM
Key encapsulation mechanism used with the ephemeral KEM keypairs in Rosenpass. The public keys of these keypairs need to be transmitted over the wire during the protocol. We use Kyber-512\footnote{The exact Kyber version is from the NIST-Competition, Round 3: \par https://pq-crystals.org/kyber/data/kyber-submission-nist-round3.zip \par https://pq-crystals.org/kyber/data/kyber-specification-round3-20210804.pdf}[@kyber], which has been selected in the NIST post-quantum cryptography competition and claims to be as hard to break as 128-bit AES. Its ciphertexts, public keys, and secret keys are 768, 800, and 1632 bytes long, respectively, providing a good balance for our use case as both a public key and a ciphertext have to be transmitted during the handshake. Key encapsulation mechanism used with the ephemeral KEM keypairs in Rosenpass. The public keys of these keypairs need to be transmitted over the wire during the protocol. We use Kyber-512 [@kyber], which has been selected in the NIST post-quantum cryptography competition and claims to be as hard to break as 128-bit AES. Its ciphertexts, public keys, and private keys are 768, 800, and 1632 bytes long, respectively, providing a good balance for our use case as both a public key and a ciphertext have to be transmitted during the handshake.
```pseudorust ```pseudorust
EKEM::enc(public_key) -> (ciphertext, shared_key) EKEM::enc(public_key) -> (ciphertext, shared_key)
@@ -120,46 +118,7 @@ Using a combination of two KEMs Classic McEliece for static keys and Kyber f
Rosenpass uses libsodium [@libsodium] as cryptographic backend for hash, AEAD, and XAEAD, and liboqs [@liboqs] for the post-quantum-secure KEMs. Rosenpass uses libsodium [@libsodium] as cryptographic backend for hash, AEAD, and XAEAD, and liboqs [@liboqs] for the post-quantum-secure KEMs.
## Protocol Roles {#roles} ## Variables {#variables}
The protocol specifies two roles: initiator and responder.
* initiator The party that starts a handshake.
* responder The party that does not start a handshake.
All Rosenpass instances operate in either mode; the traditional "client"/"server" distinction does not apply to the Rosenpass protocol. We sometimes use the term "server". In these cases, we generally refer to the "Rosenpass Server," as in the application that implements the Rosenpass protocol, not to a server/client distinction.
The initiator is stateful, and directs the handshake process. The responder is stateless for most of the protocol and reacts to the initiator's messages; this is important to protect our protocol against state disruption (protocol level denial of service) attacks. Since the responder does require some state to complete the protocol, this state is moved into an encrypted cookie, called "biscuit".
The number of concurrent responder-role handshakes with another client is unlimited to account for the possibility of an imposter trying to execute a handshake: before completion of said handshake, there is no way to figure out which peer is an imposter and which peer is a legitimate party; any attempt to do so might lead to a state-disruption attack -- denial of service on the protocol level.
There is no particular mechanism to negotiate which party acts as initiator and which acts as responder. At startup and when a key exchange is timer-triggered, Rosenpass will *initiate* a key exchange in initiator mode. At startup of another peer, and when they start a timer-triggered key exchange, the local server will *respond* in responder mode.
Implementations must account for one ongoing initiator-role key exchange and many ongoing responder-role key exchanges. Upon receiving a well-formed InitConf package and successfully completing a responder-role key exchange, implementations should abort any ongoing initiator-role key exchange. Implementations should also use different back-off periods depending on whether the handshake was completed in initiator role or in responder role. The following values are used in the Rust reference implementation:
- Initiator rekey interval: 130s
- Responder rekey interval: 120s
In practice these delays cause participants to take turns acting as initiator and acting as responder, since the ten-second difference is usually enough for the handshake with switched roles to complete before the old initiator's rekey timer goes to zero.
## Packages {#packages}
The packages, their contents, and their type IDs are graphically represented in Fig. \ref{img:MessageTypes}. Their purposes are:
* \textbf{Envelope} This is not a package on its own; it is the envelope all the other packages are put into.
* \textbf{InitHello} First package of the handshake, from initiator to responder.
* \textbf{RespHello} Second package of the handshake, from responder to initiator.
* \textbf{InitConf} Third package of the handshake, from initiator to responder.
* \textbf{EmptyData} Empty payload package. Used as acknowledgment to abort data retransmission (see Secs. \ref{payload-keys}, \ref{packet-loss}, and function `enter_live()` in Sec. \ref{fn:enter_live}).
* \textbf{Data} Transmission of actual payload data is not used in Rosenpass, but the package is still specified since it is part of WireGuard (see Sec. \ref{payload-keys} and function `enter_live()` in Sec. \ref{fn:enter_live}).
* \textbf{CookieReply} Used for proof-of-IP-ownership-based denial-of-service mitigation (see Sec. \ref{dos-mitigation}).
* \textbf{biscuit} This is not a stand-alone package; instead, it is an encrypted fragment present in \textbf{RespHello} and \textbf{InitConf}.
## Endianness {#endianess}
Unless otherwise specified, all integer values in the Rosenpass protocol use little-endian encoding.
## Variables and Domain Separators {#variables}
### KEM Keypairs and Ciphertexts ### KEM Keypairs and Ciphertexts
@@ -179,10 +138,10 @@ Rosenpass uses multiple keypairs, ciphertexts, and plaintexts for key encapsulat
These values use a naming scheme consisting of four lower-case characters. The first character indicates whether the key is static `s` or ephemeral `e`. The second character is an `s` or a `p` for secret or public. The third character is always a `k`. The fourth and final character is an `i`, `r`, `m`, or `t`, for `initiator`, `responder`, `mine`, or `theirs`. The initiator's static public key for instance is `spki`. During execution of the protocol, three KEM ciphertexts are produced: `scti`, `sctr`, and `ecti`. These values use a naming scheme consisting of four lower-case characters. The first character indicates whether the key is static `s` or ephemeral `e`. The second character is an `s` or a `p` for secret or public. The third character is always a `k`. The fourth and final character is an `i`, `r`, `m`, or `t`, for `initiator`, `responder`, `mine`, or `theirs`. The initiator's static public key for instance is `spki`. During execution of the protocol, three KEM ciphertexts are produced: `scti`, `sctr`, and `ecti`.
Besides the initiator and responder roles, we define the roles `mine` and `theirs` (`m`/`t`). These are sometimes used in the code when the assignment to initiator or responder roles is flexible. As an example, our static secret key is `sskm`, and the peer's public key is `spkt`. Besides the initiator and responder roles, we define the roles `mine` and `theirs` (`m`/`t`). These are sometimes used in the code when the assignment to initiator or responder roles is flexible. As an example, “this server's” static secret key is `sskm`, and the peer's public key is `spkt`.
### IDs {#peer-ids} ### IDs
Rosenpass uses two types of ID variables. See Figure \ref{img:HashingTree} for how the IDs are calculated. Rosenpass uses two types of ID variables. See Figure \ref{img:HashingTree} for how the IDs are calculated.
@@ -209,103 +168,33 @@ We mix all key material (e.g. `psk`) into the chaining key and derive symmetric
The protocol allows for multiple `osk`s to be generated; each of these keys is labeled with a domain separator to make sure different key usages are always given separate keys. The domain separator for using Rosenpass and WireGuard together is a token generated using the domain separator sequence `["rosenpass.eu", "wireguard psk"]` (see Fig. \ref{img:HashingTree}), as described in \ref{protocol-extension-wireguard-psk}. Third-parties using Rosenpass-keys for other purposes are asked to define their own protocol-extensions. Standard protocol extensions are described in \ref{protocol-extensions}. The protocol allows for multiple `osk`s to be generated; each of these keys is labeled with a domain separator to make sure different key usages are always given separate keys. The domain separator for using Rosenpass and WireGuard together is a token generated using the domain separator sequence `["rosenpass.eu", "wireguard psk"]` (see Fig. \ref{img:HashingTree}), as described in \ref{protocol-extension-wireguard-psk}. Third-parties using Rosenpass-keys for other purposes are asked to define their own protocol-extensions. Standard protocol extensions are described in \ref{protocol-extensions}.
#### Symmetric Keys and Nonces for payload data transmission {#payload-keys}
Keys generated by the Rosenpass key exchange could be used for encryption of payload data if post-quantum security but not hybrid post-quantum security is a goal. Despite this, we do not generally offer payload transmission in the protocol. Instead, the Rosenpass protocol focuses on providing a key exchange, letting external applications handle data transmission. When used with WireGuard, the default use case, this integration also ensures hybrid security.
Still we specify the `Data` and `EmptyData` packets. `Data` is not used, but we still specify it as the same packet is also present in WireGuard. `EmptyData` is used for packet retransmission (see Sec. \ref{packet-loss}).
We also specify how symmetric keys are generated for payload encryption. See Sec. {#live-session-state} and the function `enter_live()` (Sec. \ref{fn:enter_live}).
Keys and nonces for this purpose use the following naming scheme:
\begin{namepartpicture}
\namepart{tx=Transmission,rx=Reception}
\namepart[3.5cm]{k=Key,n=Nonce}
\namepart[7cm]{i=Initiator,r=Responder,m=Mine,t=Theirs}
\begin{scope}[decoration={brace,amplitude=5mm},thick]
\namebraceright{tx}{rx}
\namebraceleft{k}{n}
\namebraceright{k}{n}
\namebraceleft{i}{t}
\end{scope}
\end{namepartpicture}
Note that this scheme is deliberately redundant. For instance, when we are the initiator, then `txki = rxki = txkm = rxkt`. I.e. the initiator's transmission key is the responder's reception key. Since we are the initiator, the initiator's transmission key is also the transmission key of `mine` and the reception key of `theirs`.
There also is a -- now deprecated -- naming scheme:
\begin{namepartpicture}
\namepart{ini=Initiator,res=Responder,hs=Handshake}
\SingleNamePart[3.5cm]{enc}{\textunderscore{}enc}{Encryption}
\begin{scope}[decoration={brace,amplitude=5mm},thick]
\namebraceright{ini}{hs}
\namebraceleft{enc}{enc}
\end{scope}
\end{namepartpicture}
`ini_enc = txki = rxkr` and `res_enc = txkr = rxki`, but this usage is deprecated. The third name `hs_enc` is for encryption as part of the key exchange itself; this name is still in use.
### Labels
Fig. \ref{img:HashingTree} specifies multiple domain separators for various uses.
* `PROTOCOL` (`[0, PROTOCOL]`) The global domain separator; used to generate more domain separators.
Immediately below the global domain separator, you can find:
* `"mac"` Network package integrity verification and pre-authentication with `spkt`. See Sec. \ref{envelope-mac-field}.
* `"cookie"` Denial of Service mitigation through proof-of-ip ownership. See Sec. \ref{dos-mitigation}.
* `"peer id"` Generation of peer ids. See Sec. \ref{peer-ids}.
* `"biscuit additional data"` Storing the protocol state in encrypted cookies so the responder is stateless. See Sec. \ref{hs-state-and-biscuits}.
* `"chaining key init"` Starting point for the execution of the actual rosenpass protocol.
* `"chaining key extract"` Key derivation from the current protocol state, the chaining key. See Sec. \ref{symmetric-keys}.
Below `"chaining key extract"`, there are multiple labels, generating domain separators for deriving keys for various purposes during the execution of the protocol.
It is important to understand that there are two phases for these labels, e.g. applying the `"mix"` label produces a random fixed-size hash value we call `mix`. Not the label `"mix"` but the resulting hash value is used to derive keys during protocol execution. This allows us to use very complicated label structures for key derivation without losing efficiency.
The different labels are:
* `"mix"` Mixing further values into the chaining key; i.e. into the protocol state.
* `"user"` Labels for external uses; these are what generate the `osk` (output shared key). See Sec. \ref{symmetric-keys}.
* `"handshake encryption"` Used when encrypting data using a shared key as part of the protocol execution; e.g. used to generate the `auth` (authentication tag) fields in protocol packages.
* `"initiator handshake encryption"` and `"responder handshake encryption"` For transmission of data after the key-exchange finishes. See Sec. \ref{symmetric-keys}.
## Hashes ## Hashes
Rosenpass uses a cryptographic hash function for multiple purposes: Rosenpass uses a cryptographic hash function for multiple purposes:
* Computing the message authentication code in the message envelope as in WireGuard * Computing the message authentication code in the message envelope as in WireGuard
* Computing the cookie to guard against denial of service attacks. * Computing the cookie to guard against denial of service attacks. This is a feature adopted from WireGuard, but not yet included in the implementation of Rosenpass.
* Computing the peer ID * Computing the peer ID
* Key derivation during and after the handshake * Key derivation during and after the handshake
* Computing the additional data for the biscuit encryption, to provide some privacy for its contents * Computing the additional data for the biscuit encryption, to provide some privacy for its contents
Recall from Section \ref{hash} that rosenpass supports using either BLAKE2b or SHAKE256 as hash function, which can be configured for each peer ID. However, as noted above, rosenpass uses a hash function to compute the peer ID and thus also to access the configuration for a peer ID. This is an issue when receiving an `InitHello`-message, because the correct hash function is not known when a responder receives this message and at the same the responders needs it in order to compute the peer ID and by that also identfy the hash function for that peer. The reference implementation resolves this issue by first trying to derive the peer ID using SHAKE256. If that does not work (i.e. leads to an AEAD decryption error), the reference implementation tries again with BLAKE2b. The reference implementation verifies that the hash function matches the one confgured for the peer. Similarly, if the correct peer ID is not cached when receiving an InitConf message, the reference implementation proceeds in the same manner. Recall from Section \ref{hash} that rosenpass supports using either BLAKE2s or SHAKE256 as hash function, which can be configured for each peer ID. However, as noted above, rosenpass uses a hash function to compute the peer ID and thus also to access the configuration for a peer ID. This is an issue when receiving an `InitHello`-message, because the correct hash function is not known when a responder receives this message and at the same the responders needs it in order to compute the peer ID and by that also identfy the hash function for that peer. The reference implementation resolves this issue by first trying to derive the peer ID using SHAKE256. If that does not work (i.e. leads to an AEAD decryption error), the reference implementation tries again with BLAKE2s. The reference implementation verifies that the hash function matches the one confgured for the peer. Similarly, if the correct peer ID is not cached when receiving an InitConf message, the reference implementation proceeds in the same manner.
Using one hash function for multiple purposes can cause real-world security issues and even key recovery attacks [@oraclecloning]. We choose a tree-based domain separation scheme based on a keyed hash function the previously introduced primitive `hash` to make sure all our hash function calls can be seen as distinct. Using one hash function for multiple purposes can cause real-world security issues and even key recovery attacks [@oraclecloning]. We choose a tree-based domain separation scheme based on a keyed hash function the previously introduced primitive `hash` to make sure all our hash function calls can be seen as distinct.
\setupimage{landscape,fullpage,label=img:HashingTree} \setupimage{landscape,fullpage,label=img:HashingTree}
![Rosenpass Hashing Tree](graphics/rosenpass-wp-hashing-tree.svg) ![Rosenpass Hashing Tree](graphics/rosenpass-wp-hashing-tree-rgb.svg)
Each tree node $\circ{}$ in Figure \ref{img:HashingTree} represents the application of the keyed hash function, using the previous chaining key value as first parameter. The root of the tree is the zero key. In level one, the `PROTOCOL` identifier is applied to the zero key to generate a label unique across cryptographic protocols (unless the same label is deliberately used elsewhere). In level two, purpose identifiers are applied to the protocol label to generate labels to use with each separate hash function application within the Rosenpass protocol. The following layers contain the inputs used in each separate usage of the hash function: Beneath the identifiers `"mac"`, `"cookie"`, `"peer id"`, and `"biscuit additional data"` are hash functions or message authentication codes with a small number of inputs. The second, third, and fourth column in Figure \ref{img:HashingTree} cover the long sequential branch beneath the identifier `"chaining key init"` representing the entire protocol execution, one column for each message processed during the handshake. The leaves beneath `"chaining key extract"` in the left column represent pseudo-random labels for use when extracting values from the chaining key during the protocol execution. These values such as `mix >` appear as outputs in the left column, and then as inputs `< mix` in the other three columns. Each tree node $\circ{}$ in Figure \ref{img:HashingTree} represents the application of the keyed hash function, using the previous chaining key value as first parameter. The root of the tree is the zero key. In level one, the `PROTOCOL` identifier is applied to the zero key to generate a label unique across cryptographic protocols (unless the same label is deliberately used elsewhere). In level two, purpose identifiers are applied to the protocol label to generate labels to use with each separate hash function application within the Rosenpass protocol. The following layers contain the inputs used in each separate usage of the hash function: Beneath the identifiers `"mac"`, `"cookie"`, `"peer id"`, and `"biscuit additional data"` are hash functions or message authentication codes with a small number of inputs. The second, third, and fourth column in Figure \ref{img:HashingTree} cover the long sequential branch beneath the identifier `"chaining key init"` representing the entire protocol execution, one column for each message processed during the handshake. The leaves beneath `"chaining key extract"` in the left column represent pseudo-random labels for use when extracting values from the chaining key during the protocol execution. These values such as `mix >` appear as outputs in the left column, and then as inputs `< mix` in the other three columns.
The protocol identifier depends on the hash function used with the respective peer is defined as follows if BLAKE2b [@rfc_blake2] is used: The protocol identifier depends on the hash function used with the respective peer is defined as follows if BLAKE2s [@rfc_blake2] is used:
```pseudorust ```pseudorust
PROTOCOL = "Rosenpass v1 mceliece460896 Kyber512 ChaChaPoly1305 BLAKE2s" PROTOCOL = "rosenpass 1 rosenpass.eu aead=chachapoly1305 hash=blake2s ekem=kyber512 skem=mceliece460896 xaead=xchachapoly1305"
```
Note that the domain separator used here maintains that BLAKE2s is used, while in
reality, we use BLAKE2b. The reason for this is an implementation error. Since fixing this would have led to a breaking change in the Rosenpass reference implementation, and all other known implementations of Rosenpass simply reproduced this error, we chose to harmonize the white paper with the implementation instead of fixing the implementation.
If SHAKE256 [@SHAKE256] is used, then `BLAKE2s` is substituted with `SHAKE256`:
```pseudorust
PROTOCOL = "Rosenpass v1 mceliece460896 Kyber512 ChaChaPoly1305 SHAKE256"
``` ```
Since every tree node represents a sequence of `hash` calls, the node beneath `"handshake encryption"` called `hs_enc` can be written as follows: If SHAKE256 [@SHAKE256] is used, `blake2s` is replaced by `shake256` in `PROTOCOL`. Since every tree node represents a sequence of `hash` calls, the node beneath `"handshake encryption"` called `hs_enc` can be written as follows:
```pseudorust ```pseudorust
hs_enc = hash(hash(hash(0, PROTOCOL), "chaining key extract"), "handshake encryption") hs_enc = hash(hash(hash(0, PROTOCOL), "chaining key extract"), "handshake encryption")
@@ -329,7 +218,7 @@ hs_enc = hash(hash(hash(0, PROTOCOL), "chaining key extract"), "handshake encryp
= lhash("chaining key extract", "handshake encryption") = lhash("chaining key extract", "handshake encryption")
``` ```
## Rosenpass Server State ## Server State
### Global ### Global
@@ -353,9 +242,9 @@ For each peer, the server stores:
* `psk` The pre-shared key used with the peer * `psk` The pre-shared key used with the peer
* `spkt` The peer's public key * `spkt` The peer's public key
* `biscuit_used` The `biscuit_no` from the last biscuit accepted for the peer as part of InitConf processing * `biscuit_used` The `biscuit_no` from the last biscuit accepted for the peer as part of InitConf processing
* `hash_function` The hash function, SHAKE256 or BLAKE2b, used with the peer. * `hash_function` The hash function, SHAKE256 or BLAKE2s, used with the peer.
### Handshake State and Biscuits {#hs-state-and-biscuits} ### Handshake State and Biscuits
The initiator stores the following local state for each ongoing handshake: The initiator stores the following local state for each ongoing handshake:
@@ -376,13 +265,9 @@ The responder stores no state. While the responder has access to all of the abov
The biscuit is encrypted with the `XAEAD` primitive and a randomly chosen nonce. The values `sidi` and `sidr` are transmitted publicly as part of InitConf, so they do not need to be present in the biscuit, but they are added to the biscuit's additional data to make sure the correct values are transmitted as part of InitConf. The biscuit is encrypted with the `XAEAD` primitive and a randomly chosen nonce. The values `sidi` and `sidr` are transmitted publicly as part of InitConf, so they do not need to be present in the biscuit, but they are added to the biscuit's additional data to make sure the correct values are transmitted as part of InitConf.
The `biscuit_key` used to encrypt biscuits should be rotated frequently. Implementations should keep two biscuit keys in memory at any given time to avoid having to drop packages when `biscuit_key` is rotated. The Rosenpass reference implementation retires biscuits after five minutes and erases them after ten. The `biscuit_key` used to encrypt biscuits should be rotated every two minutes. Implementations should keep two biscuit keys in memory at any given time to avoid having to drop packages when `biscuit_key` is rotated.
### Live Session State {#live-session-state} ### Live Session State
These variables are used after the handshake terminates for encryption of the \textbf{Data} and \textbf{EmptyData} packages.
\textbf{EmptyData} is used as an acknowledgement package to terminate package retransmission (see Sec. \ref{packet-loss}).
\textbf{Data} would be used for transmission of actual payload, but this feature is currently not specified for Rosenpass. Despite this, we do specify the however as it is also part of WireGuard.
* `ck` The chaining key * `ck` The chaining key
* `sidm` Our session ID (“mine”) * `sidm` Our session ID (“mine”)
@@ -392,13 +277,6 @@ These variables are used after the handshake terminates for encryption of the \t
* `txkt` Peer's transmission key * `txkt` Peer's transmission key
* `txnt` Peer's transmission nonce * `txnt` Peer's transmission nonce
## Protocol Code {#functions}
The main reference for how messages are processed in the Rosenpass protocol can be found in Fig. \ref{img:HandlingCode}. The figure uses Rust-like pseudo code.
\setupimage{landscape,fullpage,label=img:HandlingCode}
![Rosenpass Message Handling Code](graphics/rosenpass-wp-message-handling-code.svg)
## Helper Functions {#functions} ## Helper Functions {#functions}
Given the peer ID, look up the peer and load the peer's variables. Given the peer ID, look up the peer and load the peer's variables.
@@ -469,13 +347,13 @@ Rosenpass is built with KEMs, not with NIKEs (Diffie-Hellman-style operations);
```pseudorust ```pseudorust
fn encaps_and_mix<T: KEM>(pk) { fn encaps_and_mix<T: KEM>(pk) {
let (ct, shk) = T::enc(pk); let (ct, shk) = T::enc(pk);
mix(pk, shk, ct); mix(pk, ct, shk);
ct ct
} }
fn decaps_and_mix<T: KEM>(sk, pk, ct) { fn decaps_and_mix<T: KEM>(sk, pk, ct) {
let shk = T::dec(sk, ct); let shk = T::dec(sk, ct);
mix(pk, shk, ct); mix(pk, ct, shk);
} }
``` ```
@@ -497,40 +375,40 @@ fn store_biscuit() {
"biscuit additional data", "biscuit additional data",
spkr, sidi, sidr); spkr, sidi, sidr);
let ct = XAEAD::enc(k, n, pt, ad); let ct = XAEAD::enc(k, n, pt, ad);
let biscuit_ct = concat(n, ct); let nct = concat(n, ct);
mix(biscuit_ct) mix(nct)
biscuit_ct nct
} }
``` ```
Note that the `mix(biscuit_ct)` call updates the chaining key, but that update does not make it into the biscuit. Therefore, `mix(biscuit_ct)` is reapplied in `load_biscuit`. The responder handshake code also needs to reapply any other operations modifying `ck` after calling `store_biscuit`. The handshake code on the initiator's side also needs to call `mix(biscuit_ct)`. Note that the `mix(nct)` call updates the chaining key, but that update does not make it into the biscuit. Therefore, `mix(nct)` is reapplied in `load_biscuit`. The responder handshake code also needs to reapply any other operations modifying `ck` after calling `store_biscuit`. The handshake code on the initiator's side also needs to call `mix(nct)`.
```pseudorust ```pseudorust
fn load_biscuit(biscuit_ct) { fn load_biscuit(nct) {
// Decrypt the biscuit // Decrypt the biscuit
let k = biscuit_key; let k = biscuit_key;
let concat(n, ct) = biscuit_ct; let (n, ct) = nct;
let ad = lhash( let ad = lhash(
"biscuit additional data", "biscuit additional data",
spkr, sidi, sidr); spkr, sidi, sidr);
let pt : Biscuit = XAEAD::dec(k, n, ct, ad); let pt : Biscuit = XAEAD::dec(k, n, ct, ad);
// Find the peer and apply retransmission protection // Find the peer and apply retransmission protection
lookup_peer(pt.pidi); lookup_peer(pt.peerid);
// In December 2024, the InitConf retransmission mechanism was redesigned // In December 2024, the InitConf retransmission mechanisim was redesigned
// in a backwards-compatible way. See the changelog. // in a backwards-compatible way. See the changelog.
// //
// -- 2024-11-30, Karolin Varner // -- 2024-11-30, Karolin Varner
if (protocol_version!(< "0.3.0")) { if (protocol_version!(< "0.3.0")) {
// Ensure that the biscuit is used only once // Ensure that the biscuit is used only once
assert(pt.biscuit_no >= peer.biscuit_used); assert(pt.biscuit_no <= peer.biscuit_used);
} }
// Restore the chaining key // Restore the chaining key
ck ← pt.ck; ck ← pt.ck;
mix(biscuit_ct); mix(nct);
// Expose the biscuit no, // Expose the biscuit no,
// so the handshake code can differentiate // so the handshake code can differentiate
@@ -539,8 +417,6 @@ fn load_biscuit(biscuit_ct) {
} }
``` ```
\phantomsection\label{fn:enter_live}
Entering the live session is very simple in Rosenpass we just use `extract_key` with dedicated identifiers to derive initiator and responder keys. Entering the live session is very simple in Rosenpass we just use `extract_key` with dedicated identifiers to derive initiator and responder keys.
```pseudorust ```pseudorust
@@ -586,15 +462,13 @@ The responder code handling InitConf needs to deal with the biscuits and package
ICR5 and ICR6 perform biscuit replay protection using the biscuit number. This is not handled in `load_biscuit()` itself because there is the case that `biscuit_no = biscuit_used` which needs to be dealt with for retransmission handling. ICR5 and ICR6 perform biscuit replay protection using the biscuit number. This is not handled in `load_biscuit()` itself because there is the case that `biscuit_no = biscuit_used` which needs to be dealt with for retransmission handling.
### Denial of Service Mitigation and Cookies {#dos-mitigation} ### Denial of Service Mitigation and Cookies
Rosenpass derives its cookie-based DoS mitigation technique for a responder when receiving InitHello messages from WireGuard [@wg]. Rosenpass derives its cookie-based DoS mitigation technique for a responder when receiving InitHello messages from Wireguard [@wg].
**This is currently implemented in the Rosenpass implementation but still considered an experimental feature and not enabled by default.**
When the responder is under load, it may choose to not process further InitHello handshake messages, but instead to respond with a cookie reply message (see Figure \ref{img:MessageTypes}). When the responder is under load, it may choose to not process further InitHello handshake messages, but instead to respond with a cookie reply message (see Figure \ref{img:MessageTypes}).
The sender of the exchange then uses this cookie in order to resend the message and have it accepted the following time by the receiver. The sender of the exchange then uses this cookie in order to resend the message and have it accepted the following time by the reciever.
For an initiator, Rosenpass ignores all messages when under load. For an initiator, Rosenpass ignores all messages when under load.
@@ -609,9 +483,9 @@ cookie_encrypted = XAEAD(lhash("cookie-key", spkm), nonce, cookie_value, mac_pee
where `cookie_secret` is a secret variable that changes every two minutes to a random value. Moreover, `lhash` is always instantiated with SHAKE256 when computing `cookie_value` for compatability reasons. `initiator_host_info` is used to identify the initiator host, and is implementation-specific for the client. This paramaters used to identify the host must be carefully chosen to ensure there is a unique mapping, especially when using IPv4 and IPv6 addresses to identify the host (such as taking care of IPv6 link-local addresses). `cookie_value` is a truncated 16 byte value from the above hash operation. `mac_peer` is the `mac` field of the peer's handshake message to which message is the reply. where `cookie_secret` is a secret variable that changes every two minutes to a random value. Moreover, `lhash` is always instantiated with SHAKE256 when computing `cookie_value` for compatability reasons. `initiator_host_info` is used to identify the initiator host, and is implementation-specific for the client. This paramaters used to identify the host must be carefully chosen to ensure there is a unique mapping, especially when using IPv4 and IPv6 addresses to identify the host (such as taking care of IPv6 link-local addresses). `cookie_value` is a truncated 16 byte value from the above hash operation. `mac_peer` is the `mac` field of the peer's handshake message to which message is the reply.
#### Envelope `mac` Field {#envelope-mac-field} #### Envelope `mac` Field
Similar to `mac.1` in WireGuard handshake messages, the `mac` field of a Rosenpass envelope from a handshake packet sender's point of view consists of the following: Similar to `mac.1` in Wireguard handshake messages, the `mac` field of a Rosenpass envelope from a handshake packet sender's point of view consists of the following:
```pseudorust ```pseudorust
mac = lhash("mac", spkt, MAC_WIRE_DATA)[0..16] mac = lhash("mac", spkt, MAC_WIRE_DATA)[0..16]
@@ -634,7 +508,7 @@ else {
} }
``` ```
Here, `seconds_since_update(peer.cookie_value)` is the amount of time in seconds elapsed since last cookie was received, and `COOKIE_WIRE_DATA` are the message contents of all bytes of the retransmitted message prior to the `cookie` field. Here, `seconds_since_update(peer.cookie_value)` is the amount of time in seconds ellapsed since last cookie was received, and `COOKIE_WIRE_DATA` are the message contents of all bytes of the retransmitted message prior to the `cookie` field.
The inititator can use an invalid value for the `cookie` value, when the responder is not under load, and the responder must ignore this value. The inititator can use an invalid value for the `cookie` value, when the responder is not under load, and the responder must ignore this value.
However, when the responder is under load, it may reject InitHello messages with the invalid `cookie` value, and issue a cookie reply message. However, when the responder is under load, it may reject InitHello messages with the invalid `cookie` value, and issue a cookie reply message.
@@ -643,18 +517,18 @@ However, when the responder is under load, it may reject InitHello messages with
This whitepaper does not mandate any specific mechanism to detect responder contention (also mentioned as the under load condition) that would trigger use of the cookie mechanism. This whitepaper does not mandate any specific mechanism to detect responder contention (also mentioned as the under load condition) that would trigger use of the cookie mechanism.
For the reference implemenation, Rosenpass has derived inspiration from the Linux implementation of WireGuard. This implementation suggests that the receiver keep track of the number of messages it is processing at a given time. For the reference implemenation, Rosenpass has derived inspiration from the Linux implementation of Wireguard. This implementation suggests that the reciever keep track of the number of messages it is processing at a given time.
On receiving an incoming message, if the length of the message queue to be processed exceeds a threshold `MAX_QUEUED_INCOMING_HANDSHAKES_THRESHOLD`, the client is considered under load and its state is stored as under load. In addition, the timestamp of this instant when the client was last under load is stored. When recieving subsequent messages, if the client is still in an under load state, the client will check if the time elapsed since the client was last under load has exceeded `LAST_UNDER_LOAD_WINDOW` seconds. If this is the case, the client will update its state to normal operation, and process the message in a normal fashion. On receiving an incoming message, if the length of the message queue to be processed exceeds a threshold `MAX_QUEUED_INCOMING_HANDSHAKES_THRESHOLD`, the client is considered under load and its state is stored as under load. In addition, the timestamp of this instant when the client was last under load is stored. When recieving subsequent messages, if the client is still in an under load state, the client will check if the time ellpased since the client was last under load has exceeded `LAST_UNDER_LOAD_WINDOW` seconds. If this is the case, the client will update its state to normal operation, and process the message in a normal fashion.
Currently, the following constants are derived from the Linux kernel implementation of WireGuard: Currently, the following constants are derived from the Linux kernel implementation of Wireguard:
```pseudorust ```pseudorust
MAX_QUEUED_INCOMING_HANDSHAKES_THRESHOLD = 4096 MAX_QUEUED_INCOMING_HANDSHAKES_THRESHOLD = 4096
LAST_UNDER_LOAD_WINDOW = 1 //seconds LAST_UNDER_LOAD_WINDOW = 1 //seconds
``` ```
## Dealing with Packet Loss {#packet-loss} ## Dealing with Packet Loss
The initiator deals with packet loss by storing the messages it sends to the responder and retransmitting them in randomized, exponentially increasing intervals until they get a response. Receiving RespHello terminates retransmission of InitHello. A Data or EmptyData message serves as acknowledgement of receiving InitConf and terminates its retransmission. The initiator deals with packet loss by storing the messages it sends to the responder and retransmitting them in randomized, exponentially increasing intervals until they get a response. Receiving RespHello terminates retransmission of InitHello. A Data or EmptyData message serves as acknowledgement of receiving InitConf and terminates its retransmission.
@@ -670,40 +544,6 @@ When a responder is under load and it receives an InitHello handshake message, t
When the responder is under load and it recieves an InitConf message, the message will be directly processed without checking the validity of the cookie field. When the responder is under load and it recieves an InitConf message, the message will be directly processed without checking the validity of the cookie field.
## Timers
The Rosenpass protocol uses various timer-triggered events during its operation. This section provides a listing of the timers used and gives the values used in the reference implementation. Other implementations may choose different values.
### Rekeying
Period after which the previous responder starts a new handshake in initiator role; period after which the previous initiator starts a new handshake in initiator role again; period after which a peer rejects an existing shared key.
```pseudorust
REKEY_AFTER_TIME_RESPONDER = 120s
REKEY_AFTER_TIME_INITIATOR = 130s
REJECT_AFTER_TIME = 180s
```
### Biscuits
Period after which the biscuit key is rotated.
```pseudorust
BISCUIT_EPOCH = 300s
```
### Retransmission
Delay after which all retransmission attempts are aborted; exponential backoff factor for retransmission delay; initial (minimum) retransmission delay; final (maximum) retransmission delay; retransmission jitter/variance factor.
```pseudorust
RETRANSMIT_ABORT = 120s
RETRANSMIT_DELAY_GROWTH = 2
RETRANSMIT_DELAY_BEGIN = 500ms
RETRANSMIT_DELAY_END = 10s
RETRANSMIT_DELAY_JITTER = 0.5
```
# Protocol extensions {#protocol-extensions} # Protocol extensions {#protocol-extensions}
The main extension point for the Rosenpass protocol is to generate `osk`s (speak output shared keys, see Sec. \ref{symmetric-keys}) for purposes other than using them to secure WireGuard. By default, the Rosenpass application generates keys for the WireGuard PSK (see \ref{protocol-extension-wireguard-psk}). It would not be impossible to use the keys generated for WireGuard in other use cases, but this might lead to attacks[@oraclecloning]. Specifying a custom protocol extension in practice just means settling on alternative domain separators (see Sec. \ref{symmetric-keys}, Fig. \ref{img:HashingTree}). The main extension point for the Rosenpass protocol is to generate `osk`s (speak output shared keys, see Sec. \ref{symmetric-keys}) for purposes other than using them to secure WireGuard. By default, the Rosenpass application generates keys for the WireGuard PSK (see \ref{protocol-extension-wireguard-psk}). It would not be impossible to use the keys generated for WireGuard in other use cases, but this might lead to attacks[@oraclecloning]. Specifying a custom protocol extension in practice just means settling on alternative domain separators (see Sec. \ref{symmetric-keys}, Fig. \ref{img:HashingTree}).
@@ -811,255 +651,13 @@ fn on_key_timeout() {
} }
``` ```
\begin{minipage}{\textwidth}
\setupimage{label=img:ExtWireguardPSKHybridSecurity,fullpage} \setupimage{label=img:ExtWireguardPSKHybridSecurity,fullpage}
![Rosenpass + WireGuard: Hybrid Security](graphics/rosenpass-wireguard-hybrid-security.pdf) ![Rosenpass + WireGuard: Hybrid Security](graphics/rosenpass-wireguard-hybrid-security.pdf)
\end{minipage}
# Errata {#errata}
## Incorrect HMAC, Hash Function Choice {#incorrect-hmac}
Initially, we chose to use `HMAC+BLAKE2s` for our message authentication code, mostly as a form of cargo cult. WireGuard used BLAKE2s, so we should use it too. BLAKE2 supports a directly keyed mode, so there is not much reason to prefer rolling your own using HMAC from a security standpoint.
It seems likely that WireGuard used HMAC as a heuristic security measure. Message authentication codes, keyed hash functions, had long been constructed by combining HMAC with a hash function; why change that? And there actually is a good reason to use HMAC: Merkle-Damgard constructions have long been the norm for hash functions; their usage was even standardized as MD5 or SHA-2. But Merkle-Damgard constructions are susceptible to extension attacks, where you can calculate `H(message || suffix)` assuming `H(message)` is known to you. HMAC fixes this issue[@boneh_shoup_graduate][@hmac].
But SHA-3 (or SHAKE) and BLAKE2 depart from this long-standing status quo: these hash functions are not based on Merkle-Damgard and they are deliberately designed so they are not susceptible to length extension attacks. On top of this, both schemes provide a keyed mode as a feature of the hash function. At this point it makes much more sense to require a keyed hash function, satisfying the PRF ("pseudo random function") security property and the PRF-SWAP security property[@pqwg] instead of building our own keyed hash from a hash function. HMAC can still be used; if someone wanted to operate Rosenpass with SHA2, the best way to do it would be using `HMAC-SHA512` as the underlying keyed hash. We just also allow using `SHAKE256` without an extra application of HMAC.
Unfortunately, there were a couple of errors in the implementation: we should have used BLAKE2s like WireGuard; instead, we used BLAKE2b. We should have implemented HMAC properly, but we failed to do so. For a fixed-length, 32 byte key and a 32 byte block size, the HMAC function is specified as:
```pseudorust
type Key = [u8; 32];
type HashFunction = Fn(&[u8]) -> Key;
const INNER_PAD: [u8; KEY_LEN] = [0x36u8; KEY_LEN];
const OUTER_PAD: [u8; KEY_LEN] = [0x5Cu8; KEY_LEN];
fn hmac<Hash: HashFunction>(h: Hash, key: Key, data: &[u8]) -> Key {
// `^` denotes XOR, `||` denotes concatenation
let inner_key = key ^ INNER_PAD;
let outer_key = key ^ OUTER_PAD;
let inner_hash = h(inner_key || data);
let outer_hash = h(outer_key || inner_hash);
return outer_hash;
}
```
Instead of implementing this function, we somehow lost track of the fact that HMAC uses concatenation to combine the keys with its data, and instead we built a construction around BLAKE2b in keyed hash mode. That is, we replaced the concatenation with calls to the keyed version of our hash:
```pseudorust
type Key = [u8; 32];
type KeyedHashFunction = Fn(Key, &[u8]) -> Key;
const INNER_PAD: [u8; KEY_LEN] = [0x36u8; KEY_LEN];
const OUTER_PAD: [u8; KEY_LEN] = [0x5Cu8; KEY_LEN];
fn incorrect_rosenpass_hmac<KeyedHash: KeyedHashFunction>(kh: KeyedHashFunction, key: Key, data: &[u8]) -> Key {
// `^` denotes XOR, `||` denotes concatenation
let inner_key = key ^ INNER_PAD;
let outer_key = key ^ OUTER_PAD;
let inner_hash = kh(inner_key, data);
let outer_hash = kh(outer_key, inner_hash);
return outer_hash;
}
```
We therefore add this section explaining our incorrect HMAC usage to harmonize the white paper with the implementation.
To ensure compatibility with the existing versions of Rosenpass, you have to replicate this incorrect variant of HMAC.
Neither mistake is assumed to cause security issues. BLAKE2b is a secure hash function.
There is no reason to assume that our incorrect variant of HMAC-BLAKE2b would be insecure; it is, however, non-standard and needlessly complicates the protocol. We are therefore phasing out usage of HMAC-BLAKE2b in favor of us using SHAKE256 as our keyed hash of choice.
# Changelog # Changelog
### 0.3.x ### 0.3.x
#### 2025-08-10 Applying fixes from Steffen Vogel proof reading of the whitepaper
\vspace{0.5em}
Author: Karolin varner
Issue: [#68](https://github.com/rosenpass/rosenpass/issues/68)
PR: [#664](https://github.com/rosenpass/rosenpass/)
\vspace{0.5em}
Early in the project lifetime, Steffen Vogel successfully implemented a [port of the Rosenpass protocol in [go](https://github.com/cunicu/go-rosenpass).
This implementation has not received an in-depth review from a cryptography implementation perspective, which is why we (the Rosenpass project) are not yet recommending this implementation for production usage;
still, creating this implementation was a great achievement.
During the process, Steffen discovered a large number of possible improvements for the whitepaper. With this update, we are addressing those issues.
This process also ensures that the world knows, that I have ADHD and makes me fix all the little mistakes I could not spot even on the seventh review of the whitepaper.
Changes, in particular:
1. Added a comprehensive reference about labels used in the protocol
2. Added a comprehensive reference about symmetric keys and nonces used for encryption/decryption (`txki`, `txni`, `ini_enc`, `hs_enc`, …)
3. Added a comprehensive reference about packages used.
4. Added an explaining paragraph to section "Live Session State".
5. Added a section about protocol roles.
6. Brief section about endianness.
7. In Fig. 5: Rosenpass Message Handling Code; in IHR5 we replace
``` {=tex}
\begin{quote}
\begin{minted}{pseudorust}
decaps_and_mix<SKEM>(sskr, spkr, ct1)
\end{minted}
\end{quote}
```
by
``` {=tex}
\begin{quote}
\begin{minted}{pseudorust}
decaps_and_mix<SKEM>(sskr, spkr, sctr)
\end{minted}
\end{quote}
```
8. In `load_biscuit()`, there was a typo doing an incorrect comparison between `biscuit_no` and `biscuit_used`. This is not a security issue, as a verbatim implementation would simply have lead to a non-functional implementation. We replace
``` {=tex}
\begin{quote}
\begin{minted}{pseudorust}
assert(pt.biscuit_no <= peer.biscuit_used);
\end{minted}
\end{quote}
```
by
``` {=tex}
\begin{quote}
\begin{minted}{pseudorust}
assert(pt.biscuit_no >= peer.biscuit_used);
\end{minted}
\end{quote}
```
9. In the whitepaper we used the labels `"initiator session encryption"` and `"responder session encryption"`, but in the implementation we used `"initiator handshake encryption"` and `"responder handshake encryption"`. While the whitepaper was correct and the implementation was not, we opt to harmonize the whitepaper with the implementation to avoid a breaking change.
10. The protocol strings used in the whitepaper where different to the ones used in the implementation. We harmonize the two by updating the whitepaper to reflect the protocol identifier used in the implementation. We substitute
``` {=tex}
\begin{quote}
The protocol identifier depends on the hash function used with the respective peer is defined as follows if BLAKE2s is used:
\begin{minted}{pseudorust}
PROTOCOL = "rosenpass 1 rosenpass.eu aead=chachapoly1305 hash=blake2s ekem=kyber512 skem=mceliece460896 xaead=xchachapoly1305"
\end{minted}
If SHAKE256 is used, \texttt{blake2s} is replaced by \texttt{shake256} in \texttt{PROTOCOL}.
\end{quote}
```
with
``` {=tex}
\begin{quote}
The protocol identifier depends on the hash function used with the respective peer is defined as follows if BLAKE2s is used:
\begin{minted}{pseudorust}
PROTOCOL = "Rosenpass v1 mceliece460896 Kyber512 ChaChaPoly1305 BLAKE2s"
\end{minted}
If SHAKE256 is used, then \texttt{BLAKE2s} is substituted with \texttt{SHAKE256}:
\begin{minted}{pseudorust}
PROTOCOL = "Rosenpass v1 mceliece460896 Kyber512 ChaChaPoly1305 SHAKE256"
\end{minted}
\end{quote}
```
11. The whitepaper stated that Rosenpass uses BLAKE2s, while the implementation used BLAKE2b; we update the whitepaper to reflect that reality. The places where this substitution happened are a bit too numerous to count them all here. On top of this, we added the following paragraph to explain the discrepancy between `PROTOCOL` and actual hash function used:
``` {=tex}
\begin{quote}
Note that the domain separator used here maintains that BLAKE2s is used, while in
reality, we use BLAKE2b. The reason for this is an implementation error. Since fixing this would have led to a breaking change in the Rosenpass reference implementation, and all other known implementations of Rosenpass simply reproduced this error, we chose to harmonize the white paper with the implementation instead of fixing the implementation.
\end{quote}
```
12. Added a section to explain and specify our incorrect implementation of HMAC-BLAKE2b.
13. In `encaps_and_mix()`/`decaps_and_mix()` the whitepaper stated that public key, ciphertext, and shared key are mixed into the chaining key in that order, but the implementation used a different order: public key, shared key, and ciphertext (shared key and ciphertext are swapped). We harmonize the white paper with the implementation.
14. In the white paper, in package `RespHello` the field `auth` was indicated to come after `biscuit`, but in the implementation, `auth` came first and `biscuit` was last. The semantics of how fields in Rosenpass messages are processed generally demand that fields are processed in the order they appear in the message, so having `biscuit` first and `auth` second—as was done in the white paper—would be correct; still, we harmonize the white paper with the implementation.
15. Fix a discrepancy with regard to biscuit key life times.
``` {=tex}
\begin{quote}
The \texttt{biscuit\textunderscore{}key} used to encrypt biscuits should be rotated every two minutes. Implementations should keep two biscuit keys in memory at any given time to avoid having to drop packages when \texttt{biscuit\textunderscore{}key} is rotated.
\end{quote}
```
by
``` {=tex}
\begin{quote}
The \texttt{biscuit\textunderscore{}key} used to encrypt biscuits should be rotated frequently. Implementations should keep two biscuit keys in memory at any given time to avoid having to drop packages when \texttt{biscuit\textunderscore{}key} is rotated. The Rosenpass reference implementation retires biscuits after five minutes and erases them after ten.
\end{quote}
```
16. Point out explicitly that we use KEMs from NIST-Competition Round 3. Include links to the competition submission packages. Update citations to reflect the exact specification version.
17. Consistent naming convention. Always use the term `secret key`, never `private key`.
18. `pidiC` -> `pidi_ct`; to make it clearer that this is a cipher text
19. Where we refer to the biscuit ciphertext, we now use the term `biscuit_ct`. Previously we had used various variable names such as `nct` (nonce followed by cipher text) or just plain `biscuit`.
20. In `load_biscuit`, we make it clear that destructuring of `biscuit_ct` destructures a concatenation.
``` {=tex}
\begin{quote}
\begin{minted}{pseudorust}
let (n, ct) = biscuit_ct;
\end{minted}
\end{quote}
```
with
``` {=tex}
\begin{quote}
\begin{minted}{pseudorust}
let concat(n, ct) = biscuit_ct;
\end{minted}
\end{quote}
```
21. Added a section about timers used in the Rosenpass protocol
Additional changes (also motivated by a close review, but not reported by Steffen):
1. Fig. 2 "Rosenpass Message Types", CookieReply package. Renamed the length sum from payload to package.
2. Fig. 2 "Rosenpass Message Types", Envelope package. Renamed the length sum from envelope to package.
3. In `load_biscuit()` fix a naming typo:
``` {=tex}
\begin{quote}
\begin{minted}{pseudorust}
lookup_peer(pt.peerid);
\end{minted}
\end{quote}
```
with
``` {=tex}
\begin{quote}
\begin{minted}{pseudorust}
lookup_peer(pt.pidi);
\end{minted}
\end{quote}
```
4. Remove reference to the proof-of-IP-ownership-based DoS mitigation feature not being implemented. Add a notice, that the feature is currently experimental.
5. Fixed a few typos and capitalization issues
#### 2025-06-24 Specifying the `osk` used for WireGuard as a protocol extension #### 2025-06-24 Specifying the `osk` used for WireGuard as a protocol extension
\vspace{0.5em} \vspace{0.5em}
@@ -1151,7 +749,7 @@ By removing all retransmission handling code from the cryptographic protocol, we
``` {=tex} ``` {=tex}
\begin{quote} \begin{quote}
\begin{minted}{pseudorust} \begin{minted}{pseudorust}
// In December 2024, the InitConf retransmission mechanism was redesigned // In December 2024, the InitConf retransmission mechanisim was redesigned
// in a backwards-compatible way. See the changelog. // in a backwards-compatible way. See the changelog.
// //
// -- 2024-11-30, Karolin Varner // -- 2024-11-30, Karolin Varner
@@ -1179,3 +777,7 @@ PR: [#142](https://github.com/rosenpass/rosenpass/pull/142)
- Added section "Denial of Service Mitigation and Cookies", and modify "Dealing with Packet Loss" for DoS cookie mechanism - Added section "Denial of Service Mitigation and Cookies", and modify "Dealing with Packet Loss" for DoS cookie mechanism
\printbibliography \printbibliography
\setupimage{landscape,fullpage,label=img:HandlingCode}
![Rosenpass Message Handling Code](graphics/rosenpass-wp-message-handling-code-rgb.svg)

View File

@@ -24,7 +24,6 @@ let
"service" "service"
"target" "target"
"toml" "toml"
"zstd" # used for offloaded test vector values
]; ];
# Files to explicitly include # Files to explicitly include
files = [ "to/README.md" ]; files = [ "to/README.md" ];
@@ -72,8 +71,6 @@ rustPlatform.buildRustPackage {
package package
]; ];
configFileVersion = "1";
doCheck = true; doCheck = true;
cargoLock = { cargoLock = {

View File

@@ -1,351 +0,0 @@
[[entries]]
entry_type = "Const"
description = "test setup: peer a secret key"
name = "peer_a_sk"
code_location = "tests/test_vector_crypto_server.rs:95"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:33"
offload = true
[[entries]]
entry_type = "Const"
description = "test setup: peer a public key"
name = "peer_a_pk"
code_location = "tests/test_vector_crypto_server.rs:96"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:33"
offload = true
[[entries]]
entry_type = "Const"
description = "test setup: peer b secret key"
name = "peer_b_sk"
code_location = "tests/test_vector_crypto_server.rs:101"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:33"
offload = true
[[entries]]
entry_type = "Const"
description = "test setup: peer b public key"
name = "peer_b_pk"
code_location = "tests/test_vector_crypto_server.rs:102"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:33"
offload = true
[[entries]]
entry_type = "Const"
description = "pre-shared key"
name = "psk"
value = "Vw7bZ1vyXfZo4D5/633F5IbTOntNFBjZRCWf/0cP3Ss="
code_location = "tests/test_vector_crypto_server.rs:105"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:33"
[[entries]]
entry_type = "Const"
name = "CryptoServer::cookie_secrets[0]"
value = "COU/279CXvyB3mwVxT6fCQ=="
code_location = "tests/test_vector_crypto_server.rs:167"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:69"
[[entries]]
entry_type = "Const"
name = "CryptoServer::cookie_secrets[1]"
value = "5Q+e2O020FTcmBWlAPnWlw=="
code_location = "tests/test_vector_crypto_server.rs:172"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:69"
[[entries]]
entry_type = "Const"
name = "CryptoServer::biscuit_keys[0]"
value = "5h9KZ2KfLP5uNbEdimMNLHUjPFm0L3helyg8QE7pd/E="
code_location = "tests/test_vector_crypto_server.rs:177"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:69"
[[entries]]
entry_type = "Const"
name = "CryptoServer::biscuit_keys[1]"
value = "uwyhSvwuEeXwVUg4+9CBoPWPL0AY+oSVUhFpGpnBaY8="
code_location = "tests/test_vector_crypto_server.rs:179"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:69"
[[entries]]
entry_type = "Const"
name = "CryptoServer::cookie_secrets[0]"
value = "KtKzsfp1NMN3mrln54w0TA=="
code_location = "tests/test_vector_crypto_server.rs:167"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:69"
[[entries]]
entry_type = "Const"
name = "CryptoServer::cookie_secrets[1]"
value = "cc1hSqM+Jhal8AII5NIWLA=="
code_location = "tests/test_vector_crypto_server.rs:172"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:69"
[[entries]]
entry_type = "Const"
name = "CryptoServer::biscuit_keys[0]"
value = "ih8UroUklL5NLdegMFQAEWE6huLEO4HBNL44jpk0VsI="
code_location = "tests/test_vector_crypto_server.rs:177"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:69"
[[entries]]
entry_type = "Const"
name = "CryptoServer::biscuit_keys[1]"
value = "mXEYSvzhz5E9eUskbKJBZlXlYF2N3Q1MwmbGeXmhXoI="
code_location = "tests/test_vector_crypto_server.rs:179"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:69"
[[entries]]
entry_type = "Const"
name = "hs.cookie_value.value"
value = "BryZRk1KR5Gc+AEm0plH1Q=="
code_location = "rosenpass/src/protocol/protocol.rs:3559"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:44"
[[entries]]
entry_type = "Const"
name = "hs.core.sidi"
value = "avpJ6g=="
code_location = "rosenpass/src/protocol/protocol.rs:3572"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:44"
[[entries]]
entry_type = "Const"
name = "hs.eski"
value = "KpIH2rHL5MR1TQosRVTAUhpDGYUfE7FbeDA/VgN2shd0gdwBRkdeTEZqKKdAY+ikmKydZQwNlFQW8WuH8fwknbUt/SCzo2iPbDg22sAuClQFN1sXckmEpDG2G4cqXHqkdVSuwhymt9V0w1lKFotTwNIN9Fo0eKq19twT16DP+nIPwrkDveAAm8OqwNp1iAODI8GuB3aL3Str/HDC7YR8QtuuzJQwfEa8CbihEpk+zZqVCJVZDrlfH6ydcJsahypuWpJQ4RwS+NejEvJirvgKngsgdPkGXyYLzQQhS4qagQDMkklWaxwL5pdSqlB+M/Cbx1iqgXgOp2PEykkOpgpEBKfDoCQxBnIYNEisx9B8XuibzqQiq0qctty3GBUf+peApMdataC6WwGqH1KpQiW8aUufIWFDK8xW56t3/bMV/AIsMWx3XpaxbGOQOgqAmRAxeYh23TeQ6lVturw/aMsV2phXBkgG6iQnzyd9z6Zufgezz3Ui2hdeJ/iCzfG0A7SMWlS8zETM46wExxO5smNh8jCoTzeSMpOeH3GfFyRs44PFybSQHtAbdcpcA+pj2VljGfRzq5U1AjpdbSKm8JO6n2PDOQlXHaNp5wZMTHZeywq/BrRWO0FXU9davLcEqUJ2xkwRIvEo24ae0MSD1SSd0rRK5LFilFWZXpDCkaoHvst87mdMeIBUYppMD+WkSuKun0XMXXSSWNPIvrGKFJlt4yTCNYsdfRBthGEa5sEApYd4jmi49zKbRSGGm/u915gdo0AvsFYa85EZzzBI0wfK3uW0X+YvGSEzwHGOAMaAyJu3tCGHt2tuevqND2lybzkJS+ih80l3jyaBbNmqQzBRt8YZtLg+e0ijH/x8IyGq+efCioRQjeN50sBAJrsSgncVtgoSraWbPLNu9movqQMtLiwGkUaZSqVANtQPQuccOFyzK7XD8zy5V0Bx/We0ijOvlyUPJWW+1LoALiArHhG7xIRQL8oe9RDP1mzPoGQd1MNRvCuePNpRX+JAO7a49vwsqUtsK6iAY5C1WIxc1TAVhrIz2YzKuyOQYJCbtkOTx5EZ+AbCsTa/E7VHJacj5xQXtYpy3NogXpAnI/ubjABhCVKTfNFytwKkQUAR1ZcoqzJlngdFILIFBeTEUJChXpBb3/obCCQOFVWCKaYfuLam34JgWkmKYUoao4ZP68yn7yc1l4lDRswKSgFt6YI31PcWGAbKM9QeKLF1Tso2bQOXlEF8MssCQjhN+PimSYU/A1ANTHEyQMxM+uUGXBAJwViSGSshHpioLkF3nBc2h7FT5Fi6hMU4xqUwsBgkfZKYQ6gMsMIqZjd/gIkbawwGU6VdLNNf4tw1f4ssD3QbKSA9LfsSHHV8YjcJ3vVoIVVd/Pmbe/kV8Ccz0zLPYWxyrrEanTOJwPqzYxBqTOBilVWlEfREu1ddYaccILMGEMdsQ6eBj4ySZYhj24Ajc3R8afR+anR2NNorfgIlF1d7VuW1BQG+loA3UqdO9lE4mwrARoy87LZKagYHUshet/CAYxinr0UlfCKqbEydljslyafPC4x/mmRWqjTNsTAVfZdOc1ESLyQ6fCkZ/ewOMmsVgUZsBPHI5LgE/2qjYhgXxzg72OmYynR4+8EWunEd2JScjTAurTVZBEPDfGq9wvySBeMbyIGgY0yIfJF/oGRI6/oyNoOBMyKff7oCVNzH+UBGPQJE0De7U1wmEqBNIOu6MMx4nFVgdNzA3TyLrhaOT3uDoJMo/9NnnvWDS5xhp9l8URkcVsol12MhmZAhqlhtGIOR72e5Jml6DNkLvYCX49ZKfMGBbnHNk/RhN5k3dccuD+UvIwxR3irMUXt6jITE0RbPCYWX14N4Jlcdz2oxA6U+RXW8ccJ0YQYjsNgmj1xpsnwY8/O6LkiB+Sm/fsJAkRGsKrWeyPKRcNR1uioBr6YpqKa0aHC0meQX7YqKNWZujOQX6ZJb2aMgx4CRJOc/fbqrtgpQy8mEy4JG2dmEPCdYKmY3YTGlpiVb65pLciEtJRIRiCqh4QNmCwtrixM5QgO5Y5gNfX/fXULtbtZdCDgQJ8CKaJNgxosHESp7YfeW+bO2tmmEwSHG+/s4YEEVQZm2OfJ46gLFPIixcTmADwFGOKEgTRofmHFxOUlIH1gXBkuqH0zWp71FqEpAoucjrROw"
code_location = "rosenpass/src/protocol/protocol.rs:3579"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:44"
[[entries]]
entry_type = "Const"
name = "hs.core.ck"
value = "qUtsK6iAY5C1WIxc1TAVhrIz2YzKuyOQYJCbtkOTx5EZ+AbCsTa/E7VHJacj5xQXtYpy3NogXpAnI/ubjABhCVKTfNFytwKkQUAR1ZcoqzJlngdFILIFBeTEUJChXpBb3/obCCQOFVWCKaYfuLam34JgWkmKYUoao4ZP68yn7yc1l4lDRswKSgFt6YI31PcWGAbKM9QeKLF1Tso2bQOXlEF8MssCQjhN+PimSYU/A1ANTHEyQMxM+uUGXBAJwViSGSshHpioLkF3nBc2h7FT5Fi6hMU4xqUwsBgkfZKYQ6gMsMIqZjd/gIkbawwGU6VdLNNf4tw1f4ssD3QbKSA9LfsSHHV8YjcJ3vVoIVVd/Pmbe/kV8Ccz0zLPYWxyrrEanTOJwPqzYxBqTOBilVWlEfREu1ddYaccILMGEMdsQ6eBj4ySZYhj24Ajc3R8afR+anR2NNorfgIlF1d7VuW1BQG+loA3UqdO9lE4mwrARoy87LZKagYHUshet/CAYxinr0UlfCKqbEydljslyafPC4x/mmRWqjTNsTAVfZdOc1ESLyQ6fCkZ/ewOMmsVgUZsBPHI5LgE/2qjYhgXxzg72OmYynR4+8EWunEd2JScjTAurTVZBEPDfGq9wvySBeMbyIGgY0yIfJF/oGRI6/oyNoOBMyKff7oCVNzH+UBGPQJE0De7U1wmEqBNIOu6MMx4nFVgdNzA3TyLrhaOT3uDoJMo/9NnnvWDS5xhp9l8URkcVsol12MhmZAhqlhtGIOR72e5Jml6DNkLvYCX49ZKfMGBbnHNk/RhN5k3dccuD+UvIwxR3irMUXt6jITE0RbPCYWX14N4Jlcdz2oxA6U+RXW8ccJ0YQYjsNgmj1xpsnwY8/O6LkiB+Sm/fsJAkRGsKrWeyPKRcNR1uioBr6YpqKa0aHC0meQX7YqKNWZujOQX6ZJb2aMgx4CRJOc/fbqrtgpQy8mEy4JG2dmEPCdYKmY3YTGlpiVb65pLciEtJRIRiCqh4QNmCwtrixM5QgO5Y5gNfX/fXULtbtZdCDgQJ8CKaJNgxosHESp7YfeW+bM="
code_location = "rosenpass/src/protocol/protocol.rs:3580"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:44"
[[entries]]
entry_type = "Output"
name = "hs.core.ck 1"
value = "z2JAxQ4DPIikqHMSpFDAlmhjSBumhLZatJMrFAP+D1U="
code_location = "rosenpass/src/protocol/protocol.rs:3587"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:44"
[[entries]]
entry_type = "Const"
value = "crPEWzqlCERLJr83BrZupxLUOxWHsYZalisk94tma0k="
code_location = "rosenpass/src/protocol/protocol.rs:3263"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:23"
[[entries]]
entry_type = "Const"
value = "eJXlj5zOJo/Eq85TzOTi7QY8zqWBP0QOOl3PAcpFDYnZyWmuzdpwDZJTbagAP52Md9r+j2vME4SW9UvdvOQo+jbNfuCHytU5K3yxI77srR4aWepM+xPAmxbyIwD4VGjDOQNAjP4Rn8n5L9cCju1tgit7yeM0S4Mx2KDR/Emr8V7gQnERob6LrPJgu6BMWkbZA2+dLVZOsvWPFmmn"
code_location = "rosenpass/src/protocol/protocol.rs:3264"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:23"
[[entries]]
entry_type = "Output"
name = "hs.core.ck 2"
value = "UVoOgm+xgnV9tXlaLrlBHiM8XDAH+4tPm3DTbP9uJzs="
code_location = "rosenpass/src/protocol/protocol.rs:3602"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:44"
[[entries]]
entry_type = "Output"
name = "ih.pidi_ct"
value = "Y3Wstn84+vmUb/a/CtWHFixkdyTFKEaE7joUFM0vBZPehPAeDOXls/u5I1PvViF6"
code_location = "rosenpass/src/protocol/protocol.rs:3615"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:44"
[[entries]]
entry_type = "Output"
name = "hs.core.ck 3"
value = "RTCFQy236fEakHlQn8Pq4+ZbWAg4zvkP5iSp+RU7CpQ="
code_location = "rosenpass/src/protocol/protocol.rs:3616"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:44"
[[entries]]
entry_type = "Output"
name = "hs.core.ck 4"
value = "9bjg2ICzmCeqYMt4ACfX5UMQUde7WgeuI6H+vdQuWck="
code_location = "rosenpass/src/protocol/protocol.rs:3627"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:44"
[[entries]]
entry_type = "Output"
name = "ih.auth"
value = "E+AP6wyOrpngo7vE9Vpkjg=="
code_location = "rosenpass/src/protocol/protocol.rs:3636"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:44"
[[entries]]
entry_type = "Output"
name = "hs.core.ck 5"
value = "MkkapMEoAWftWlVPIcroCCTpqOrMv5TYSff5h8Un/OE="
code_location = "rosenpass/src/protocol/protocol.rs:3637"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:44"
[[entries]]
entry_type = "Output"
description = "message exchanged by the protocol parties"
name = "message"
code_location = "tests/test_vector_crypto_server.rs:136"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:33"
offload = true
[[entries]]
entry_type = "Output"
name = "chaining_key_ihr IHR 4"
value = "z2JAxQ4DPIikqHMSpFDAlmhjSBumhLZatJMrFAP+D1U="
code_location = "rosenpass/src/protocol/protocol.rs:3693"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:84"
[[entries]]
entry_type = "Output"
name = "chaining_key_ihr IHR 5"
value = "UVoOgm+xgnV9tXlaLrlBHiM8XDAH+4tPm3DTbP9uJzs="
code_location = "rosenpass/src/protocol/protocol.rs:3702"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:84"
[[entries]]
entry_type = "Output"
name = "chaining_key_ihr IHR 6"
value = "RTCFQy236fEakHlQn8Pq4+ZbWAg4zvkP5iSp+RU7CpQ="
code_location = "rosenpass/src/protocol/protocol.rs:3714"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:84"
[[entries]]
entry_type = "Output"
name = "chaining_key_ihr IHR 7"
value = "9bjg2ICzmCeqYMt4ACfX5UMQUde7WgeuI6H+vdQuWck="
code_location = "rosenpass/src/protocol/protocol.rs:3724"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:84"
[[entries]]
entry_type = "Output"
name = "chaining_key_ihr IHR 8"
value = "MkkapMEoAWftWlVPIcroCCTpqOrMv5TYSff5h8Un/OE="
code_location = "rosenpass/src/protocol/protocol.rs:3733"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:84"
[[entries]]
entry_type = "Const"
name = "session_id"
value = "+qqWGQ=="
code_location = "rosenpass/src/protocol/protocol.rs:3741"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:84"
[[entries]]
entry_type = "Output"
name = "chaining_key_ihr RHR 3"
value = "rPSnj3sQzMcnolHZJZpDlZ71VcFEtIEENGLWUPyRZws="
code_location = "rosenpass/src/protocol/protocol.rs:3749"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:84"
[[entries]]
entry_type = "Const"
value = "aQGM2N7OhVgSlsa7pEaqdiRZLacxgDhwuEplHORsv3s="
code_location = "rosenpass/src/protocol/protocol.rs:3263"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:23"
[[entries]]
entry_type = "Const"
value = "XIOzetMa7cemW0Qq+vEu1frv9J/MhfFiT68mfbWZrZbzM5AI2lVPLXi75KvjbNC7YrqVG20d2DhZ38g9vjIAG50Lc8LHw3C+tQV2g/lCa4p1XySyQOJUAj/CpBGito8MdcdcxpFzLhCnq0owBSonbgyboxZq/hsX5z+unJu+5UiJYlxpcvu++w954OQiXi9lJpfnC4biY8Mw+8UL5d2UgWp8Yn3y3ZoIKSNGA5hR5/JUg1QStbSvWrhNiiDrfNUR0k2zKmLPXPS1pmaBvSuWQptq3WiA1OtkRsCSrAzjOtyUPWSZyXrttAZ4VJCBkEnd4OZy7eC/mBa3FjwJAfcvVY7i8mU1yDpLtS7MtdAZKMeGn0fQDWOx5z+vM+jbwOxXer79jPKPcdigxjTfARz+SxhfWfqGO5hBh86Ra0F+vgw3KH/YQgTchroWVF8WIwZlNwp6DqvwXBXwRPbtrv+uxmRHT9Oe+ZxJr88Nd1gRtjL0FN6faE1quGDAHWPuAfhFcxa7kdPpHN46cHSC+nzO1gtabPX/b0PM2awmNPB5QPpWoGHzz4HTYV7MYHmC4mxdKU7BT+U3vJd4+vl+7wGQSVxSCwzWHqCjRwOkIDLeiyZss7iz8BnOeErDySbPTMYI/Jv/R7lalOk4+73a1m2m4uZKetXRGEjg8btiKfhFaPZMc9p8xZeJNbsUbqoMl8/R1QGRqXHxzk9tTZW0AHV0t4uLnvHJgu9mR6LApZ99sAJpNcuU9TnsSPfT32DlXWNxtb0DnTQXxLQ7TnSWFYPCYyv7hbfNk8lDdGJqStSvnCe16KYoYjxpExEIfCAFicYhhar5MOpkinJMeyhMhVd2ctVIIIzZXePfZXcdOod2JbYh6+dmp0bnTyussHv9R+qYCCv5AyU/crKSmTbjgyOsmaVpyoTljsozC32uhqZh4M7KBUz1XyPJfD6L4NE1ovCKSfwJepYOqBw0MkdWoXwScyhMWNpVhS8X1aZ/QOZFVIuyYxoiwqpF/y3xV6QYFZmd"
code_location = "rosenpass/src/protocol/protocol.rs:3264"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:23"
[[entries]]
entry_type = "Output"
name = "chaining_key_ihr RHR 4"
value = "WCh3N6kKat+5vvn3WNTxsF9yXGYTQS7hlMUplMac/14="
code_location = "rosenpass/src/protocol/protocol.rs:3764"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:84"
[[entries]]
entry_type = "Const"
value = "Sx7y7DSdVQVHWxR4OOMjyrDr8vuZa7MPX/U8GnPCIHY="
code_location = "rosenpass/src/protocol/protocol.rs:3263"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:23"
[[entries]]
entry_type = "Const"
value = "VwqEOlvdW0Evc1CasejxXQ0dN3mZ4HPMA6ogk3Q7OUzzgCIvbTU8BvBK6d1UH2R7Y5Nd/JdHgag42f5FpjVljX2vlXMk3XxUtREpORxqJ5qUgHejsgJyRO9caOPX/ZXmUZ6vORP7pIulLt2i47ykPNNlWuJmxVJj6NK+lE1BDMIuivHebR31atigV/fFFJui26vy5V9y6xZmnCJm"
code_location = "rosenpass/src/protocol/protocol.rs:3264"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:23"
[[entries]]
entry_type = "Output"
name = "chaining_key_ihr RHR 5"
value = "7gd9Mw7X0ZFmkIkP/JDofflRSAw21F1RjG4HXeMJfTI="
code_location = "rosenpass/src/protocol/protocol.rs:3779"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:84"
[[entries]]
entry_type = "Output"
value = "QyffgzBjc8qAqK18vYsH9TKs9lc6Njg8Q8nANsF/FMMBAAAAAAAAAAAAAADuB30zDtfRkWaQiQ/8kOh9+VFIDDbUXVGMbgdd4wl9Mg=="
code_location = "rosenpass/src/protocol/protocol.rs:3336"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:31"
[[entries]]
entry_type = "Const"
description = "Biscuit key after being cycled"
name = "CryptoServer::biscuit_key[r]"
value = "TIDswcSHh8WKsEsuwMCyldE0zVH8IEjV97ES8v3nHw0="
code_location = "rosenpass/src/protocol/protocol.rs:1430"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:127"
[[entries]]
entry_type = "Const"
value = "iSR2RKOw5VeBICb4b+i8P4QtF8XnJq2N"
code_location = "rosenpass/src/protocol/protocol.rs:3353"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:31"
[[entries]]
entry_type = "Output"
value = "iSR2RKOw5VeBICb4b+i8P4QtF8XnJq2Nq1gaCMgEJ+v1LulDYsjbfU5O0alWStfs4fBy7zS69RkzT8p0m3mVcK0TY9RRdWfxmCzU1U8DP7CbhfZxZHJC9CO8xwIa5r1NjVE1gxJJUEJCTHvtCc3PtFj861c="
code_location = "rosenpass/src/protocol/protocol.rs:3361"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:31"
[[entries]]
entry_type = "Output"
name = "chaining_key_ihr RHR 6"
value = "urS3a0/ufhUxj7bAnafEQ3j7it4q2XOfO+DVCeQJp4U="
code_location = "rosenpass/src/protocol/protocol.rs:3788"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:84"
[[entries]]
entry_type = "Output"
name = "chaining_key_ihr RHR 7"
value = "bbWd4iHXPK6helZLik4t96JKB7yiyw+qcNWbvlDiaQs="
code_location = "rosenpass/src/protocol/protocol.rs:3797"
test_vec_set_code_location = "rosenpass/src/protocol/test_vector_sets.rs:84"
[[entries]]
entry_type = "Output"
description = "message exchanged by the protocol parties"
name = "message"
code_location = "tests/test_vector_crypto_server.rs:136"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:33"
offload = true
[[entries]]
entry_type = "Output"
description = "message exchanged by the protocol parties"
name = "message"
code_location = "tests/test_vector_crypto_server.rs:136"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:33"
offload = true
[[entries]]
entry_type = "Output"
description = "message exchanged by the protocol parties"
name = "message"
code_location = "tests/test_vector_crypto_server.rs:136"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:33"
offload = true
[[entries]]
entry_type = "Output"
description = "final exchanged key"
name = "exchanged_key"
value = "NKG5/vCPc0akKnm5RxctcPigO8fvd0zqJeO2+xbDpq4="
code_location = "tests/test_vector_crypto_server.rs:153"
test_vec_set_code_location = "rosenpass/tests/test_vector_crypto_server.rs:33"

View File

@@ -64,8 +64,6 @@ clap = { workspace = true }
clap_complete = { workspace = true } clap_complete = { workspace = true }
clap_mangen = { workspace = true } clap_mangen = { workspace = true }
mio = { workspace = true } mio = { workspace = true }
signal-hook = { workspace = true }
signal-hook-mio = { workspace = true }
rand = { workspace = true } rand = { workspace = true }
zerocopy = { workspace = true } zerocopy = { workspace = true }
home = { workspace = true } home = { workspace = true }
@@ -78,10 +76,8 @@ heck = { workspace = true, optional = true }
command-fds = { workspace = true, optional = true } command-fds = { workspace = true, optional = true }
rustix = { workspace = true, optional = true } rustix = { workspace = true, optional = true }
uds = { workspace = true, optional = true, features = ["mio_1xx"] } uds = { workspace = true, optional = true, features = ["mio_1xx"] }
signal-hook = { workspace = true, optional = true }
libcrux-test-utils = { workspace = true, optional = true } libcrux-test-utils = { workspace = true, optional = true }
assert_tv = { workspace = true }
base64 = { workspace = true }
serde_json = { workspace = true }
[build-dependencies] [build-dependencies]
anyhow = { workspace = true } anyhow = { workspace = true }
@@ -94,9 +90,9 @@ serial_test = { workspace = true }
procspawn = { workspace = true } procspawn = { workspace = true }
tempfile = { workspace = true } tempfile = { workspace = true }
rustix = { workspace = true } rustix = { workspace = true }
serde_json = { workspace = true }
[features] [features]
#default = ["experiment_libcrux_all"]
experiment_cookie_dos_mitigation = [] experiment_cookie_dos_mitigation = []
experiment_memfd_secret = ["rosenpass-wireguard-broker/experiment_memfd_secret"] experiment_memfd_secret = ["rosenpass-wireguard-broker/experiment_memfd_secret"]
experiment_libcrux_all = ["rosenpass-ciphers/experiment_libcrux_all"] experiment_libcrux_all = ["rosenpass-ciphers/experiment_libcrux_all"]
@@ -113,6 +109,7 @@ experiment_api = [
"rosenpass-util/experiment_file_descriptor_passing", "rosenpass-util/experiment_file_descriptor_passing",
"rosenpass-wireguard-broker/experiment_api", "rosenpass-wireguard-broker/experiment_api",
] ]
internal_signal_handling_for_coverage_reports = ["signal-hook"]
internal_testing = [] internal_testing = []
internal_bin_gen_ipc_msg_types = ["hex", "heck"] internal_bin_gen_ipc_msg_types = ["hex", "heck"]
trace_bench = ["rosenpass-util/trace_bench", "dep:libcrux-test-utils"] trace_bench = ["rosenpass-util/trace_bench", "dep:libcrux-test-utils"]

View File

@@ -1,9 +1,6 @@
use std::{ use std::io::{self, Write};
collections::HashMap, use std::time::{Duration, Instant};
hint::black_box, use std::{collections::HashMap, hint::black_box, ops::DerefMut};
ops::DerefMut,
time::{Duration, Instant},
};
use anyhow::Result; use anyhow::Result;
@@ -12,12 +9,11 @@ use libcrux_test_utils::tracing::{EventType, Trace as _};
use rosenpass_cipher_traits::primitives::Kem; use rosenpass_cipher_traits::primitives::Kem;
use rosenpass_ciphers::StaticKem; use rosenpass_ciphers::StaticKem;
use rosenpass_secret_memory::secret_policy_try_use_memfd_secrets; use rosenpass_secret_memory::secret_policy_try_use_memfd_secrets;
use rosenpass_util::trace_bench::RpEvent; use rosenpass_util::trace_bench::RpEventType;
use rosenpass::protocol::basic_types::{MsgBuf, SPk, SSk, SymKey}; use rosenpass::protocol::basic_types::{MsgBuf, SPk, SSk, SymKey};
use rosenpass::protocol::osk_domain_separator::OskDomainSeparator; use rosenpass::protocol::osk_domain_separator::OskDomainSeparator;
use rosenpass::protocol::{CryptoServer, HandleMsgResult, PeerPtr, ProtocolVersion}; use rosenpass::protocol::{CryptoServer, HandleMsgResult, PeerPtr, ProtocolVersion};
use serde::ser::SerializeStruct;
const ITERATIONS: usize = 100; const ITERATIONS: usize = 100;
@@ -128,30 +124,15 @@ fn main() {
(v02, &v03_with_marker[1..]) (v02, &v03_with_marker[1..])
}; };
// Perform statistical analysis on both trace sections // Perform statistical analysis on both trace sections and write results as JSON
let analysis_v02 = statistical_analysis(trace_v02); write_json_arrays(
let analysis_v03 = statistical_analysis(trace_v03); &mut std::io::stdout(), // Write to standard output
vec![
// Transform analysis results to JSON-encodable data type ("V02", statistical_analysis(trace_v02.to_vec())),
let stats_v02 = analysis_v02 ("V03", statistical_analysis(trace_v03.to_vec())),
.iter() ],
.map(|(label, agg_stat)| JsonAggregateStat { )
protocol_version: "V02", .expect("error writing json data");
label,
agg_stat,
});
let stats_v03 = analysis_v03
.iter()
.map(|(label, agg_stat)| JsonAggregateStat {
protocol_version: "V03",
label,
agg_stat: &agg_stat,
});
// Write results as JSON
let stats_all: Vec<_> = stats_v02.chain(stats_v03).collect();
let stats_json = serde_json::to_string_pretty(&stats_all).expect("error encoding to json");
println!("{stats_json}");
} }
/// Performs a simple statistical analysis: /// Performs a simple statistical analysis:
@@ -159,7 +140,7 @@ fn main() {
/// - extracts durations of spamns /// - extracts durations of spamns
/// - filters out empty bins /// - filters out empty bins
/// - calculates aggregate statistics (mean, std dev) /// - calculates aggregate statistics (mean, std dev)
fn statistical_analysis(trace: &[RpEvent]) -> Vec<(&'static str, AggregateStat<Duration>)> { fn statistical_analysis(trace: Vec<RpEventType>) -> Vec<(&'static str, AggregateStat<Duration>)> {
bin_events(trace) bin_events(trace)
.into_iter() .into_iter()
.map(|(label, spans)| (label, extract_span_durations(label, spans.as_slice()))) .map(|(label, spans)| (label, extract_span_durations(label, spans.as_slice())))
@@ -168,6 +149,44 @@ fn statistical_analysis(trace: &[RpEvent]) -> Vec<(&'static str, AggregateStat<D
.collect() .collect()
} }
/// Takes an iterator of ("protocol_version", iterator_of_stats) pairs and writes them
/// as a single flat JSON array to the provided writer.
///
/// # Arguments
/// * `w` - The writer to output JSON to (e.g., stdout, file).
/// * `item_groups` - An iterator producing tuples `(version, stats): (&'static str, II)`.
/// Here `II` is itself an iterator producing `(label, agg_stat): (&'static str, AggregateStat<Duration>)`,
/// where the label is the label of the span, e.g. "IHI2".
///
/// # Type Parameters
/// * `W` - A type that implements `std::io::Write`.
/// * `II` - An iterator type yielding (`&'static str`, `AggregateStat<Duration>`).
fn write_json_arrays<W: Write, II: IntoIterator<Item = (&'static str, AggregateStat<Duration>)>>(
w: &mut W,
item_groups: impl IntoIterator<Item = (&'static str, II)>,
) -> io::Result<()> {
// Flatten the groups into a single iterator of (protocol_version, label, stats)
let iter = item_groups.into_iter().flat_map(|(version, items)| {
items
.into_iter()
.map(move |(label, agg_stat)| (version, label, agg_stat))
});
let mut delim = ""; // Start with no delimiter
// Start the JSON array
write!(w, "[")?;
// Write the flattened statistics as JSON objects, separated by commas.
for (version, label, agg_stat) in iter {
write!(w, "{delim}")?; // Write delimiter (empty for first item, "," for subsequent)
agg_stat.write_json_ns(label, version, w)?; // Write the JSON object for the stat entry
delim = ","; // Set delimiter for the next iteration
}
// End the JSON array
write!(w, "]")
}
/// Used to group benchmark results in visualizations /// Used to group benchmark results in visualizations
enum RunTimeGroup { enum RunTimeGroup {
/// For particularly long operations. /// For particularly long operations.
@@ -220,13 +239,13 @@ enum StatEntry {
/// Takes a flat list of events and organizes them into a HashMap where keys /// Takes a flat list of events and organizes them into a HashMap where keys
/// are event labels and values are vectors of events with that label. /// are event labels and values are vectors of events with that label.
fn bin_events(events: &[RpEvent]) -> HashMap<&'static str, Vec<RpEvent>> { fn bin_events(events: Vec<RpEventType>) -> HashMap<&'static str, Vec<RpEventType>> {
let mut spans = HashMap::<_, Vec<_>>::new(); let mut spans = HashMap::<_, Vec<_>>::new();
for event in events { for event in events {
// Get the vector for the event's label, or create a new one // Get the vector for the event's label, or create a new one
let spans_for_label = spans.entry(event.label).or_default(); let spans_for_label = spans.entry(event.label).or_default();
// Add the event to the vector // Add the event to the vector
spans_for_label.push(event.clone()); spans_for_label.push(event);
} }
spans spans
} }
@@ -234,7 +253,7 @@ fn bin_events(events: &[RpEvent]) -> HashMap<&'static str, Vec<RpEvent>> {
/// Processes a list of events (assumed to be for the same label), matching /// Processes a list of events (assumed to be for the same label), matching
/// `SpanOpen` and `SpanClose` events to calculate the duration of each span. /// `SpanOpen` and `SpanClose` events to calculate the duration of each span.
/// It handles potentially interleaved spans correctly. /// It handles potentially interleaved spans correctly.
fn extract_span_durations(label: &str, events: &[RpEvent]) -> Vec<Duration> { fn extract_span_durations(label: &str, events: &[RpEventType]) -> Vec<Duration> {
let mut processing_list: Vec<StatEntry> = vec![]; // List to track open spans and final durations let mut processing_list: Vec<StatEntry> = vec![]; // List to track open spans and final durations
for entry in events { for entry in events {
@@ -294,7 +313,6 @@ fn extract_span_durations(label: &str, events: &[RpEvent]) -> Vec<Duration> {
/// Stores the mean, standard deviation, relative standard deviation (sd/mean), /// Stores the mean, standard deviation, relative standard deviation (sd/mean),
/// and the number of samples used for calculation. /// and the number of samples used for calculation.
#[derive(Debug)] #[derive(Debug)]
#[allow(dead_code)]
struct AggregateStat<T> { struct AggregateStat<T> {
/// Average duration. /// Average duration.
mean_duration: T, mean_duration: T,
@@ -344,33 +362,32 @@ impl AggregateStat<Duration> {
sample_size, sample_size,
} }
} }
}
struct JsonAggregateStat<'a, T> { /// Writes the statistics as a JSON object to the provided writer.
agg_stat: &'a AggregateStat<T>, /// Includes metadata like label, protocol_version, OS, architecture, and run time group.
label: &'a str, ///
protocol_version: &'a str, /// # Arguments
} /// * `label` - The specific benchmark/span label.
/// * `protocol_version` - Version of the protocol that is benchmarked.
impl<'a> serde::Serialize for JsonAggregateStat<'a, Duration> { /// * `w` - The output writer (must implement `std::io::Write`).
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn write_json_ns(
where &self,
S: serde::Serializer, label: &str,
{ protocol_version: &str,
let mut stat = serializer.serialize_struct("AggregateStat", 9)?; w: &mut impl io::Write,
stat.serialize_field("name", self.label)?; ) -> io::Result<()> {
stat.serialize_field("unit", "ns/iter")?; // Format the JSON string using measured values and environment constants
stat.serialize_field("value", &self.agg_stat.mean_duration.as_nanos().to_string())?; writeln!(
stat.serialize_field( w,
"range", r#"{{"name":"{name}", "unit":"ns/iter", "value":"{value}", "range":"± {range}", "protocol version":"{protocol_version}", "sample size":"{sample_size}", "operating system":"{os}", "architecture":"{arch}", "run time":"{run_time}"}}"#,
&format!("± {}", self.agg_stat.sd_duration.as_nanos()), name = label, // Benchmark name
)?; value = self.mean_duration.as_nanos(), // Mean duration in nanoseconds
stat.serialize_field("protocol version", self.protocol_version)?; range = self.sd_duration.as_nanos(), // Standard deviation in nanoseconds
stat.serialize_field("sample size", &self.agg_stat.sample_size)?; sample_size = self.sample_size, // Number of samples
stat.serialize_field("operating system", std::env::consts::OS)?; os = std::env::consts::OS, // Operating system
stat.serialize_field("architecture", std::env::consts::ARCH)?; arch = std::env::consts::ARCH, // CPU architecture
stat.serialize_field("run time", &run_time_group(self.label).to_string())?; run_time = run_time_group(label), // Run time group category (long, medium, etc.)
protocol_version = protocol_version // Overall protocol_version (e.g., protocol version)
stat.end() )
} }
} }

View File

@@ -7,20 +7,17 @@ use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSoc
use std::time::{Duration, Instant}; use std::time::{Duration, Instant};
use std::{cell::Cell, fmt::Debug, io, path::PathBuf, slice}; use std::{cell::Cell, fmt::Debug, io, path::PathBuf, slice};
use mio::{Interest, Token};
use signal_hook_mio::v1_0 as signal_hook_mio;
use anyhow::{bail, Context, Result}; use anyhow::{bail, Context, Result};
use derive_builder::Builder; use derive_builder::Builder;
use log::{error, info, warn}; use log::{error, info, warn};
use mio::{Interest, Token};
use zerocopy::AsBytes; use zerocopy::AsBytes;
use rosenpass_util::attempt; use rosenpass_util::attempt;
use rosenpass_util::fmt::debug::NullDebug;
use rosenpass_util::functional::{run, ApplyExt}; use rosenpass_util::functional::{run, ApplyExt};
use rosenpass_util::io::{IoResultKindHintExt, SubstituteForIoErrorKindExt}; use rosenpass_util::io::{IoResultKindHintExt, SubstituteForIoErrorKindExt};
use rosenpass_util::{ use rosenpass_util::{
b64::B64Display, build::ConstructionSite, file::StoreValueB64, result::OkExt, b64::B64Display, build::ConstructionSite, file::StoreValueB64, option::SomeExt, result::OkExt,
}; };
use rosenpass_secret_memory::{Public, Secret}; use rosenpass_secret_memory::{Public, Secret};
@@ -132,7 +129,7 @@ pub struct BrokerStore {
/// The collection of WireGuard brokers. See [Self]. /// The collection of WireGuard brokers. See [Self].
pub store: HashMap< pub store: HashMap<
Public<BROKER_ID_BYTES>, Public<BROKER_ID_BYTES>,
Box<dyn WireguardBrokerMio<Error = anyhow::Error, MioError = anyhow::Error> + Send>, Box<dyn WireguardBrokerMio<Error = anyhow::Error, MioError = anyhow::Error>>,
>, >,
} }
@@ -149,12 +146,12 @@ pub struct BrokerPeer {
/// ///
/// This is woefully overengineered and there is very little reason why the broker /// This is woefully overengineered and there is very little reason why the broker
/// configuration should not live in the particular WireGuard broker. /// configuration should not live in the particular WireGuard broker.
peer_cfg: Box<dyn WireguardBrokerCfg + Send>, peer_cfg: Box<dyn WireguardBrokerCfg>,
} }
impl BrokerPeer { impl BrokerPeer {
/// Create a broker peer /// Create a broker peer
pub fn new(ptr: BrokerStorePtr, peer_cfg: Box<dyn WireguardBrokerCfg + Send>) -> Self { pub fn new(ptr: BrokerStorePtr, peer_cfg: Box<dyn WireguardBrokerCfg>) -> Self {
Self { ptr, peer_cfg } Self { ptr, peer_cfg }
} }
@@ -289,20 +286,12 @@ pub enum AppServerIoSource {
Socket(usize), Socket(usize),
/// IO source refers to a PSK broker in [AppServer::brokers] /// IO source refers to a PSK broker in [AppServer::brokers]
PskBroker(Public<BROKER_ID_BYTES>), PskBroker(Public<BROKER_ID_BYTES>),
/// IO source refers to our signal handlers
SignalHandler,
/// IO source refers to some IO sources used in the API; /// IO source refers to some IO sources used in the API;
/// see [AppServer::api_manager] /// see [AppServer::api_manager]
#[cfg(feature = "experiment_api")] #[cfg(feature = "experiment_api")]
MioManager(crate::api::mio::MioManagerIoSource), MioManager(crate::api::mio::MioManagerIoSource),
} }
pub enum AppServerTryRecvResult {
None,
Terminate,
NetworkMessage(usize, Endpoint),
}
/// Number of epoll(7) events Rosenpass can receive at a time /// Number of epoll(7) events Rosenpass can receive at a time
const EVENT_CAPACITY: usize = 20; const EVENT_CAPACITY: usize = 20;
@@ -343,8 +332,6 @@ pub struct AppServer {
/// MIO associates IO sources with numeric tokens. This struct takes care of generating these /// MIO associates IO sources with numeric tokens. This struct takes care of generating these
/// tokens /// tokens
pub mio_token_dispenser: MioTokenDispenser, pub mio_token_dispenser: MioTokenDispenser,
/// Mio-based handler for signals
pub signal_handler: NullDebug<signal_hook_mio::Signals>,
/// Helpers handling communication with WireGuard; these take a generated key and forward it to /// Helpers handling communication with WireGuard; these take a generated key and forward it to
/// WireGuard /// WireGuard
pub brokers: BrokerStore, pub brokers: BrokerStore,
@@ -370,6 +357,16 @@ pub struct AppServer {
/// Used by integration tests to force [Self] into DoS condition /// Used by integration tests to force [Self] into DoS condition
/// and to terminate the AppServer after the test is complete /// and to terminate the AppServer after the test is complete
pub test_helpers: Option<AppServerTest>, pub test_helpers: Option<AppServerTest>,
/// Helper for integration tests running rosenpass as a subprocess
/// to terminate properly upon receiving an appropriate system signal.
///
/// This is primarily needed for coverage testing, since llvm-cov does not
/// write coverage reports to disk when a process is stopped by the default
/// signal handler.
///
/// See <https://github.com/rosenpass/rosenpass/issues/385>
#[cfg(feature = "internal_signal_handling_for_coverage_reports")]
pub term_signal: terminate::TerminateRequested,
#[cfg(feature = "experiment_api")] #[cfg(feature = "experiment_api")]
/// The Rosenpass unix socket API handler; this is an experimental /// The Rosenpass unix socket API handler; this is an experimental
/// feature that can be used to embed Rosenpass in external applications /// feature that can be used to embed Rosenpass in external applications
@@ -459,8 +456,6 @@ impl AppPeerPtr {
/// Instructs [AppServer::event_loop_without_error_handling] on how to proceed. /// Instructs [AppServer::event_loop_without_error_handling] on how to proceed.
#[derive(Debug)] #[derive(Debug)]
pub enum AppPollResult { pub enum AppPollResult {
/// Received request to terminate the application
Terminate,
/// Erase the key for a given peer. Corresponds to [crate::protocol::PollResult::DeleteKey] /// Erase the key for a given peer. Corresponds to [crate::protocol::PollResult::DeleteKey]
DeleteKey(AppPeerPtr), DeleteKey(AppPeerPtr),
/// Send an initiation to the given peer. Corresponds to [crate::protocol::PollResult::SendInitiation] /// Send an initiation to the given peer. Corresponds to [crate::protocol::PollResult::SendInitiation]
@@ -807,27 +802,10 @@ impl AppServer {
verbosity: Verbosity, verbosity: Verbosity,
test_helpers: Option<AppServerTest>, test_helpers: Option<AppServerTest>,
) -> anyhow::Result<Self> { ) -> anyhow::Result<Self> {
// Setup Mio itself // setup mio
let mio_poll = mio::Poll::new()?; let mio_poll = mio::Poll::new()?;
let events = mio::Events::with_capacity(EVENT_CAPACITY); let events = mio::Events::with_capacity(EVENT_CAPACITY);
// And helpers to map mio tokens to internal event types
let mut mio_token_dispenser = MioTokenDispenser::default(); let mut mio_token_dispenser = MioTokenDispenser::default();
let mut io_source_index = HashMap::new();
// Setup signal handling
let signal_handler = attempt!({
let mut handler =
signal_hook_mio::Signals::new(signal_hook::consts::TERM_SIGNALS.iter())?;
let mio_token = mio_token_dispenser.dispense();
mio_poll
.registry()
.register(&mut handler, mio_token, Interest::READABLE)?;
let prev = io_source_index.insert(mio_token, AppServerIoSource::SignalHandler);
assert!(prev.is_none());
Ok(NullDebug(handler))
})
.context("Failed to set up signal (user triggered program termination) handler")?;
// bind each SocketAddr to a socket // bind each SocketAddr to a socket
let maybe_sockets: Result<Vec<_>, _> = let maybe_sockets: Result<Vec<_>, _> =
@@ -901,6 +879,7 @@ impl AppServer {
} }
// register all sockets to mio // register all sockets to mio
let mut io_source_index = HashMap::new();
for (idx, socket) in sockets.iter_mut().enumerate() { for (idx, socket) in sockets.iter_mut().enumerate() {
let mio_token = mio_token_dispenser.dispense(); let mio_token = mio_token_dispenser.dispense();
mio_poll mio_poll
@@ -916,6 +895,8 @@ impl AppServer {
}; };
Ok(Self { Ok(Self {
#[cfg(feature = "internal_signal_handling_for_coverage_reports")]
term_signal: terminate::TerminateRequested::new()?,
crypto_site, crypto_site,
peers: Vec::new(), peers: Vec::new(),
verbosity, verbosity,
@@ -926,7 +907,6 @@ impl AppServer {
io_source_index, io_source_index,
mio_poll, mio_poll,
mio_token_dispenser, mio_token_dispenser,
signal_handler,
brokers: BrokerStore::default(), brokers: BrokerStore::default(),
all_sockets_drained: false, all_sockets_drained: false,
under_load: DoSOperation::Normal, under_load: DoSOperation::Normal,
@@ -997,7 +977,7 @@ impl AppServer {
/// Register a new WireGuard PSK broker /// Register a new WireGuard PSK broker
pub fn register_broker( pub fn register_broker(
&mut self, &mut self,
broker: Box<dyn WireguardBrokerMio<Error = anyhow::Error, MioError = anyhow::Error> + Send>, broker: Box<dyn WireguardBrokerMio<Error = anyhow::Error, MioError = anyhow::Error>>,
) -> Result<BrokerStorePtr> { ) -> Result<BrokerStorePtr> {
let ptr = Public::from_slice((self.brokers.store.len() as u64).as_bytes()); let ptr = Public::from_slice((self.brokers.store.len() as u64).as_bytes());
if self.brokers.store.insert(ptr, broker).is_some() { if self.brokers.store.insert(ptr, broker).is_some() {
@@ -1069,7 +1049,7 @@ impl AppServer {
Ok(AppPeerPtr(pn)) Ok(AppPeerPtr(pn))
} }
/// Main IO handler; this generally does not terminate other than through unix signals /// Main IO handler; this generally does not terminate
/// ///
/// # Examples /// # Examples
/// ///
@@ -1086,6 +1066,23 @@ impl AppServer {
Err(e) => e, Err(e) => e,
}; };
#[cfg(feature = "internal_signal_handling_for_coverage_reports")]
{
let terminated_by_signal = err
.downcast_ref::<std::io::Error>()
.filter(|e| e.kind() == std::io::ErrorKind::Interrupted)
.filter(|_| self.term_signal.value())
.is_some();
if terminated_by_signal {
log::warn!(
"\
Terminated by signal; this signal handler is correct during coverage testing \
but should be otherwise disabled"
);
return Ok(());
}
}
// This should not happen… // This should not happen…
failure_cnt = if msgs_processed > 0 { failure_cnt = if msgs_processed > 0 {
0 0
@@ -1138,7 +1135,6 @@ impl AppServer {
use AppPollResult::*; use AppPollResult::*;
use KeyOutputReason::*; use KeyOutputReason::*;
// TODO: We should read from this using a mio channel
if let Some(AppServerTest { if let Some(AppServerTest {
termination_handler: Some(terminate), termination_handler: Some(terminate),
.. ..
@@ -1162,8 +1158,6 @@ impl AppServer {
#[allow(clippy::redundant_closure_call)] #[allow(clippy::redundant_closure_call)]
match (have_crypto, poll_result) { match (have_crypto, poll_result) {
(_, Terminate) => return Ok(()),
(CryptoSrv::Missing, SendInitiation(_)) => {} (CryptoSrv::Missing, SendInitiation(_)) => {}
(CryptoSrv::Avail, SendInitiation(peer)) => tx_maybe_with!(peer, || self (CryptoSrv::Avail, SendInitiation(peer)) => tx_maybe_with!(peer, || self
.crypto_server_mut()? .crypto_server_mut()?
@@ -1311,7 +1305,6 @@ impl AppServer {
pub fn poll(&mut self, rx_buf: &mut [u8]) -> anyhow::Result<AppPollResult> { pub fn poll(&mut self, rx_buf: &mut [u8]) -> anyhow::Result<AppPollResult> {
use crate::protocol::PollResult as C; use crate::protocol::PollResult as C;
use AppPollResult as A; use AppPollResult as A;
use AppServerTryRecvResult as R;
let res = loop { let res = loop {
// Call CryptoServer's poll (if available) // Call CryptoServer's poll (if available)
let crypto_poll = self let crypto_poll = self
@@ -1332,10 +1325,8 @@ impl AppServer {
}; };
// Perform IO (look for a message) // Perform IO (look for a message)
match self.try_recv(rx_buf, io_poll_timeout)? { if let Some((len, addr)) = self.try_recv(rx_buf, io_poll_timeout)? {
R::None => {} break A::ReceivedMessage(len, addr);
R::Terminate => break A::Terminate,
R::NetworkMessage(len, addr) => break A::ReceivedMessage(len, addr),
} }
}; };
@@ -1353,12 +1344,12 @@ impl AppServer {
&mut self, &mut self,
buf: &mut [u8], buf: &mut [u8],
timeout: Timing, timeout: Timing,
) -> anyhow::Result<AppServerTryRecvResult> { ) -> anyhow::Result<Option<(usize, Endpoint)>> {
let timeout = Duration::from_secs_f64(timeout); let timeout = Duration::from_secs_f64(timeout);
// if there is no time to wait on IO, well, then, lets not waste any time! // if there is no time to wait on IO, well, then, lets not waste any time!
if timeout.is_zero() { if timeout.is_zero() {
return Ok(AppServerTryRecvResult::None); return Ok(None);
} }
// NOTE when using mio::Poll, there are some particularities (taken from // NOTE when using mio::Poll, there are some particularities (taken from
@@ -1468,19 +1459,12 @@ impl AppServer {
// blocking poll, we go through all available IO sources to see if we missed anything. // blocking poll, we go through all available IO sources to see if we missed anything.
{ {
while let Some(ev) = self.short_poll_queue.pop_front() { while let Some(ev) = self.short_poll_queue.pop_front() {
match self.try_recv_from_mio_token(buf, ev.token())? { if let Some(v) = self.try_recv_from_mio_token(buf, ev.token())? {
AppServerTryRecvResult::None => continue, return Ok(Some(v));
res => return Ok(res),
} }
} }
} }
// Drain operating system signals
match self.try_recv_from_signal_handler()? {
AppServerTryRecvResult::None => {} // Nop
res => return Ok(res),
}
// drain all sockets // drain all sockets
let mut would_block_count = 0; let mut would_block_count = 0;
for sock_no in 0..self.sockets.len() { for sock_no in 0..self.sockets.len() {
@@ -1488,11 +1472,11 @@ impl AppServer {
.try_recv_from_listen_socket(buf, sock_no) .try_recv_from_listen_socket(buf, sock_no)
.io_err_kind_hint() .io_err_kind_hint()
{ {
Ok(AppServerTryRecvResult::None) => continue, Ok(None) => continue,
Ok(res) => { Ok(Some(v)) => {
// at least one socket was not drained... // at least one socket was not drained...
self.all_sockets_drained = false; self.all_sockets_drained = false;
return Ok(res); return Ok(Some(v));
} }
Err((_, ErrorKind::WouldBlock)) => { Err((_, ErrorKind::WouldBlock)) => {
would_block_count += 1; would_block_count += 1;
@@ -1520,24 +1504,12 @@ impl AppServer {
self.performed_long_poll = true; self.performed_long_poll = true;
Ok(AppServerTryRecvResult::None) Ok(None)
} }
/// Internal helper for [Self::try_recv] /// Internal helper for [Self::try_recv]
fn perform_mio_poll_and_register_events(&mut self, timeout: Duration) -> io::Result<()> { fn perform_mio_poll_and_register_events(&mut self, timeout: Duration) -> io::Result<()> {
loop { self.mio_poll.poll(&mut self.events, Some(timeout))?;
use std::io::ErrorKind as IOE;
match self
.mio_poll
.poll(&mut self.events, Some(timeout))
.io_err_kind_hint()
{
Ok(()) => break,
Err((_, IOE::Interrupted)) => continue,
Err((err, _)) => return Err(err),
}
}
// Fill the short poll buffer with the acquired events // Fill the short poll buffer with the acquired events
self.events self.events
.iter() .iter()
@@ -1551,12 +1523,12 @@ impl AppServer {
&mut self, &mut self,
buf: &mut [u8], buf: &mut [u8],
token: mio::Token, token: mio::Token,
) -> anyhow::Result<AppServerTryRecvResult> { ) -> anyhow::Result<Option<(usize, Endpoint)>> {
let io_source = match self.io_source_index.get(&token) { let io_source = match self.io_source_index.get(&token) {
Some(io_source) => *io_source, Some(io_source) => *io_source,
None => { None => {
log::warn!("No IO source assiociated with mio token ({token:?}). Polling using mio tokens directly is an experimental feature and IO handler should recover when all available io sources are polled. This is a developer error. Please report it."); log::warn!("No IO source assiociated with mio token ({token:?}). Polling using mio tokens directly is an experimental feature and IO handler should recover when all available io sources are polled. This is a developer error. Please report it.");
return Ok(AppServerTryRecvResult::None); return Ok(None);
} }
}; };
@@ -1568,13 +1540,11 @@ impl AppServer {
&mut self, &mut self,
buf: &mut [u8], buf: &mut [u8],
io_source: AppServerIoSource, io_source: AppServerIoSource,
) -> anyhow::Result<AppServerTryRecvResult> { ) -> anyhow::Result<Option<(usize, Endpoint)>> {
match io_source { match io_source {
AppServerIoSource::SignalHandler => self.try_recv_from_signal_handler()?.ok(),
AppServerIoSource::Socket(idx) => self AppServerIoSource::Socket(idx) => self
.try_recv_from_listen_socket(buf, idx) .try_recv_from_listen_socket(buf, idx)
.substitute_for_ioerr_wouldblock(AppServerTryRecvResult::None)? .substitute_for_ioerr_wouldblock(None)?
.ok(), .ok(),
AppServerIoSource::PskBroker(key) => self AppServerIoSource::PskBroker(key) => self
@@ -1583,7 +1553,7 @@ impl AppServer {
.get_mut(&key) .get_mut(&key)
.with_context(|| format!("No PSK broker under key {key:?}"))? .with_context(|| format!("No PSK broker under key {key:?}"))?
.process_poll() .process_poll()
.map(|_| AppServerTryRecvResult::None), .map(|_| None),
#[cfg(feature = "experiment_api")] #[cfg(feature = "experiment_api")]
AppServerIoSource::MioManager(mmio_src) => { AppServerIoSource::MioManager(mmio_src) => {
@@ -1591,28 +1561,17 @@ impl AppServer {
MioManagerFocus(self) MioManagerFocus(self)
.poll_particular(mmio_src) .poll_particular(mmio_src)
.map(|_| AppServerTryRecvResult::None) .map(|_| None)
} }
} }
} }
/// Internal helper for [Self::try_recv]
fn try_recv_from_signal_handler(&mut self) -> io::Result<AppServerTryRecvResult> {
#[allow(clippy::never_loop)]
for signal in self.signal_handler.pending() {
log::debug!("Received operating system signal no {signal}.");
log::info!("Received termination request; exiting.");
return Ok(AppServerTryRecvResult::Terminate);
}
Ok(AppServerTryRecvResult::None)
}
/// Internal helper for [Self::try_recv] /// Internal helper for [Self::try_recv]
fn try_recv_from_listen_socket( fn try_recv_from_listen_socket(
&mut self, &mut self,
buf: &mut [u8], buf: &mut [u8],
idx: usize, idx: usize,
) -> io::Result<AppServerTryRecvResult> { ) -> io::Result<Option<(usize, Endpoint)>> {
use std::io::ErrorKind as K; use std::io::ErrorKind as K;
let (n, addr) = loop { let (n, addr) = loop {
match self.sockets[idx].recv_from(buf).io_err_kind_hint() { match self.sockets[idx].recv_from(buf).io_err_kind_hint() {
@@ -1624,7 +1583,8 @@ impl AppServer {
SocketPtr(idx) SocketPtr(idx)
.apply(|sp| SocketBoundEndpoint::new(sp, addr)) .apply(|sp| SocketBoundEndpoint::new(sp, addr))
.apply(Endpoint::SocketBoundAddress) .apply(Endpoint::SocketBoundAddress)
.apply(|ep| AppServerTryRecvResult::NetworkMessage(n, ep)) .apply(|ep| (n, ep))
.some()
.ok() .ok()
} }
@@ -1676,3 +1636,48 @@ impl crate::api::mio::MioManagerContext for MioManagerFocus<'_> {
self.0 self.0
} }
} }
/// These signal handlers are used exclusively used during coverage testing
/// to ensure that the llvm-cov can produce reports during integration tests
/// with multiple processes where subprocesses are terminated via kill(2).
///
/// llvm-cov does not support producing coverage reports when the process exits
/// through a signal, so this is necessary.
///
/// The functionality of exiting gracefully upon reception of a terminating signal
/// is desired for the production variant of Rosenpass, but we should make sure
/// to use a higher quality implementation; in particular, we should use signalfd(2).
///
#[cfg(feature = "internal_signal_handling_for_coverage_reports")]
mod terminate {
use signal_hook::flag::register as sig_register;
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
/// Automatically register a signal handler for common termination signals;
/// whether one of these signals was issued can be polled using [Self::value].
///
/// The signal handler is not removed when this struct goes out of scope.
#[derive(Debug)]
pub struct TerminateRequested {
value: Arc<AtomicBool>,
}
impl TerminateRequested {
/// Register signal handlers watching for common termination signals
pub fn new() -> anyhow::Result<Self> {
let value = Arc::new(AtomicBool::new(false));
for sig in signal_hook::consts::TERM_SIGNALS.iter().copied() {
sig_register(sig, Arc::clone(&value))?;
}
Ok(Self { value })
}
/// Check whether a termination signal has been set
pub fn value(&self) -> bool {
self.value.load(Ordering::Relaxed)
}
}
}

View File

@@ -490,7 +490,7 @@ impl CliArgs {
cfg_peer.key_out, cfg_peer.key_out,
broker_peer, broker_peer,
cfg_peer.endpoint.clone(), cfg_peer.endpoint.clone(),
cfg_peer.protocol_version, cfg_peer.protocol_version.into(),
cfg_peer.osk_domain_separator.try_into()?, cfg_peer.osk_domain_separator.try_into()?,
)?; )?;
} }
@@ -515,7 +515,7 @@ impl CliArgs {
fn create_broker( fn create_broker(
broker_interface: Option<BrokerInterface>, broker_interface: Option<BrokerInterface>,
) -> Result< ) -> Result<
Box<dyn WireguardBrokerMio<MioError = anyhow::Error, Error = anyhow::Error> + Send>, Box<dyn WireguardBrokerMio<MioError = anyhow::Error, Error = anyhow::Error>>,
anyhow::Error, anyhow::Error,
> { > {
if let Some(interface) = broker_interface { if let Some(interface) = broker_interface {

View File

@@ -200,7 +200,7 @@ impl RosenpassPeerOskDomainSeparator {
pub fn org_and_label(&self) -> anyhow::Result<Option<(&String, &Vec<String>)>> { pub fn org_and_label(&self) -> anyhow::Result<Option<(&String, &Vec<String>)>> {
match (&self.osk_organization, &self.osk_label) { match (&self.osk_organization, &self.osk_label) {
(None, None) => Ok(None), (None, None) => Ok(None),
(Some(org), Some(label)) => Ok(Some((org, label))), (Some(org), Some(label)) => Ok(Some((&org, &label))),
(Some(_), None) => bail!("Specified osk_organization but not osk_label in config file. You need to specify both, or none."), (Some(_), None) => bail!("Specified osk_organization but not osk_label in config file. You need to specify both, or none."),
(None, Some(_)) => bail!("Specified osk_label but not osk_organization in config file. You need to specify both, or none."), (None, Some(_)) => bail!("Specified osk_label but not osk_organization in config file. You need to specify both, or none."),
} }

View File

@@ -166,7 +166,7 @@ hash_domain_ns!(
protocol, cookie_key, "cookie-key"); protocol, cookie_key, "cookie-key");
hash_domain_ns!( hash_domain_ns!(
/// Hash domain based on [protocol] for calculating the peer id as transmitted (encrypted) /// Hash domain based on [protocol] for calculating the peer id as transmitted (encrypted)
/// in [crate::msgs::InitHello::pidi_ct]. /// in [crate::msgs::InitHello::pidic].
/// ///
/// # Examples /// # Examples
/// ///
@@ -179,7 +179,7 @@ hash_domain_ns!(
hash_domain_ns!( hash_domain_ns!(
/// Hash domain based on [protocol] for calculating the additional data /// Hash domain based on [protocol] for calculating the additional data
/// during [crate::msgs::Biscuit] encryption, storing the biscuit into /// during [crate::msgs::Biscuit] encryption, storing the biscuit into
/// [crate::msgs::RespHello::biscuit_ct]. /// [crate::msgs::RespHello::biscuit].
/// ///
/// # Examples /// # Examples
/// ///

View File

@@ -135,7 +135,7 @@ pub struct InitHello {
/// Classic McEliece Ciphertext /// Classic McEliece Ciphertext
pub sctr: [u8; StaticKem::CT_LEN], pub sctr: [u8; StaticKem::CT_LEN],
/// Encryped: 16 byte hash of McEliece initiator static key /// Encryped: 16 byte hash of McEliece initiator static key
pub pidi_ct: [u8; Aead::TAG_LEN + 32], pub pidic: [u8; Aead::TAG_LEN + 32],
/// Encrypted TAI64N Time Stamp (against replay attacks) /// Encrypted TAI64N Time Stamp (against replay attacks)
pub auth: [u8; Aead::TAG_LEN], pub auth: [u8; Aead::TAG_LEN],
} }
@@ -188,7 +188,7 @@ pub struct RespHello {
/// Empty encrypted message (just an auth tag) /// Empty encrypted message (just an auth tag)
pub auth: [u8; Aead::TAG_LEN], pub auth: [u8; Aead::TAG_LEN],
/// Responders handshake state in encrypted form /// Responders handshake state in encrypted form
pub biscuit_ct: [u8; BISCUIT_CT_LEN], pub biscuit: [u8; BISCUIT_CT_LEN],
} }
/// This is the third message sent by the initiator to the responder /// This is the third message sent by the initiator to the responder
@@ -233,7 +233,7 @@ pub struct InitConf {
/// Copied from RespHello /// Copied from RespHello
pub sidr: [u8; 4], pub sidr: [u8; 4],
/// Responders handshake state in encrypted form /// Responders handshake state in encrypted form
pub biscuit_ct: [u8; BISCUIT_CT_LEN], pub biscuit: [u8; BISCUIT_CT_LEN],
/// Empty encrypted message (just an auth tag) /// Empty encrypted message (just an auth tag)
pub auth: [u8; Aead::TAG_LEN], pub auth: [u8; Aead::TAG_LEN],
} }

View File

@@ -86,7 +86,6 @@ pub mod constants;
pub mod cookies; pub mod cookies;
pub mod index; pub mod index;
pub mod osk_domain_separator; pub mod osk_domain_separator;
pub mod test_vector_sets;
pub mod testutils; pub mod testutils;
pub mod timing; pub mod timing;
pub mod zerocopy; pub mod zerocopy;

View File

@@ -15,7 +15,6 @@ use std::{
}; };
use anyhow::{bail, ensure, Context, Result}; use anyhow::{bail, ensure, Context, Result};
use assert_tv::{TestVector, TestVectorNOP};
use memoffset::span_of; use memoffset::span_of;
use zerocopy::{AsBytes, FromBytes, Ref}; use zerocopy::{AsBytes, FromBytes, Ref};
@@ -34,10 +33,6 @@ use rosenpass_util::{
time::Timebase, time::Timebase,
}; };
use crate::protocol::test_vector_sets::{
CycledBiscuitSecretKeyTestValues, EncapsAndMixTestValues, HandleInitHelloTestValues,
HandleInitiationTestValues, StoreBiscuitTestValues,
};
use crate::{hash_domains, msgs::*, RosenpassError}; use crate::{hash_domains, msgs::*, RosenpassError};
use super::basic_types::{ use super::basic_types::{
@@ -1397,20 +1392,6 @@ impl CryptoServer {
/// ///
/// Swap the biscuit keys, also advancing both biscuit key's mortality /// Swap the biscuit keys, also advancing both biscuit key's mortality
pub fn active_biscuit_key(&mut self) -> BiscuitKeyPtr { pub fn active_biscuit_key(&mut self) -> BiscuitKeyPtr {
self.active_biscuit_key_with_test_vector::<TestVectorNOP>()
}
/// Generic variant of [`Self::active_biscuit_key`] that allows selecting
/// a [`TestVector`] implementation.
///
/// This function is primarily intended for testing with different
/// test vector strategies. In production code, prefer using
/// [`Self::active_biscuit_key`], which defaults to [`assert_tv::TestVectorNOP`].
///
/// Use this function with [`assert_tv::TestVectorActive`] in tests that require
/// applying actual test vectors. See the `tests::test_vector_crypto_server`
/// test for an example
pub fn active_biscuit_key_with_test_vector<TV: TestVector>(&mut self) -> BiscuitKeyPtr {
let (a, b) = (BiscuitKeyPtr(0), BiscuitKeyPtr(1)); let (a, b) = (BiscuitKeyPtr(0), BiscuitKeyPtr(1));
let (t, u) = (a.get(self).created_at, b.get(self).created_at); let (t, u) = (a.get(self).created_at, b.get(self).created_at);
@@ -1426,11 +1407,6 @@ impl CryptoServer {
let r = if t < u { a } else { b }; let r = if t < u { a } else { b };
let tb = self.timebase.clone(); let tb = self.timebase.clone();
r.get_mut(self).randomize(&tb); r.get_mut(self).randomize(&tb);
let test_values: CycledBiscuitSecretKeyTestValues = TV::initialize_values();
TV::expose_mut_value(
&test_values.cycled_biscuit_secret_key,
&mut self.biscuit_keys[r.0].value,
);
r r
} }
@@ -1749,7 +1725,6 @@ impl Mortal for KnownInitConfResponsePtr {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use assert_tv::TestVector;
/// use rosenpass::protocol::{timing::Timing, Mortal, MortalExt, Lifecycle, CryptoServer, ProtocolVersion}; /// use rosenpass::protocol::{timing::Timing, Mortal, MortalExt, Lifecycle, CryptoServer, ProtocolVersion};
/// use rosenpass::protocol::testutils::{ServerForTesting, time_travel_forward}; /// use rosenpass::protocol::testutils::{ServerForTesting, time_travel_forward};
/// ///
@@ -1890,31 +1865,13 @@ impl CryptoServer {
/// ///
/// See [Self::poll] on how to use this function with poll. /// See [Self::poll] on how to use this function with poll.
pub fn initiate_handshake(&mut self, peer: PeerPtr, tx_buf: &mut [u8]) -> Result<usize> { pub fn initiate_handshake(&mut self, peer: PeerPtr, tx_buf: &mut [u8]) -> Result<usize> {
self.initiate_handshake_with_test_vector::<TestVectorNOP>(peer, tx_buf)
}
/// Generic variant of [`Self::initiate_handshake`] that allows selecting
/// a [`TestVector`] implementation.
///
/// This function is primarily intended for testing with different
/// test vector strategies. In production code, prefer using
/// [`Self::initiate_handshake`], which defaults to [`assert_tv::TestVectorNOP`].
///
/// Use this function with [`assert_tv::TestVectorActive`] in tests that require
/// applying actual test vectors. See the `tests::test_vector_crypto_server`
/// test for an example
pub fn initiate_handshake_with_test_vector<TV: TestVector>(
&mut self,
peer: PeerPtr,
tx_buf: &mut [u8],
) -> Result<usize> {
// NOTE retransmission? yes if initiator, no if responder // NOTE retransmission? yes if initiator, no if responder
// TODO remove unnecessary copying between global tx_buf and per-peer buf // TODO remove unnecessary copying between global tx_buf and per-peer buf
// TODO move retransmission storage to io server // TODO move retransmission storage to io server
// //
// Envelope::<InitHello>::default(); // TODO // Envelope::<InitHello>::default(); // TODO
let mut msg = truncating_cast_into::<Envelope<InitHello>>(tx_buf)?; let mut msg = truncating_cast_into::<Envelope<InitHello>>(tx_buf)?;
self.handle_initiation_with_test_vector::<TV>(peer, &mut msg.payload)?; self.handle_initiation(peer, &mut msg.payload)?;
let len = self.seal_and_commit_msg(peer, MsgType::InitHello, &mut msg)?; let len = self.seal_and_commit_msg(peer, MsgType::InitHello, &mut msg)?;
peer.hs() peer.hs()
.store_msg_for_retransmission(self, msg.as_bytes())?; .store_msg_for_retransmission(self, msg.as_bytes())?;
@@ -1986,7 +1943,7 @@ impl CryptoServer {
&mut self, &mut self,
rx_buf: &[u8], rx_buf: &[u8],
tx_buf: &mut [u8], tx_buf: &mut [u8],
_host_identification: &H, host_identification: &H,
) -> Result<HandleMsgResult> { ) -> Result<HandleMsgResult> {
self.handle_msg(rx_buf, tx_buf) self.handle_msg(rx_buf, tx_buf)
} }
@@ -2154,24 +2111,6 @@ impl CryptoServer {
/// ///
/// See [Self::poll] on how to use this function with poll. /// See [Self::poll] on how to use this function with poll.
pub fn handle_msg(&mut self, rx_buf: &[u8], tx_buf: &mut [u8]) -> Result<HandleMsgResult> { pub fn handle_msg(&mut self, rx_buf: &[u8], tx_buf: &mut [u8]) -> Result<HandleMsgResult> {
self.handle_msg_with_test_vector::<TestVectorNOP>(rx_buf, tx_buf)
}
/// Generic message handler that allows selecting a [`TestVector`]
/// implementation.
///
/// This function is primarily intended for **testing** with different
/// test vector strategies. In production code, prefer using
/// [`Self::handle_msg`], which defaults to [`assert_tv::TestVectorNOP`].
///
/// Use this function with [`assert_tv::TestVectorActive`] in tests that require
/// applying actual test vectors. See the `tests::test_vector_crypto_server`
/// test for an example
pub fn handle_msg_with_test_vector<TV: TestVector>(
&mut self,
rx_buf: &[u8],
tx_buf: &mut [u8],
) -> Result<HandleMsgResult> {
let seal_broken = "Message seal broken!"; let seal_broken = "Message seal broken!";
// length of the response. We assume no response, so None for now // length of the response. We assume no response, so None for now
let mut len = 0; let mut len = 0;
@@ -2192,7 +2131,7 @@ impl CryptoServer {
// At this point, we do not know the hash functon used by the peer, thus we try both, // At this point, we do not know the hash functon used by the peer, thus we try both,
// with a preference for SHAKE256. // with a preference for SHAKE256.
let peer_shake256 = self.handle_init_hello_with_test_vector::<TV>( let peer_shake256 = self.handle_init_hello(
&msg_in.payload, &msg_in.payload,
&mut msg_out.payload, &mut msg_out.payload,
KeyedHash::keyed_shake256(), KeyedHash::keyed_shake256(),
@@ -2200,7 +2139,7 @@ impl CryptoServer {
let (peer, peer_hash_choice) = match peer_shake256 { let (peer, peer_hash_choice) = match peer_shake256 {
Ok(peer) => (peer, KeyedHash::keyed_shake256()), Ok(peer) => (peer, KeyedHash::keyed_shake256()),
Err(_) => { Err(_) => {
let peer_blake2b = self.handle_init_hello_with_test_vector::<TV>( let peer_blake2b = self.handle_init_hello(
&msg_in.payload, &msg_in.payload,
&mut msg_out.payload, &mut msg_out.payload,
KeyedHash::incorrect_hmac_blake2b(), KeyedHash::incorrect_hmac_blake2b(),
@@ -3220,48 +3159,8 @@ impl HandshakeState {
ct: &mut [u8; KEM_CT_LEN], ct: &mut [u8; KEM_CT_LEN],
pk: &[u8; KEM_PK_LEN], pk: &[u8; KEM_PK_LEN],
) -> Result<&mut Self> { ) -> Result<&mut Self> {
self.encaps_and_mix_with_test_vector(kem, ct, pk, std::marker::PhantomData::<TestVectorNOP>)
}
/// Generic variant of [`Self::encaps_and_mix`] that allows selecting
/// a [`TestVector`] implementation.
///
/// This function is primarily intended for testing with different
/// test vector strategies. In production code, prefer using
/// [`Self::encaps_and_mix`], which defaults to [`assert_tv::TestVectorNOP`].
///
/// Use this function with [`assert_tv::TestVectorActive`] in tests that require
/// applying actual test vectors. See the `tests::test_vector_crypto_server`
/// test for an example.
///
/// Note on `_tv: PhantomData<TV>` parameter:
/// - Rusts type inference ties generic parameter specification together;
/// explicitly selecting `TV` with turbofish can force you to also spell
/// out the const generics.
/// - By adding a value parameter of type `PhantomData<TV>`, you can choose
/// `TV` at the call site while allowing the compiler to infer `KEM_*`
/// const generics from `ct` and `pk`.
/// - Call like: `encaps_and_mix_with_test_vector(&StaticKem, &mut ct, pk,
/// PhantomData::<TestVectorActive>)?;`
pub fn encaps_and_mix_with_test_vector<
const KEM_SK_LEN: usize,
const KEM_PK_LEN: usize,
const KEM_CT_LEN: usize,
const KEM_SHK_LEN: usize,
KemImpl: Kem<KEM_SK_LEN, KEM_PK_LEN, KEM_CT_LEN, KEM_SHK_LEN>,
TV: TestVector,
>(
&mut self,
kem: &KemImpl,
ct: &mut [u8; KEM_CT_LEN],
pk: &[u8; KEM_PK_LEN],
_tv: std::marker::PhantomData<TV>,
) -> Result<&mut Self> {
let test_values: EncapsAndMixTestValues<KEM_CT_LEN, KEM_SHK_LEN> = TV::initialize_values();
let mut shk = Secret::<KEM_SHK_LEN>::zero(); let mut shk = Secret::<KEM_SHK_LEN>::zero();
kem.encaps(shk.secret_mut(), ct, pk)?; kem.encaps(shk.secret_mut(), ct, pk)?;
TV::expose_mut_value(&test_values.shk, &mut shk);
TV::expose_mut_value(&test_values.ct, ct);
self.mix(pk)?.mix(shk.secret())?.mix(ct) self.mix(pk)?.mix(shk.secret())?.mix(ct)
} }
@@ -3300,26 +3199,6 @@ impl HandshakeState {
peer: PeerPtr, peer: PeerPtr,
biscuit_ct: &mut [u8], biscuit_ct: &mut [u8],
) -> Result<&mut Self> { ) -> Result<&mut Self> {
self.store_biscuit_with_test_vector::<TestVectorNOP>(srv, peer, biscuit_ct)
}
/// Generic variant of [`Self::store_biscuit`] that allows selecting
/// a [`TestVector`] implementation.
///
/// This function is primarily intended for testing with different
/// test vector strategies. In production code, prefer using
/// [`Self::store_biscuit`], which defaults to [`assert_tv::TestVectorNOP`].
///
/// Use this function with [`assert_tv::TestVectorActive`] in tests that require
/// applying actual test vectors. See the `tests::test_vector_crypto_server`
/// test for an example
pub fn store_biscuit_with_test_vector<TV: TestVector>(
&mut self,
srv: &mut CryptoServer,
peer: PeerPtr,
biscuit_ct: &mut [u8],
) -> Result<&mut Self> {
let test_values: StoreBiscuitTestValues = TV::initialize_values();
let mut biscuit = Secret::<BISCUIT_PT_LEN>::zero(); // pt buffer let mut biscuit = Secret::<BISCUIT_PT_LEN>::zero(); // pt buffer
let mut biscuit: Ref<&mut [u8], Biscuit> = let mut biscuit: Ref<&mut [u8], Biscuit> =
Ref::new(biscuit.secret_mut().as_mut_slice()).unwrap(); Ref::new(biscuit.secret_mut().as_mut_slice()).unwrap();
@@ -3333,8 +3212,6 @@ impl HandshakeState {
.ck .ck
.copy_from_slice(self.ck.clone().danger_into_secret().secret()); .copy_from_slice(self.ck.clone().danger_into_secret().secret());
TV::check_value(&test_values.biscuit, &biscuit.as_bytes().to_vec());
// calculate ad contents // calculate ad contents
let ad = hash_domains::biscuit_ad(peer.get(srv).protocol_version.keyed_hash())? let ad = hash_domains::biscuit_ad(peer.get(srv).protocol_version.keyed_hash())?
.mix(srv.spkm.deref())? .mix(srv.spkm.deref())?
@@ -3347,18 +3224,14 @@ impl HandshakeState {
// The first bit of the nonce indicates which biscuit key was used // The first bit of the nonce indicates which biscuit key was used
// TODO: This is premature optimization. Remove! // TODO: This is premature optimization. Remove!
let bk = srv.active_biscuit_key_with_test_vector::<TV>(); let bk = srv.active_biscuit_key();
let mut n = XAEADNonce::random(); let mut n = XAEADNonce::random();
TV::expose_mut_value(&test_values.n, &mut n);
n[0] &= 0b0111_1111; n[0] &= 0b0111_1111;
n[0] |= (bk.0 as u8 & 0x1) << 7; n[0] |= (bk.0 as u8 & 0x1) << 7;
let k = bk.get(srv).value.secret(); let k = bk.get(srv).value.secret();
let pt = biscuit.as_bytes(); let pt = biscuit.as_bytes();
XAead.encrypt_with_nonce_in_ctxt(biscuit_ct, k, &n, &ad, pt)?; XAead.encrypt_with_nonce_in_ctxt(biscuit_ct, k, &*n, &ad, pt)?;
TV::check_value(&test_values.biscuit_ct, &biscuit_ct.to_vec());
self.mix(biscuit_ct) self.mix(biscuit_ct)
} }
@@ -3527,26 +3400,6 @@ impl CryptoServer {
/// Core cryptographic protocol implementation: Kicks of the handshake /// Core cryptographic protocol implementation: Kicks of the handshake
/// on the initiator side, producing the InitHello message. /// on the initiator side, producing the InitHello message.
pub fn handle_initiation(&mut self, peer: PeerPtr, ih: &mut InitHello) -> Result<PeerPtr> { pub fn handle_initiation(&mut self, peer: PeerPtr, ih: &mut InitHello) -> Result<PeerPtr> {
self.handle_initiation_with_test_vector::<TestVectorNOP>(peer, ih)
}
/// Generic variant of [`Self::handle_initiation`] that allows selecting
/// a [`TestVector`] implementation.
///
/// This function is primarily intended for testing with different
/// test vector strategies. In production code, prefer using
/// [`Self::handle_initiation`], which defaults to [`assert_tv::TestVectorNOP`].
///
/// Use this function with [`assert_tv::TestVectorActive`] in tests that require
/// applying actual test vectors. See the `tests::test_vector_crypto_server`
/// test for an example
pub fn handle_initiation_with_test_vector<TV: TestVector>(
&mut self,
peer: PeerPtr,
ih: &mut InitHello,
) -> Result<PeerPtr> {
let test_values: HandleInitiationTestValues = TV::initialize_values();
#[cfg(feature = "trace_bench")] #[cfg(feature = "trace_bench")]
let _span_guard = rosenpass_util::trace_bench::trace().emit_span("handle_initiation"); let _span_guard = rosenpass_util::trace_bench::trace().emit_span("handle_initiation");
@@ -3555,12 +3408,6 @@ impl CryptoServer {
peer.get(self).protocol_version.keyed_hash(), peer.get(self).protocol_version.keyed_hash(),
); );
// hs.cookie_value.created_at = tv_const!(hs.cookie_value.created_at, "init_handshake-cookie-created_at");
TV::expose_mut_value(
&test_values.init_handshake_cookie,
&mut hs.cookie_value.value,
);
// IHI1 // IHI1
protocol_section!("IHI1", { protocol_section!("IHI1", {
hs.core.init(peer.get(self).spkt.deref())?; hs.core.init(peer.get(self).spkt.deref())?;
@@ -3569,54 +3416,33 @@ impl CryptoServer {
// IHI2 // IHI2
protocol_section!("IHI2", { protocol_section!("IHI2", {
hs.core.sidi.randomize(); hs.core.sidi.randomize();
TV::expose_mut_value(&test_values.init_handshake_sidi, &mut hs.core.sidi);
ih.sidi.copy_from_slice(&hs.core.sidi.value); ih.sidi.copy_from_slice(&hs.core.sidi.value);
}); });
// IHI3 // IHI3
protocol_section!("IHI3", { protocol_section!("IHI3", {
EphemeralKem.keygen(hs.eski.secret_mut(), &mut hs.epki)?; EphemeralKem.keygen(hs.eski.secret_mut(), &mut *hs.epki)?;
TV::expose_mut_value(&test_values.init_handshake_eski, &mut hs.eski);
TV::expose_mut_value(&test_values.init_handshake_epki, &mut hs.epki);
ih.epki.copy_from_slice(&hs.epki.value); ih.epki.copy_from_slice(&hs.epki.value);
}); });
// IHI4 // IHI4
protocol_section!("IHI4", { protocol_section!("IHI4", {
hs.core.mix(ih.sidi.as_slice())?.mix(ih.epki.as_slice())?; hs.core.mix(ih.sidi.as_slice())?.mix(ih.epki.as_slice())?;
TV::check_value(
&test_values.init_handshake_mix_1,
&hs.core.ck.clone().danger_into_secret(),
);
}); });
// IHI5 // IHI5
protocol_section!("IHI5", { protocol_section!("IHI5", {
use std::marker::PhantomData; hs.core
hs.core.encaps_and_mix_with_test_vector( .encaps_and_mix(&StaticKem, &mut ih.sctr, peer.get(self).spkt.deref())?;
&StaticKem,
&mut ih.sctr,
peer.get(self).spkt.deref(),
PhantomData::<TV>,
)?;
TV::check_value(
&test_values.init_handshake_mix_2,
&hs.core.ck.clone().danger_into_secret(),
);
}); });
// IHI6 // IHI6
protocol_section!("IHI6", { protocol_section!("IHI6", {
hs.core.encrypt_and_mix( hs.core.encrypt_and_mix(
ih.pidi_ct.as_mut_slice(), ih.pidic.as_mut_slice(),
self.pidm(peer.get(self).protocol_version.keyed_hash())? self.pidm(peer.get(self).protocol_version.keyed_hash())?
.as_ref(), .as_ref(),
)?; )?;
TV::check_value(&test_values.init_hello_pidi_ct, &ih.pidi_ct);
TV::check_value(
&test_values.init_handshake_mix_3,
&hs.core.ck.clone().danger_into_secret(),
);
}); });
// IHI7 // IHI7
@@ -3624,24 +3450,16 @@ impl CryptoServer {
hs.core hs.core
.mix(self.spkm.deref())? .mix(self.spkm.deref())?
.mix(peer.get(self).psk.secret())?; .mix(peer.get(self).psk.secret())?;
TV::check_value(
&test_values.init_handshake_mix_4,
&hs.core.ck.clone().danger_into_secret(),
);
}); });
// IHI8 // IHI8
protocol_section!("IHI8", { protocol_section!("IHI8", {
hs.core.encrypt_and_mix(ih.auth.as_mut_slice(), &[])?; hs.core.encrypt_and_mix(ih.auth.as_mut_slice(), &[])?;
TV::check_value(&test_values.init_hello_auth, &ih.auth);
TV::check_value(
&test_values.init_handshake_mix_5,
&hs.core.ck.clone().danger_into_secret(),
);
}); });
// Update the handshake hash last (not changing any state on prior error // Update the handshake hash last (not changing any state on prior error
peer.hs().insert(self, hs)?; peer.hs().insert(self, hs)?;
Ok(peer) Ok(peer)
} }
@@ -3653,27 +3471,6 @@ impl CryptoServer {
rh: &mut RespHello, rh: &mut RespHello,
keyed_hash: KeyedHash, keyed_hash: KeyedHash,
) -> Result<PeerPtr> { ) -> Result<PeerPtr> {
self.handle_init_hello_with_test_vector::<TestVectorNOP>(ih, rh, keyed_hash)
}
/// Generic variant of [`Self::handle_init_hello`] that allows selecting
/// a [`TestVector`] implementation.
///
/// This function is primarily intended for testing with different
/// test vector strategies. In production code, prefer using
/// [`Self::handle_init_hello`], which defaults to [`assert_tv::TestVectorNOP`].
///
/// Use this function with [`assert_tv::TestVectorActive`] in tests that require
/// applying actual test vectors. See the `tests::test_vector_crypto_server`
/// test for an example
pub fn handle_init_hello_with_test_vector<TV: TestVector>(
&mut self,
ih: &InitHello,
rh: &mut RespHello,
keyed_hash: KeyedHash,
) -> Result<PeerPtr> {
let test_values: HandleInitHelloTestValues = TV::initialize_values();
#[cfg(feature = "trace_bench")] #[cfg(feature = "trace_bench")]
let _span_guard = rosenpass_util::trace_bench::trace().emit_span("handle_init_hello"); let _span_guard = rosenpass_util::trace_bench::trace().emit_span("handle_init_hello");
@@ -3690,55 +3487,34 @@ impl CryptoServer {
protocol_section!("IHR4", { protocol_section!("IHR4", {
core.mix(&ih.sidi)?.mix(&ih.epki)?; core.mix(&ih.sidi)?.mix(&ih.epki)?;
}); });
TV::check_value(
&test_values.chaining_key_ihr_4,
&core.ck.clone().danger_into_secret(),
);
// IHR5 // IHR5
protocol_section!("IHR5", { protocol_section!("IHR5", {
core.decaps_and_mix(&StaticKem, self.sskm.secret(), self.spkm.deref(), &ih.sctr)?; core.decaps_and_mix(&StaticKem, self.sskm.secret(), self.spkm.deref(), &ih.sctr)?;
}); });
TV::check_value(
&test_values.chaining_key_ihr_5,
&core.ck.clone().danger_into_secret(),
);
// IHR6 // IHR6
let peer = protocol_section!("IHR6", { let peer = protocol_section!("IHR6", {
let mut peerid = PeerId::zero(); let mut peerid = PeerId::zero();
core.decrypt_and_mix(&mut *peerid, &ih.pidi_ct)?; core.decrypt_and_mix(&mut *peerid, &ih.pidic)?;
self.find_peer(peerid) self.find_peer(peerid)
.with_context(|| format!("No such peer {peerid:?}."))? .with_context(|| format!("No such peer {peerid:?}."))?
}); });
TV::check_value(
&test_values.chaining_key_ihr_6,
&core.ck.clone().danger_into_secret(),
);
// IHR7 // IHR7
protocol_section!("IHR7", { protocol_section!("IHR7", {
core.mix(peer.get(self).spkt.deref())? core.mix(peer.get(self).spkt.deref())?
.mix(peer.get(self).psk.secret())?; .mix(peer.get(self).psk.secret())?;
}); });
TV::check_value(
&test_values.chaining_key_ihr_7,
&core.ck.clone().danger_into_secret(),
);
// IHR8 // IHR8
protocol_section!("IHR8", { protocol_section!("IHR8", {
core.decrypt_and_mix(&mut [0u8; 0], &ih.auth)?; core.decrypt_and_mix(&mut [0u8; 0], &ih.auth)?;
}); });
TV::check_value(
&test_values.chaining_key_ihr_8,
&core.ck.clone().danger_into_secret(),
);
// RHR1 // RHR1
protocol_section!("RHR1", { protocol_section!("RHR1", {
core.sidr.randomize(); core.sidr.randomize();
TV::expose_mut_value(&test_values.session_id, &mut core.sidr);
rh.sidi.copy_from_slice(core.sidi.as_ref()); rh.sidi.copy_from_slice(core.sidi.as_ref());
rh.sidr.copy_from_slice(core.sidr.as_ref()); rh.sidr.copy_from_slice(core.sidr.as_ref());
}); });
@@ -3746,59 +3522,28 @@ impl CryptoServer {
// RHR3 // RHR3
protocol_section!("RHR3", { protocol_section!("RHR3", {
core.mix(&rh.sidr)?.mix(&rh.sidi)?; core.mix(&rh.sidr)?.mix(&rh.sidi)?;
TV::check_value(
&test_values.chaining_key_rhr_3,
&core.ck.clone().danger_into_secret(),
);
}); });
// RHR4 // RHR4
protocol_section!("RHR4", { protocol_section!("RHR4", {
use std::marker::PhantomData; core.encaps_and_mix(&EphemeralKem, &mut rh.ecti, &ih.epki)?;
core.encaps_and_mix_with_test_vector(
&EphemeralKem,
&mut rh.ecti,
&ih.epki,
PhantomData::<TV>,
)?;
TV::check_value(
&test_values.chaining_key_rhr_4,
&core.ck.clone().danger_into_secret(),
);
}); });
// RHR5 // RHR5
protocol_section!("RHR5", { protocol_section!("RHR5", {
use std::marker::PhantomData; core.encaps_and_mix(&StaticKem, &mut rh.scti, peer.get(self).spkt.deref())?;
core.encaps_and_mix_with_test_vector(
&StaticKem,
&mut rh.scti,
peer.get(self).spkt.deref(),
PhantomData::<TV>,
)?;
TV::check_value(
&test_values.chaining_key_rhr_5,
&core.ck.clone().danger_into_secret(),
);
}); });
// RHR6 // RHR6
protocol_section!("RHR6", { protocol_section!("RHR6", {
core.store_biscuit_with_test_vector::<TV>(self, peer, &mut rh.biscuit_ct)?; core.store_biscuit(self, peer, &mut rh.biscuit)?;
TV::check_value(
&test_values.chaining_key_rhr_6,
&core.ck.clone().danger_into_secret(),
);
}); });
// RHR7 // RHR7
protocol_section!("RHR7", { protocol_section!("RHR7", {
core.encrypt_and_mix(&mut rh.auth, &[])?; core.encrypt_and_mix(&mut rh.auth, &[])?;
TV::check_value(
&test_values.chaining_key_rhr_7,
&core.ck.clone().danger_into_secret(),
);
}); });
Ok(peer) Ok(peer)
} }
@@ -3872,7 +3617,7 @@ impl CryptoServer {
// RHI6 // RHI6
protocol_section!("RHI6", { protocol_section!("RHI6", {
core.mix(&rh.biscuit_ct)?; core.mix(&rh.biscuit)?;
}); });
// RHI7 // RHI7
@@ -3889,7 +3634,7 @@ impl CryptoServer {
// ICI3 // ICI3
protocol_section!("ICI3", { protocol_section!("ICI3", {
core.mix(&ic.sidi)?.mix(&ic.sidr)?; core.mix(&ic.sidi)?.mix(&ic.sidr)?;
ic.biscuit_ct.copy_from_slice(&rh.biscuit_ct); ic.biscuit.copy_from_slice(&rh.biscuit);
}); });
// ICI4 // ICI4
@@ -3937,7 +3682,7 @@ impl CryptoServer {
let (peer, biscuit_no, mut core) = protocol_section!("ICR1", { let (peer, biscuit_no, mut core) = protocol_section!("ICR1", {
HandshakeState::load_biscuit( HandshakeState::load_biscuit(
self, self,
&ic.biscuit_ct, &ic.biscuit,
SessionId::from_slice(&ic.sidi), SessionId::from_slice(&ic.sidi),
SessionId::from_slice(&ic.sidr), SessionId::from_slice(&ic.sidr),
keyed_hash, keyed_hash,

View File

@@ -55,14 +55,12 @@ fn setup_logging() {
#[test] #[test]
#[serial] #[serial]
#[cfg_attr(miri, ignore)] // Miri does not support calls to mmap with protections other than PROT_READ|PROT_WRITE
fn handles_incorrect_size_messages_v02() { fn handles_incorrect_size_messages_v02() {
handles_incorrect_size_messages(ProtocolVersion::V02) handles_incorrect_size_messages(ProtocolVersion::V02)
} }
#[test] #[test]
#[serial] #[serial]
#[cfg_attr(miri, ignore)] // Miri does not support calls to mmap with protections other than PROT_READ|PROT_WRITE
fn handles_incorrect_size_messages_v03() { fn handles_incorrect_size_messages_v03() {
handles_incorrect_size_messages(ProtocolVersion::V03) handles_incorrect_size_messages(ProtocolVersion::V03)
} }
@@ -165,14 +163,12 @@ fn make_server_pair(protocol_version: ProtocolVersion) -> Result<(CryptoServer,
#[test] #[test]
#[serial] #[serial]
#[cfg_attr(miri, ignore)] // Miri does not support calls to mmap with protections other than PROT_READ|PROT_WRITE
fn test_regular_exchange_v02() { fn test_regular_exchange_v02() {
test_regular_exchange(ProtocolVersion::V02) test_regular_exchange(ProtocolVersion::V02)
} }
#[test] #[test]
#[serial] #[serial]
#[cfg_attr(miri, ignore)] // Miri does not support calls to mmap with protections other than PROT_READ|PROT_WRITE
fn test_regular_exchange_v03() { fn test_regular_exchange_v03() {
test_regular_exchange(ProtocolVersion::V03) test_regular_exchange(ProtocolVersion::V03)
} }
@@ -238,14 +234,12 @@ fn test_regular_exchange(protocol_version: ProtocolVersion) {
#[test] #[test]
#[serial] #[serial]
#[cfg_attr(miri, ignore)] // Miri does not support calls to mmap with protections other than PROT_READ|PROT_WRITE
fn test_regular_init_conf_retransmit_v02() { fn test_regular_init_conf_retransmit_v02() {
test_regular_init_conf_retransmit(ProtocolVersion::V02) test_regular_init_conf_retransmit(ProtocolVersion::V02)
} }
#[test] #[test]
#[serial] #[serial]
#[cfg_attr(miri, ignore)] // Miri does not support calls to mmap with protections other than PROT_READ|PROT_WRITE
fn test_regular_init_conf_retransmit_v03() { fn test_regular_init_conf_retransmit_v03() {
test_regular_init_conf_retransmit(ProtocolVersion::V03) test_regular_init_conf_retransmit(ProtocolVersion::V03)
} }
@@ -513,13 +507,11 @@ fn cookie_reply_mechanism_initiator_bails_on_message_under_load(protocol_version
} }
#[test] #[test]
#[cfg_attr(miri, ignore)] // Miri does not support calls to mmap with protections other than PROT_READ|PROT_WRITE
fn init_conf_retransmission_v02() -> Result<()> { fn init_conf_retransmission_v02() -> Result<()> {
init_conf_retransmission(ProtocolVersion::V02) init_conf_retransmission(ProtocolVersion::V02)
} }
#[test] #[test]
#[cfg_attr(miri, ignore)] // Miri does not support calls to mmap with protections other than PROT_READ|PROT_WRITE
fn init_conf_retransmission_v03() -> Result<()> { fn init_conf_retransmission_v03() -> Result<()> {
init_conf_retransmission(ProtocolVersion::V03) init_conf_retransmission(ProtocolVersion::V03)
} }

View File

@@ -1,176 +0,0 @@
//! Test vector definitions for derandomizing protocol internals.
//!
//! This module contains the definitions of internal test vector values used by
//! `CryptoServer` and the functions in `protocol.rs`. These values allow the
//! protocol implementation to be derandomized for deterministic testing and
//! reproducible behavior across runs.
//!
//! For an example of a test that uses these test vector values, see:
//! `rosenpass/tests/test_vector_crypto_server.rs`.
use crate::msgs::SESSION_ID_LEN;
use crate::protocol::basic_types::SessionId;
use crate::protocol::constants::COOKIE_VALUE_LEN;
use anyhow::anyhow;
use assert_tv::TestValue;
use assert_tv::TestVectorSet;
use base64::Engine;
use rosenpass_cipher_traits::primitives::{Aead, Kem};
use rosenpass_ciphers::{EphemeralKem, XAead, KEY_LEN};
use rosenpass_secret_memory::{Public, PublicBox, Secret};
use serde_json::Value;
#[derive(TestVectorSet)]
pub struct EncapsAndMixTestValues<const KEM_CT_LEN: usize, const KEM_SHK_LEN: usize> {
#[test_vec(serialize_with = "serialize_byte_arr")]
#[test_vec(deserialize_with = "deserialize_byte_arr")]
pub ct: TestValue<[u8; KEM_CT_LEN]>,
pub shk: TestValue<Secret<KEM_SHK_LEN>>,
}
#[derive(TestVectorSet)]
pub struct StoreBiscuitTestValues {
#[test_vec(serialize_with = "serialize_byte_vec")]
#[test_vec(deserialize_with = "deserialize_byte_vec")]
pub biscuit: TestValue<Vec<u8>>,
pub n: TestValue<Public<{ XAead::NONCE_LEN }>>,
#[test_vec(serialize_with = "serialize_byte_vec")]
#[test_vec(deserialize_with = "deserialize_byte_vec")]
pub biscuit_ct: TestValue<Vec<u8>>,
}
#[derive(TestVectorSet)]
pub struct HandleInitiationTestValues {
#[test_vec(name = "hs.cookie_value.value")]
pub init_handshake_cookie: TestValue<Secret<COOKIE_VALUE_LEN>>,
#[test_vec(name = "hs.core.sidi")]
pub init_handshake_sidi: TestValue<Public<SESSION_ID_LEN>>,
#[test_vec(name = "hs.eski")]
pub init_handshake_eski: TestValue<Secret<{ EphemeralKem::SK_LEN }>>,
#[test_vec(name = "hs.core.ck")]
pub init_handshake_epki: TestValue<Public<{ EphemeralKem::PK_LEN }>>,
#[test_vec(name = "hs.core.ck 1")]
pub init_handshake_mix_1: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "hs.core.ck 2")]
pub init_handshake_mix_2: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "ih.pidi_ct")]
#[test_vec(serialize_with = "serialize_byte_arr")]
#[test_vec(deserialize_with = "deserialize_byte_arr")]
pub init_hello_pidi_ct: TestValue<[u8; rosenpass_ciphers::Aead::TAG_LEN + 32]>,
#[test_vec(name = "hs.core.ck 3")]
pub init_handshake_mix_3: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "hs.core.ck 4")]
pub init_handshake_mix_4: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "ih.auth")]
#[test_vec(serialize_with = "serialize_byte_arr")]
#[test_vec(deserialize_with = "deserialize_byte_arr")]
pub init_hello_auth: TestValue<[u8; rosenpass_ciphers::Aead::TAG_LEN]>,
#[test_vec(name = "hs.core.ck 5")]
pub init_handshake_mix_5: TestValue<Secret<KEY_LEN>>,
}
#[derive(TestVectorSet)]
pub struct HandleInitHelloTestValues {
#[test_vec(name = "chaining_key_ihr IHR 4")]
pub chaining_key_ihr_4: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "chaining_key_ihr IHR 5")]
pub chaining_key_ihr_5: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "chaining_key_ihr IHR 6")]
pub chaining_key_ihr_6: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "chaining_key_ihr IHR 7")]
pub chaining_key_ihr_7: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "chaining_key_ihr IHR 8")]
pub chaining_key_ihr_8: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "session_id")]
pub session_id: TestValue<SessionId>,
#[test_vec(name = "chaining_key_ihr RHR 3")]
pub chaining_key_rhr_3: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "chaining_key_ihr RHR 4")]
pub chaining_key_rhr_4: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "chaining_key_ihr RHR 5")]
pub chaining_key_rhr_5: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "chaining_key_ihr RHR 6")]
pub chaining_key_rhr_6: TestValue<Secret<KEY_LEN>>,
#[test_vec(name = "chaining_key_ihr RHR 7")]
pub chaining_key_rhr_7: TestValue<Secret<KEY_LEN>>,
}
#[derive(TestVectorSet)]
pub struct InitHandshakeTestValues {
#[test_vec(serialize_with = "serialize_byte_vec")]
#[test_vec(deserialize_with = "deserialize_byte_vec")]
pub msg: TestValue<Vec<u8>>,
}
#[derive(TestVectorSet)]
pub struct CycledBiscuitSecretKeyTestValues {
#[test_vec(name = "CryptoServer::biscuit_key[r]")]
#[test_vec(description = "Biscuit key after being cycled")]
pub cycled_biscuit_secret_key: TestValue<Secret<KEY_LEN>>,
}
// Serialization helpers for raw byte arrays and vectors.
//
// These functions provide a small bridge implementation to serialize/deserialize
// standard values that do not carry serde implementations with the desired
// base64 format by default. They are used by the test vector machinery to
// encode `[u8; N]` and `Vec<u8>` values consistently.
/// Serialize a byte array as a base64 JSON string (bridge for `[u8; N]`).
pub fn serialize_byte_arr<const N: usize>(observed_value: &[u8; N]) -> anyhow::Result<Value> {
let encoded = base64::engine::general_purpose::STANDARD.encode(observed_value);
Ok(Value::String(encoded))
}
/// Deserialize a base64 JSON string into a byte array (bridge for `[u8; N]`).
pub fn deserialize_byte_arr<const N: usize>(value: &Value) -> anyhow::Result<[u8; N]> {
let value: &str = value
.as_str()
.ok_or_else(|| anyhow!("Unexpected value, expected string"))?;
let decoded = base64::engine::general_purpose::STANDARD
.decode(value.as_bytes())
.map_err(|e| anyhow!("Couldn't decode value: {e}"))?;
decoded
.as_slice()
.try_into()
.map_err(|e| anyhow!("Couldn't convert to array of size={}: {e}", N))
}
/// Serialize a byte vector as a base64 JSON string (bridge for `Vec<u8>`).
pub fn serialize_byte_vec(observed_value: &Vec<u8>) -> anyhow::Result<Value> {
let encoded = base64::engine::general_purpose::STANDARD.encode(observed_value);
Ok(Value::String(encoded))
}
/// Deserialize a base64 JSON string into a byte vector (bridge for `Vec<u8>`).
pub fn deserialize_byte_vec(value: &Value) -> anyhow::Result<Vec<u8>> {
let value: &str = value
.as_str()
.ok_or_else(|| anyhow!("Unexpected value, expected string"))?;
let decoded = base64::engine::general_purpose::STANDARD
.decode(value.as_bytes())
.map_err(|e| anyhow!("Couldn't decode value: {e}"))?;
Ok(decoded)
}

View File

@@ -105,7 +105,7 @@ fn api_integration_api_setup(protocol_version: ProtocolVersion) -> anyhow::Resul
peer: format!("{}", peer_b_wg_peer_id.fmt_b64::<8129>()), peer: format!("{}", peer_b_wg_peer_id.fmt_b64::<8129>()),
extra_params: vec![], extra_params: vec![],
}), }),
protocol_version: protocol_version, protocol_version: protocol_version.clone(),
osk_domain_separator: Default::default(), osk_domain_separator: Default::default(),
}], }],
}; };
@@ -127,7 +127,7 @@ fn api_integration_api_setup(protocol_version: ProtocolVersion) -> anyhow::Resul
endpoint: Some(peer_a_endpoint.to_owned()), endpoint: Some(peer_a_endpoint.to_owned()),
pre_shared_key: None, pre_shared_key: None,
wg: None, wg: None,
protocol_version: protocol_version, protocol_version: protocol_version.clone(),
osk_domain_separator: Default::default(), osk_domain_separator: Default::default(),
}], }],
}; };

View File

@@ -82,7 +82,7 @@ fn api_integration_test(protocol_version: ProtocolVersion) -> anyhow::Result<()>
endpoint: None, endpoint: None,
pre_shared_key: None, pre_shared_key: None,
wg: None, wg: None,
protocol_version: protocol_version, protocol_version: protocol_version.clone(),
osk_domain_separator: Default::default(), osk_domain_separator: Default::default(),
}], }],
}; };
@@ -104,7 +104,7 @@ fn api_integration_test(protocol_version: ProtocolVersion) -> anyhow::Result<()>
endpoint: Some(peer_a_endpoint.to_owned()), endpoint: Some(peer_a_endpoint.to_owned()),
pre_shared_key: None, pre_shared_key: None,
wg: None, wg: None,
protocol_version: protocol_version, protocol_version: protocol_version.clone(),
osk_domain_separator: Default::default(), osk_domain_separator: Default::default(),
}], }],
}; };

View File

@@ -10,13 +10,11 @@ use rosenpass::protocol::basic_types::{SPk, SSk, SymKey};
use rosenpass::{config::ProtocolVersion, protocol::osk_domain_separator::OskDomainSeparator}; use rosenpass::{config::ProtocolVersion, protocol::osk_domain_separator::OskDomainSeparator};
#[test] #[test]
#[cfg_attr(miri, ignore)] // unsupported operation: can't call foreign function `mprotect` on OS `linux`
fn key_exchange_with_app_server_v02() -> anyhow::Result<()> { fn key_exchange_with_app_server_v02() -> anyhow::Result<()> {
key_exchange_with_app_server(ProtocolVersion::V02) key_exchange_with_app_server(ProtocolVersion::V02)
} }
#[test] #[test]
#[cfg_attr(miri, ignore)] // unsupported operation: can't call foreign function `mprotect` on OS `linux`
fn key_exchange_with_app_server_v03() -> anyhow::Result<()> { fn key_exchange_with_app_server_v03() -> anyhow::Result<()> {
key_exchange_with_app_server(ProtocolVersion::V03) key_exchange_with_app_server(ProtocolVersion::V03)
} }

View File

@@ -3,7 +3,6 @@ use std::fs;
use rosenpass::{cli::generate_and_save_keypair, config::Rosenpass}; use rosenpass::{cli::generate_and_save_keypair, config::Rosenpass};
#[test] #[test]
#[cfg_attr(miri, ignore)] // unsupported operation: can't call foreign function `mprotect` on OS `linux`
fn example_config_rosenpass_validate() -> anyhow::Result<()> { fn example_config_rosenpass_validate() -> anyhow::Result<()> {
rosenpass_secret_memory::policy::secret_policy_use_only_malloc_secrets(); rosenpass_secret_memory::policy::secret_policy_use_only_malloc_secrets();

View File

@@ -144,7 +144,7 @@ fn check_example_config() {
let tmp_dir = tempdir().unwrap(); let tmp_dir = tempdir().unwrap();
let config_path = tmp_dir.path().join("config.toml"); let config_path = tmp_dir.path().join("config.toml");
let mut config_file = File::create(&config_path).unwrap(); let mut config_file = File::create(config_path.to_owned()).unwrap();
config_file config_file
.write_all( .write_all(
@@ -182,7 +182,6 @@ fn check_example_config() {
// check that we can exchange keys // check that we can exchange keys
#[test] #[test]
#[serial] #[serial]
#[cfg_attr(miri, ignore)] // TODO investigate why this panicks in miri
fn check_exchange_under_normal() { fn check_exchange_under_normal() {
setup_tests(); setup_tests();
setup_logging(); setup_logging();
@@ -256,7 +255,6 @@ fn check_exchange_under_normal() {
// This test creates a responder (server) with the feature flag "integration_test_always_under_load" to always be under load condition for the test. // This test creates a responder (server) with the feature flag "integration_test_always_under_load" to always be under load condition for the test.
#[test] #[test]
#[serial] #[serial]
#[cfg_attr(miri, ignore)] // integer-to-pointer cast
fn check_exchange_under_dos() { fn check_exchange_under_dos() {
setup_tests(); setup_tests();
setup_logging(); setup_logging();

View File

@@ -19,19 +19,16 @@ use rosenpass::protocol::{CryptoServer, HostIdentification, PeerPtr, PollResult,
// rosenpass::protocol::testutils; // rosenpass::protocol::testutils;
#[test] #[test]
#[cfg_attr(miri, ignore)] // unsupported operation: can't call foreign function `mprotect` on OS `linux`
fn test_successful_exchange_with_poll_v02() -> anyhow::Result<()> { fn test_successful_exchange_with_poll_v02() -> anyhow::Result<()> {
test_successful_exchange_with_poll(ProtocolVersion::V02, OskDomainSeparator::default()) test_successful_exchange_with_poll(ProtocolVersion::V02, OskDomainSeparator::default())
} }
#[test] #[test]
#[cfg_attr(miri, ignore)] // unsupported operation: can't call foreign function `mprotect` on OS `linux`
fn test_successful_exchange_with_poll_v03() -> anyhow::Result<()> { fn test_successful_exchange_with_poll_v03() -> anyhow::Result<()> {
test_successful_exchange_with_poll(ProtocolVersion::V03, OskDomainSeparator::default()) test_successful_exchange_with_poll(ProtocolVersion::V03, OskDomainSeparator::default())
} }
#[test] #[test]
#[cfg_attr(miri, ignore)] // unsupported operation: can't call foreign function `mprotect` on OS `linux`
fn test_successful_exchange_with_poll_v02_custom_domain_separator() -> anyhow::Result<()> { fn test_successful_exchange_with_poll_v02_custom_domain_separator() -> anyhow::Result<()> {
test_successful_exchange_with_poll( test_successful_exchange_with_poll(
ProtocolVersion::V02, ProtocolVersion::V02,
@@ -40,7 +37,6 @@ fn test_successful_exchange_with_poll_v02_custom_domain_separator() -> anyhow::R
} }
#[test] #[test]
#[cfg_attr(miri, ignore)] // unsupported operation: can't call foreign function `mprotect` on OS `linux`
fn test_successful_exchange_with_poll_v03_custom_domain_separator() -> anyhow::Result<()> { fn test_successful_exchange_with_poll_v03_custom_domain_separator() -> anyhow::Result<()> {
test_successful_exchange_with_poll( test_successful_exchange_with_poll(
ProtocolVersion::V03, ProtocolVersion::V03,
@@ -112,13 +108,11 @@ fn test_successful_exchange_with_poll(
} }
#[test] #[test]
#[cfg_attr(miri, ignore)] // unsupported operation: can't call foreign function `mprotect` on OS `linux`
fn test_successful_exchange_under_packet_loss_v02() -> anyhow::Result<()> { fn test_successful_exchange_under_packet_loss_v02() -> anyhow::Result<()> {
test_successful_exchange_under_packet_loss(ProtocolVersion::V02) test_successful_exchange_under_packet_loss(ProtocolVersion::V02)
} }
#[test] #[test]
#[cfg_attr(miri, ignore)] // unsupported operation: can't call foreign function `mprotect` on OS `linux`
fn test_successful_exchange_under_packet_loss_v03() -> anyhow::Result<()> { fn test_successful_exchange_under_packet_loss_v03() -> anyhow::Result<()> {
test_successful_exchange_under_packet_loss(ProtocolVersion::V03) test_successful_exchange_under_packet_loss(ProtocolVersion::V03)
} }
@@ -208,7 +202,6 @@ fn test_successful_exchange_under_packet_loss(
} }
#[test] #[test]
#[cfg_attr(miri, ignore)] // unsupported operation: can't call foreign function `mprotect` on OS `linux`
fn test_osk_label_mismatch() -> anyhow::Result<()> { fn test_osk_label_mismatch() -> anyhow::Result<()> {
// Set security policy for storing secrets; choose the one that is faster for testing // Set security policy for storing secrets; choose the one that is faster for testing
rosenpass_secret_memory::policy::secret_policy_use_only_malloc_secrets(); rosenpass_secret_memory::policy::secret_policy_use_only_malloc_secrets();

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