This document describes in-depth our rust-modules and the zero-knowledge proof, and how to run various tests.
For better understanding, lets look at roundtrip of the proofing system:
- Request and retrieval of banking documents with daily statements (EBICS request and response) through an EBICS banking client, e.g. [ebics-java-client]. The client
- Pre-Processing of the EBICS Response, which is an XML document. Pre-processing is necessary to off-load as much as possible from expensive proof-generation and to get a small footprint of the proof-code. Pre-processing is done with script 'data/checkResponse.sh'
- Present data from the previous step and the private key of the client to the prover, and generate proof of computation (a STARK) and produce the [Receipt] which contains balance, currency date and account-number.
- A generic risc0 based verifier can check the proof, thus the above account data can be trusted.
- On-chain integration (validation) of the proof-system using the Substrate Off-Chain-Worker.
Important note: Milestone 1 only covers step 2. and 3., generating and validating the STARK with the Risk-Zero framework - other steps will be done in later milestones. Starting with milestone 3 integration with substrate gets implemented.
Note: You may remove RISC0_DEV_MODE=true
variable to create a real proof, expect the execution time to be several hours to create the STARK. You may add --verbose
after each command (host or verifier) to see what is going on. Use RUST_BACKTRACE=1
to debug.
Note for MacOS: Images on Dockerhub are built locally and pushed to dockerhub due to restriction of github-actions. If a certain version is needed on MacOs which was not pushed to dockerhub, build the image locally with docker build . -t fridge
or using the Script buildPublish.sh
to pushlish a release to github or dockerhub. See MacOS Development for help to give some guidance for the development environment in MacOS.
Remark on code coverage: Module
methods/guest
can not be shown because the Risc-Zero framework compiles to Risc V instruction set.
Docker containers are on dockerhub. It is crucial to understand the concept of a "sealed" binary. Means, that the (RiscV) binary producing the STARK is pinned by its hash ("Image-ID"). Proofs can only be validated if you know the Image-Id, that is why we included the Image-ID in the releases and docker tags and as a file (IMAGE_ID.hex) in the distributions.
Use bash:
bash
echo $0
# output: bash ..
We are using docker, make sure its installed:
docker --version
# output, e.g. Docker version 24.0.7, build afdd53b
Label the hyperfridge container from dockerhub you want to use with a shortcut "fridge" for later usage:
On Linux:
docker pull e36io/hyperfridge-r0:latest
docker tag e36io/hyperfridge-r0:latest fridge
# no output is given by docker
On MacOS:
docker pull e36io/hyperfridge-r0:macos-latest
docker tag e36io/hyperfridge-r0:macos-latest fridge
# no output is given by docker
Or test with docker using your local container on Linux:
# optional, don't do this for first tests unless you know what you are doing
docker build -f DockerfileLinux . -t fridge
On MacOs use:
# optional, don't do this for first tests unless you know what you are doing
docker build -f DockerfileMacOs . -t fridge
Creating MacOS image will take several hours and is not possible on github free tier. The script buildPublish.sh
is used for building and publishing the image from the local Mac.
We included all test data which is necessary to run a quick shake-down test to generate and validate a proof in one go. This creates a proof based on test data, prints the JSON-receipt which is the STARK-proof and contains public and committed data. Steps "3." and "4." of the roundtrip are tested in that way.
# The test generates a proof and validates it
docker run --env RISC0_DEV_MODE=true fridge host test
The output
Show help output:
# show help
docker run fridge host prove-camt53 --help
Create the proof as JSON file, which can be deserialized and verified in Rust:
# create the proof
docker run --env RISC0_DEV_MODE=true fridge host prove-camt53 \
--request=../data/test/test.xml --bankkey ../data/pub_bank.pem \
--clientkey ../data/client.pem --witnesskey ../data/pub_witness.pem \
--clientiban CH4308307000289537312
Show help:
# show help
docker run fridge verifier verify --help
Verify a receipt (json-file) and show its contents (public commitments):
# we need the image id and the receipt
imageid=$(docker run fridge cat /app/IMAGE_ID.hex)
proof=/data/test/test.xml-Receipt-$imageid-latest.json
# check the proof
docker run --env RISC0_DEV_MODE=true fridge verifier verify --imageid-hex=$imageid --proof-json=$proof
The binary distribution can be downloaded from github. To understand versioning concept, is crucial to understand the concept of a "sealed" binary. Means, that the (RiscV) binary producing the STARK is pinned by its hash ("Image-ID"). Proofs can only be validated if you know the Image-Id, that is why we included the Image-ID in the releases and docker tags and as a file (IMAGE_ID.hex) in the distributions.
Download binary realease from this repo, unzip the release to ./bin. Test your installation by cd-ing to bin and showing the command line help:
cd app
./host --help
# output should show command line parameters: Usage: host [OPTIONS] [COMMAND] ...
Get Image-ID of the linked guest code:
./host show-image-id
# output, e.g.: a54af3e5a903cc5d80f900f12785a337c1872098c2aacf0b7de28d7b8d6c3fe6
We included all test data in data
directory which is necessary to run a quick shake-down test to generate and validate a proof in one go. This creates a proof based on test data, prints the JSON-receipt which is the STARK-proof and contains public and committed data. Steps "3." and "4." of the roundtrip are tested in that way.
# The test generates a proof and validates it
RISC0_DEV_MODE=true ./host test
You may create new keys, additional test data and payload which is described here.
In the app directory:
# show help
./host prove-camt53 --help
# create the proof
RISC0_DEV_MODE=true ./host prove-camt53 \
--request ../data/test/test.xml --bankkey ../data/pub_bank.pem \
--clientkey ../data/client.pem --witnesskey ../data/pub_witness.pem \
--clientiban CH4308307000289537312
In the app directory of the binary distribution:
# show help
./verifier verify --help
Verify the proof:
# we need the image id and the receipt
./host show-image-id > IMAGE_ID.hex
imageid=$(cat IMAGE_ID.hex)
proof=../data/test/test.xml-Receipt-$imageid-latest.json
echo verify with $imageid
RISC0_DEV_MODE=true ./verifier verify --imageid-hex=$imageid --proof-json=$proof
We assume you have installed rust and risk zero environment. Check with rustup toolchain list --verbose | grep risc0
. Clone project: git clone git@github.com:element36-io/hyperfridge-r0.git
.
Unit tests for the host program in host
will create receipt for the test data:
cd hyperfridge-r0
cd host
RISC0_DEV_MODE=true cargo test -- --nocapture
Most important, run unit test for the guest code in directory methods/guest
:
cd ..
cd methods/guest
RISC0_DEV_MODE=true cargo test --features debug_mode -- --nocapture
If you are using the binary distribution make sure you are running a glibc compatible environment and necessary tools are installed to run the scripts for pre-processing the EBICS Response. On debian based systems you may use apt install -y openssl perl qpdf xxd libxml2-utils inotify-tools
- versions are given only as FYI, we are not aware of any version related dependencies.
Check if those commands are available/installed on Linux
apt install -y openssl perl qpdf xxd libxml2-utils inotify-tools
ldd /bin/bash # linux-vdso.so.1 (0x00007ffc33bee000) ....
opennssl version # output, e.g. OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022)
xxd --version # xxd 2021-10-22 by Juergen Weigert et al.
zlib-flate --version # zlib-flate from qpdf version 10.6.3
xmllint --version # xmllint: using libxml version 20913
perl --version # 5 Version 34
rustup toolchain list --verbose | grep risc0 # risc-zero installed: risc0 (...path...)
For running the tests with a new ebics response, lets copy the existing into a new file, then we create the proof for it:
# simulates the download of ebics file
cd data
mkdir myrequest
cp response_template.xml myrequest.xml
cp -r response_template/camt53 myrequest
# you may edit the myrequest and payload in ../data/myrequest/camt53 now
# Data above needs to be compressed, signed etc.
# Create the signed ebics response and pre-process data for proofing:
xml_file=myrequest.xml ./createTestResponse.sh
# now create the proof
# note that the proof needs the singed file: --request="../data/myrequest-generated/myrequest-generated.xml"
cd ../host
RISC0_DEV_MODE=true \
cargo run -- --verbose prove-camt53 \
--request="../data/myrequest-generated/myrequest-generated.xml" --bankkey ../data/pub_bank.pem \
--clientkey ../data/client.pem --witnesskey ../data/pub_witness.pem --clientiban CH4308307000289537312
Lets check the output:
# You see receipt in output of the command and serialized in a json file:
ls -la ../data/myrequest-generated/*.json
cat ../data/myrequest-generated/*.json
Now let's try to create a fake proof - we will use wrong public keys where the verification of signatures should fail:
# note that we use witness key for bank: --bankkey ../data/pub_witness.pem
cd host
RISC0_DEV_MODE=true \
cargo run -- --verbose prove-camt53 \
--request="../data/myrequest-generated/myrequest-generated.xml" --bankkey ../data/pub_witness.pem \
--clientkey ../data/client.pem --witnesskey ../data/pub_witness.pem --clientiban CH4308307000289537312
# panics, output:
# verify bank signature
# ---> error Verification
Wrong witness:
# note that we use bank key for witness: --witnesskey ../data/pub_bank.pem
RISC0_DEV_MODE=true \
cargo run -- --verbose prove-camt53 \
--request="../data/myrequest-generated/myrequest-generated.xml" --bankkey ../data/pub_bank.pem \
--clientkey ../data/client.pem --witnesskey ../data/pub_bank.pem --clientiban CH4308307000289537312
# panics, output:
# verify the verify_order_data_signature by witness
# ---> error Verification
Bash into the container:
docker run -it --rm --entrypoint /bin/bash fridge
For running the tests with a new ebics response, lets copy the existing into a new file, then we create the proof for it:
# simulates the download of ebics file
cd /data
rm -R -f /data/myrequest && mkdir -p myrequest
cp response_template.xml myrequest.xml
cp -r response_template/camt53 myrequest
# you may edit the myrequest and payload in ../data/myrequest/camt53 now
# Data above needs to be compressed, signed etc.
# Create the signed ebics response and pre-process data for proofing,
# should result in "Secret Input Data generated."
xml_file=myrequest.xml ./createTestResponse.sh
# now create the proof
# note that the proof needs the singed file: --request="../data/myrequest-generated/myrequest-generated.xml"
cd /app
RISC0_DEV_MODE=true \
host prove-camt53 \
--request="/data/myrequest-generated/myrequest-generated.xml" --bankkey /data/pub_bank.pem \
--clientkey /data/client.pem --witnesskey /data/pub_witness.pem --clientiban CH4308307000289537312
Lets check the output:
# You see receipt in output of the command and serialized in a json file:
ls -la /data/myrequest-generated/*.json
cat /data/myrequest-generated/*.json
Now let's try to create a fake proof - we will use wrong public keys where the verification of signatures should fail:
# note that we use witness key for bank: --bankkey ../data/pub_witness.pem
cd /app
RISC0_DEV_MODE=true \
host prove-camt53 \
--request="../data/myrequest-generated/myrequest-generated.xml" --bankkey ../data/pub_witness.pem \
--clientkey ../data/client.pem --witnesskey ../data/pub_witness.pem --clientiban CH4308307000289537312
# panics, output:
# verify bank signature
# ---> error Verification
Wrong witness:
# note that we use bank key for witness: --witnesskey ../data/pub_bank.pem
RISC0_DEV_MODE=true \
host prove-camt53 \
--request="/data/myrequest-generated/myrequest-generated.xml" --bankkey /data/pub_bank.pem \
--clientkey /data/client.pem --witnesskey /data/pub_bank.pem --clientiban CH4308307000289537312
# panics, output:
# verify the verify_order_data_signature by witness
# ---> error Verification
The test data was taken from the productive systems (Hypo Lenzburg), decrypted and encrypted again with generated keys as it can be seen in scripts data/createTestResponse.sh
and data/checkResponse.sh
. A productive sample has been added to data/test/test.xml (prod).zip
, the payload of test data remained unchanged from the productive system.