This tool is used to verify interoperability between the sd-jwt-rust
and sd-jwt-python
implementations of the IETF SD-JWT specification.
The main idea is to generate data structures (SDJWT/presentation/verified claims) using both implementations and compare them.
The sd-jwt-python
is used to generate artifacts based on input data (specification.yml
) and store them as files.
The interop tool (based on sd-jwt-rust
) is used to generate artifacts using the same specification file, load artifacts stored in files by sd-jwt-python
and compare them. The interop tool doesn't store any files on filesystem.
There are some factors that make impossible to compare data due to non-equivalence data generated by different implementations:
- Using random 'salt' in each run that make results different even though they are generated by the same implementation.
- Not equivalent json-serialized strings (different number of spaces) generated under the hood of the different implementations.
- Using 'decoy' digests in the SD-JWT payload.
In order to reach reproducibility and equivalence of the values generated by both implementations it is required to use the same input data (issuer private key, user claims, etc.) and to get rid of some non-deterministic values during data generating (values of 'salt', for example).
In order to make it possible to get reproducible result each run it's required to use deterministic values of 'salt' used in internal algorithms. The sd-jwt-python
project implements such behavior for test purposes.
In order to use the same set of 'salt' values by the sd-jwt-rust
project Python-implementation stores values in the claims_vs_salts.json
file as artifact. The Interop tool loads values from the file and use it instead of random generated values (see the mock_salts
feature).
In order to have the same json-strings used under the hood of the both implementations there is some code that gets rid of different number of spaces:
value_str = value_str
.replace(":[", ": [")
.replace(',', ", ")
.replace("\":", "\": ")
.replace("\": ", "\": ");
In order to make it possible to compare SD-JWT
payloads that contains decoy it was decided to detect and remove all decoy
items from payloads and then compare them.
- Install the prerequisites
- Clone and build the
sd-jwt-rust
project - Clone and build the
sd-jwt-python
project - Generate artifacts using the
sd-jwt-python
project - Run the interop tool
In order to be able to build both implementations it is required to setup following tools:
Rust
/cargo
poetry
git clone [email protected]:openwallet-foundation-labs/sd-jwt-rust.git
cd sd-jwt-rust/generate
cargo build
Once the project repo is cloned to local directory it is necessary to apply special patch.
This patch is required to have some additional files as artifacts generated by the sd-jwt-python
project.
Files:
claims_vs_salts.json
file contains values of so called 'salt' that have been used duringSDJWT
issuance.issuer_key.pem
file contains the issuer's private key.issuer_public_key.pem
file contains the issuer's public key.holder_key.pem
file contains the holder's private key.
The files are used to make it possible for this tool to generate the same values of artifacts (SDJWT payload/SDJWT claims/presentation/verified claims) that are generated by sd-jwt-python
.
git clone [email protected]:openwallet-foundation-labs/sd-jwt-python.git
cd sd-jwt-python
# apply the patch
git apply ../sd-jwt-rust/generate/sd_jwt_python.patch
# build
poetry install && poetry build
pushd sd-jwt-python/tests/testcases && poetry run ../../src/sd_jwt/bin/generate.py -- example && popd
pushd sd-jwt-python/examples && poetry run ../src/sd_jwt/bin/generate.py -- example && popd
cd sd-jwt-rust/generate
sd_jwt_py="../../sd-jwt-python"
for cases_dir in $sd_jwt_py/examples $sd_jwt_py/tests/testcases; do
for test_case_dir in $(ls $cases_dir); do
if [[ -d $cases_dir/$test_case_dir ]]; then
./target/debug/sd-jwt-generate -p $cases_dir/$test_case_dir
fi
done
done