All notable changes to this project are documented here. The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.
0.2.0 - 2026-10-06
A follow-up release on the wickra 2.0 family.
- Built on wickra 2.0 and wickra-backtest 0.2.0.
wickra-core2.0, the formula-audit release of the indicator core, arrives through wickra-backtest; the exact pin onwickra-backtestmoves from =0.1.9 to =0.2.0 (root andguest/methods/guest/); every tracked lockfile follows. Indicators the audit corrected return the values of their published definitions; wickra's changelog lists them, with the warmup changes and the new defaults. - Built on wickra-proof-core 0.2.0. The exact pin moves from =0.1.5 to =0.2.0 in the host and the guest; every tracked lockfile follows.
- The guest is rebuilt on this train's family releases. Its lock -- bound to
the committed artefact -- takes wickra-core 2.0.0, wickra-backtest 0.2.0 and
wickra-proof-core 0.2.0, and a different build is a different program: the
artefact is the one risc0's container builds reproducibly (the
guest-buildjob), and the image id moves fromb96faeeb…to8efa8f7f19f20ebd96515b450a09f52b60e071f4219c4e7d8b5d6a88d90d4aac. The committed real receipt (golden/proofs/momentum.json) is re-proved for the new guest, by the 0.2.0 prover it records; its journal is the blessed one, byte for byte, only theguest_idit carries moves.
0.1.4 - 2026-09-27
The guest is rebuilt on wickra-backtest 0.1.9 and wickra-proof-core 0.1.5, whose strategy-spec schema is now generated by schemars 1.x, so the image id a verifier pins moves; what the guest computes does not. schemars 0.8 leaves every lock.
- The guest is built on this train's family releases. The guest pins its
engine exactly, like the host:
wickra-backtest=0.1.8 -> =0.1.9 andwickra-proof-core=0.1.4 -> =0.1.5, and its lock -- bound to the committed artefact -- takes schemars 1.2.2 with them. Neither release changes what a report is, so the guest computes what it computed; but a different build is a different program. The artefact is the one risc0's container builds reproducibly (theguest-buildjob), and the image id moves from1e4c18a4…tobeaf117bfc83fa052c3e981a0d5785f9a0c3753a1b4294e61465a5ba17a3bd6b. The committed real receipt (golden/proofs/momentum.json) is re-proved for the new guest, by the 0.1.4 prover it records; its journal is the blessed one, byte for byte, only theguest_idit carries moves. - The family pins follow the owners' releases.
wickra-backtest=0.1.8 -> =0.1.9,wickra-proof-core=0.1.4 -> =0.1.5 -- the exact pins this repository keeps on its siblings move to the versions those repositories release in the same train, and every tracked lockfile follows. Besides the family crates the locks moveschemars0.8.22 -> 1.2.2 (0.9.0, which risc0 brings throughserde_with, stays),schemars_derive0.8.22 -> 1.2.2 andserde_derive_internals0.29.1 -> 0.30.0, and the WebAssembly binding and the guest addref-cast1.0.27 andref-cast-impl1.0.27. - The Node binding's build-tool tree matches the family. The packages
bindings/node/package-lock.jsonholds only for@napi-rs/cli3.10.4 are resolved again, so every repository in the family builds with one identical tree; the CLI itself, which generates the committed loader, stays. - The READMEs show the organization's banner as vectors, so its text stays sharp at any width and zoom.
0.1.3 - 2026-09-23
The guest is rebuilt on the family's releases of this train -- wickra-core 1.0.6, wickra-backtest 0.1.8, wickra-proof-core 0.1.4 -- so the image id a verifier pins moves; what the guest computes does not. The R package now builds for WebAssembly, verify-only. Everything else is maintenance: the refreshed dependency tree and toolchain pins.
- The Node binding reports which artifact it loaded. The loader generated
by
@napi-rs/cli3.10.4 exports__napiBindingTarget--'native'for the native addon, otherwise the WASI flavor it resolved -- and follows aNAPI_RS_NATIVE_LIBRARY_PATHoverride to a WASI loader instead of misreporting it as native. Typed inindex.d.ts.
- The guest is built on this train's family releases. The guest pins its
engine exactly, like the host:
wickra-backtest=0.1.7 -> =0.1.8 andwickra-proof-core=0.1.3 -> =0.1.4, and its lock -- bound to the committed artefact -- takes wickra-core 1.0.6 with them. None of the three changes crate code, so the guest computes what it computed; but a different build is a different program. The artefact is the one risc0's container builds reproducibly (theguest-buildjob), and the image id moves fromcbdd1019…to1e4c18a4247ddb9b59b643909053c077f0228bebfb13b5dc4ff32f31fbf6e1a7. The committed real receipt (golden/proofs/momentum.json) is re-proved for the new guest, by the 0.1.3 prover it records; its journal is the blessed one, byte for byte, only theguest_idit carries moves. - Built on wickra-core 1.0.6. The lock takes the indicator core's latest
release, reached through
wickra-backtest; nothing here names it. - The family pins follow the owners' releases.
wickra-backtest=0.1.7 -> =0.1.8,wickra-proof-core=0.1.3 -> =0.1.4 -- the exact pins this repository keeps on its siblings move to the versions those repositories release in the same train, and every tracked lockfile follows. - Third-party dependencies refreshed.
Cargo.locktakes 140 crates to their newest versions compatible with the Rust floor (the lock now resolves MSRV-aware, see below), run across the family in one pass so every repository resolves the same day's versions. The refresh itself changes no manifest. - The lockfile resolves for the Rust floor.
.cargo/config.tomlsetsincompatible-rust-versions = "fallback", socargo updatetakes the newest version the workspace'srust-versioncan build rather than the newest release -- the setting compile, copilot and shazam already carried, now family-wide. Without it, a routine refresh elsewhere in the family raised the icu crates to 2.3.0, which declares Rust 1.88, above a 1.86 floor. Re-resolved under it, the lock needed no version the floor cannot build. @napi-rs/cli3.10.4 for the Node binding, the family's line.- uv 0.12.18 for the lockfile bootstrap in
scripts/update-lockfiles.sh, with all four platform checksums moved together. - The README's static badges are served by the organization rather than hot-linked from shields.io, so they no longer break when shields is down.
- The R package builds for WebAssembly, verify-only. r-universe's webR build
compiles the C ABI from source for
wasm32-unknown-emscriptenwith--no-default-features, but the C ABI tookwickra-zk-hostwith its defaultprovefeature regardless, so the prover'snvtxandringwent into the build and it failed.bindings/cnow forwards aprovefeature (on by default, so every native build is unchanged), and without it the C ABI verifies, commits and hashes -- theprovecommand answers that this build verifies only. Built in r-universe's toolchain (Rust nightly 2026-09-17, emcc 5.0.7) before release.
0.1.2 - 2026-09-18
- The Java binding loads the library it ships. The jar carries the native
library under
native/<os>-<arch>/-- the release pipeline stages every platform there -- but the loader only ever looked at-Dnative.lib.dirand the working directory, so a Maven Central consumer got a jar it could not load without pointing the JVM at a library it had to build itself. The loader now resolves in wickra's order:-Dnative.lib.dirwhen set, the bundled copy extracted to a temporary file, everytarget/releaseortarget/debugup the tree from the working directory and the class's own location, then the bare name.
- Family pins follow the owners' releases: wickra-backtest =0.1.4 -> =0.1.7, wickra-proof-core =0.1.2 -> =0.1.3, in the host
and in the guest. A different guest source is a different program: the docker rebuild produced a new artefact, and the image id
moves from
542491b0…tocbdd10199ba8c50e3923c2d3be331e63f464293c5db5335335a35c9e59ef29c1— a verifier that pins the old id rejects receipts from this release, which is the point of pinning. The committed real receipt (golden/proofs/momentum.json) is re-proved for the new guest; its journal is the blessed one, byte for byte. No code of this repository changes. - Every README follows wickra's shape. A cross-repo scan compared the
heading skeleton of each README against wickra's and this repository's
differed throughout. The root README opens as wickra's does (banner, badges,
the one-liner, the live-demo and ecosystem lines, no separate H1), the
License section carries wickra's wording and its
### Contributionclause, and the shared sections run in wickra's order. Each binding README isInstall,Quick start,Benchmark,Documentation,Security,Disclaimer,Licensewith the product's own surface and protocol notes as subsections; the registry pages that render them now say how to report a vulnerability and under which licence the package ships.examples/README.mdlists every language the way wickra's does, with the commands the CI examples job runs; the per-language example READMEs,fuzz/README.mdand the## Editing the docssection ofdocs/README.mdexist as they do in wickra.
-
The wasm binding's lock says what its manifests say.
bindings/wasm/Cargo.lockwas committed with the crates at 0.1.0 andwickra-proof-corefrom a git rev the workspace had long replaced with crates.io -- a detached workspace that nothing in the bump refreshes. It is re-resolved (0.1.1, registry sources); Dependabot now covers that directory so its own dependencies move too.examples/rustnamedwickra-zk-hostat 0.1.0 for the same reason and says 0.1.1. -
The repository spells shared things the way the family does. A cross-repo scan lined the 24 wickra-lib repositories up and this one also differed in:
napi = "3"/napi-derive = "3"where the family writes3.9/3.5,engines.node >= 20in the Node packages where every sibling requires 22, the C example'sCMAKE_CXX_STANDARD14 where the family builds with 17,dotnet-version: "8.0.x"in the example job, the fuzz job on a rolling nightly rather than the family's pinnednightly-2026-07-01, andexamples/nodeabsent from Dependabot. The Node lock gains the four platform packages, published since v0.1.1.wickra-backteststays at=0.1.4for now:wickra-proof-core0.1.2 pinswickra-backtest-coreto that exact version, so the move to 0.1.6 comes with wickra-proof 0.1.3, together with the guest rebuild it implies.
-
The link check covers NuGet and pkg.go.dev. Both time-boxed
lycheeexcludes written before the first release are gone:Wickra.Zkand its four runtime packages answer on nuget.org, and pkg.go.dev indexeswickra-zk-gosince v0.1.1 (verified: 200 each), so the README badges are checked like every other published link. -
BENCHMARKS.mdcarries measurements. The first nightly bench that finished (2026-09-15) replaces the placeholder: execution 237 ms, a real proof 17 min 37 s, verification 19 ms on themomentumcase, on a GitHub-hosted runner, with what each number depends on and how to reproduce it.
-
The nightly benchmark finishes.
bench.ymlmeasured real proving with Criterion's minimum of ten samples at roughly fourteen minutes a proof under a two-hour budget, so every nightly run was cancelled andBENCHMARKS.mdnever received a number. The job has the runner's six-hour budget, and the suite gainsverify/<case>, the third measurement the document promised: one real receipt produced outside the timed loop, checked against the pinned guest id. -
The pinned
uvbootstrap could not verify its download.scripts/update-lockfiles.shnamed uv 0.12.14 but kept the release checksums of 0.12.13, soWICKRA_BOOTSTRAP_UV=1fetched the archive and then refused it. The pin and all four checksums now name 0.12.15, taken from the release's.sha256files.
0.1.1 - 2026-09-15
- The NuGet package publishes. NuGet.org caps a package at 250 MB and the
prover library is about 90 MB per platform, so
Wickra.Zkwith all four runtimes inside was refused at upload (413). The native libraries now ship asWickra.Zk.runtime.<rid>, one package per runtime identifier, andWickra.Zkdepends on all four: onedotnet add packagestill brings every platform, anddotnet runwithout aRuntimeIdentifierstill finds the library throughdeps.json. The release pipeline packs the runtime packages first and pushes them ahead of the main package.
float_roundtripis stated, not inherited. The workspace and the guest now declare serde_json's correctly rounded float parser themselves.wickra-proof-corealready requires it and cargo unifies the feature across the graph, so nothing in the built binaries or the guest ELF changes; the decision just no longer lives in the engine's manifest.
0.1.0 - 2026-09-14
-
The Python 3.9 CI row installs no pytest. pytest 9.x requires 3.10, so the 3.9 row could only pin 8.4.2, which is below the fix for GHSA-6w46-j5rx-g56g and has no backport. The dev requirements are locked twice now (
ci-dev-py3.txt,ci-dev-py39.txt, both hash-pinned), the 3.9 lock carries maturin alone, and the row runs the suite throughrun_without_pytest.py-- the same modules, rewritten as plain functions with plain asserts, which 3.10 and up still run under pytest. -
The compiled guest is committed, and the prover runs in-process. The methods crate built the guest in its
build.rs, so every crate above it -- and every wheel, npm package and C ABI archive built from them -- needed the risc0 toolchain, docs.rs could never build the host, and the crate'spublish = falsemade the host unpublishable in turn.guest/builder, the one crate that needs risc0, now writesguest/methods/elf/wickra-zk-guest.binand the image id inguest/methods/src/guest_id.rs; theguest-buildjob rebuilds the guest withRISC0_USE_DOCKER=1and fails on a diff. risc0's default prover runsr0vmas a subprocess even for dev-mode receipts; with risc0-zkvm'sprovefeature the prover is in-process, so apip installor acargo installis the whole prover. The in-process prover linksmalachite(LGPL-3.0-only); the README's License section says how that is met. -
The command envelope is usable from a binding.
dataset_commitmentwas required in everyprovespec and only the host can compute it, so no binding could prove. It is optional now -- the host computes it, a stated one is held to -- and acommitcommand hashes candles for the verifying side;versionnames the guest id.verifycompared only the persistedguest_idwith the receipt, so a proof file whose journal copy lied aboutreport_hashverified; the whole persisted journal is checked now. -
Linux and macOS only. risc0 has no Windows host and the host crate does not link on MSVC; no CI matrix, release matrix or package targets Windows. The R package is
OS_type: unix. MSRV is Rust 1.90. -
The C# package is
Wickra.Zk. It wasWickra.Proof-- wickra-proof's package id, namespace and assembly name -- by copy.
-
Every binding tests both operating modes of
prove. The caller can leave the dataset commitment to the host or state it up front -- the valuecommitreturns. The journal must not depend on which, and both proofs must verify to it. Python, Node, C#, Go, Java, R and the C ABI test now re-prove every golden case with the stated commitment and compare; the WASM verifier checks the other pair of modes it has -- the committed proof bytes and the proof as the host's JSON library re-emits it decode to one journal. -
A browser demo joins the examples.
examples/wasm/verify.htmlfetches a real golden receipt and decodes its journal through the WebAssembly verifier; the Examples job parse-checks its module. -
Golden tests in every binding: each of Python, Node, Go, C#, Java, R and C proves the three golden cases through the envelope in dev-mode and holds the journal to the blessed
report_hashand metrics, verifies the proof, refuses a proof whose journal lies, and refuses a false commitment.golden/cases.jsonis the one case-to-dataset mapping every test reads.examples/cis the C ABI's first test. -
One runnable example per language under
examples/, all proving the same inputs to the samereport_hash, which the Examples job holds them to. -
The release front of the family: guard, gate, crates.io (methods, host, CLI), PyPI wheels and sdist, npm with per-platform packages, NuGet, Maven Central, the Go mirror (
wickra-lib/wickra-zk-go), C ABI archives, CLI binaries, the guest ELF and image id, SBOMs and build provenance. -
CI builds risc0's C++ kernels with clang. One of them,
risc0-circuit-keccak-sys, is a single generated file that g++ 13 spends 25 minutes optimising on a runner core and clang 18 compiles in seconds; every runner job that built the prover cold took over half an hour because of it. The Examples job builds the prover once for every language (the napi CLI's explicit--targetused to send it into a second cold build), the container wheel smoke covers the four Linux wheels the release ships, and the macOS wheel builds get the Metal toolchain risc0-sys needs.
-
The strategy crosses the host/guest boundary as JSON text. risc0's serde is a word stream, and
StrategySpecrelies on JSON semantics (skip_serializing_ifon anOption, anuntaggedenum), so written as a value it never read back: every dev-mode prove died in the guest withDeserializeBadOption. -
The node binding did not compile: cargo passes the workspace
unsafe_code = "forbid"on the command line and napi-derive'sallowcannot overrule it (E0453). The crate declares its own lints now. -
The R
configurereadWKPROOF_INC/WKPROOF_LIB; CI setsWKZK_*. -
The Node tests were ESM syntax over a CommonJS
requireand could not run. -
cargo-deny:
ruint1.20.0 fixes RUSTSEC-2026-0220;rsa,derivativeandpastehave no fixed release and are ignored with their chain and reason. -
Code scanning: every action pinned at patch level, the risc0 setup action without template expansion or
GITHUB_PATH, Dependabot cooldowns on every ecosystem, the Python CI tools installed from the hash-locked requirements. -
Follows wickra-proof's core crate rename.
proof-corebecamewickra-proof-coreupstream because the old name was taken on crates.io by an unrelated project before wickra-proof had released -- so its first publish would have failed with a permission error after the tag. The guest and the host now callwickra_proof_core::, and the pin moves to the commit that carries the rename. -
serde_with3.17.0 -> 3.22.0, clearing GHSA-7gcf-g7xr-8hxj:KeyValueMapserialisation panicked on empty sequence or map entries. Fixed from 3.21.0. -
The remaining advisory is suppressed with its reason, because it cannot be fixed here.
tracing-subscriber0.2.25 carries CVE-2025-58160 -- ANSI escape sequences can poison log output when untrusted input reaches a log line -- and the fix is 0.3.20. That version is unreachable:ark-relationsdeclares the 0.2 line, and the chain to us runs ark-relations <- ark-crypto-primitives <- ark-groth16 <- risc0-groth16 <- risc0-zkvm. A pin that blocks an update raises no PR and reports nothing; recording why is the only honest thing to do with it. Nothing here logs untrusted input through that subscriber either -- it arrives with risc0's groth16 path, which this crate does not drive. -
The guest and the host rounded differently, and the golden test's tolerance hid it.
round_to(x, 1e-8)divided by the precision and multiplied back, while the guest'sround8scaled up and back down. Those are the same arithmetic on paper and a differentf64in practice: for a pnl of1483.61984049the host produced1483.6198404900001. The guest commits its figures into the journal and the host recomputes its own, so the two have to agree bit-for-bit -- andmodel.rsalready documented the guest's expression as the contract, so the implementation contradicted its own doc comment. The implementation now matches it. The golden test compares with< 1e-8, which is why this survived. -
The guest ran on a zkVM it was not built for. It pinned
risc0-zkvm 1.2while the host executes with 3.0, so every proof aborted at runtime:Invalid trap address: 0x00000000, cause: IllegalInstruction(0xc0001073, 287). The guest is on 3.0 with the workspace. This also clears the critical advisory against risc0-zkvm 1.x (arbitrary code execution in the guest via a memory-safety failure insys_read, patched in 2.3.2). -
taiki-e/install-actionwas pinned to a commit that does not exist, so Coverage and Fuzz never got pastSet up job:Unable to resolve action ... unable to find version 6f1af7f8. Repinned to the v2.87.9 commit, which is a real object. -
Three internal path dependencies carried no version, which
cargo-denyreads as wildcards and denies. They now declareversion = "0.1.0"beside the path. -
Clippy (host)could not compile the guest.cargo clippyexportsRUSTC_WORKSPACE_WRAPPER; the child cargo thatrisc0-buildspawns inherits it, and clippy-driver then builds the guest against a stable sysroot with nostdfor the zkVM target. The job setsRISC0_SKIP_BUILD, which is what that variable is for -- the guest is still compiled for real byguest-buildand linted byclippy-guest. -
Golden re-bless. Only
report_hashmoves:pnl,sharpeandn_tradesare byte-identical to the previous fixtures. The hash covers the whole report, and the engine bump addedsymbolandtimeframeto it. -
Neither the guest nor the host had ever compiled. Both called
wickra_proof_core::hash_candlesandwickra_proof_core::hash_report, two functions that did not exist inwickra-proofand never had; the host's own doc comments called them "provisional" and the guest's module doc called itself "blind-authored". CI has 30 runs and no successful one. wickra-proof now exports those entry points, and both sides call them.The guest also read
report.sharpe,report.pnlandreport.n_tradesdirectly offBacktestReport. Those figures live onreport.metrics, and the trade count isnum_trades: usize, so the journal now reads them from there and converts withu64::try_from. -
The git dependencies floated.
wickra-backtestandwickra-proof-corewere taken from a branch with norev, so they tracked whatever upstream had last pushed. That is how the guest came to call functions that no longer existed: an unpinned git dependency never goes red, it only gets older, and then one day the API underneath has moved and the failure looks like your own. Both are pinned to exact published releases now,wickra-backtest =0.1.4andwickra-proof-core =0.1.2, in the host and the guest alike (the two must agree: proof-core 0.1.2 requireswickra-backtest-core =0.1.4, and two copies of the engine in one graph do not share aBacktestReport), anddeny.tomlno longer allows git sources at all. -
A dependency pointed at a repository that does not exist. The workspace declared
wickra-data = { git = ".../wickra-lib/wickra-data" }, which 404s --wickra-datais a crate inside thewickrarepository. No member referenced it, so it never resolved and never appeared inCargo.lock; it would have failed the build the day someone wrotewickra-data.workspace = true. Removed. -
Clippy (guest, riscv)could not pass. It rancargo clippyinguest/methods/guest, where the repository-rootrust-toolchain.tomlpins stable 1.88 -- a toolchain with nostdforriscv32im-risc0-zkvm-elf-- so the job died witherror[E0463]: can't find crate for stdon a guest that builds.guest-buildnever hit it becauserisc0-buildinvokes the risc0 toolchain itself. The job now selects it explicitly with+risc0.
-
deny.tomlandosv-scanner.tomlsuppress RUSTSEC-2025-0141 with a reason. bincode 1.3.3 is unmaintained rather than vulnerable -- development ceased after a harassment incident -- and it reaches this repository only as risc0-zkvm's serialisation format, so there is nothing here to replace and no patched version to move to. -
The documentation no longer claims the guest cannot be built.
ARCHITECTURE.md,CONTRIBUTING.md,docs/DETERMINISM.md, the guest's module doc and its manifest all stated that the guest waits on ano_stdconversion ofwickra-core->wickra-backtest->wickra-proof. It does not: risc0's guest std shim carries what those crates use, and the CI log shows every one of them -- andrayonbesides -- compiling forriscv32im-risc0-zkvm-elfbefore the guest's own five errors. The claim cost a day to disprove and would have cost the next reader the same. -
commit_datasetreturnsResult<String>rather thanString, since canonicalisation can fail.
- Project scaffolding: the host workspace manifest, dual
MIT OR Apache-2.0license, supply-chain and link config (deny.toml,lychee.toml,osv-scanner.toml,repo-metadata.toml), and the governance and community docs. - Guest program (
guest/methods/guest) and therisc0-buildmethods wrapper: bind the dataset commitment, run the deterministicwickra-backtestengine, hash the report withwickra-proof, and commit the public journal. wickra-zk-host:prove/verify/command_json, theZkSpec/PublicOutputs/ZkProofmodel,commit_datasetandnative_report_hash.wickra-zkCLI:prove/verify/version.- Golden harness (
golden/): deterministic data, three strategies, and the natively blessed{report_hash, sharpe, pnl, n_trades}the guest must reproduce. - Integration tests (roundtrip, golden hash-chain, determinism, nightly
prod_roundtrip), fuzz targets, and a criterion bench crate. - Examples (
examples/) and CI/CD workflows (CI, CodeQL, Scorecard, zizmor, links, sync-metadata, nightly prove/bench, tag-gated release). - Documentation set:
docs/{ARCHITECTURE,ZK,DETERMINISM,PROVING,Cookbook}.md.