src/test_vectors_44.rs — unused by Quantus, ignore
Each entry is (seed_bytes, path, expected). Extract them to a JSON fixture rather than retyping — a transcription error here produces a test that passes against the wrong answer.
What to pin
HD derivation — mnemonic + path → public key, from the vectors above.
Account id — public key → poseidonHashBytes → SS58 at prefix 189. Take known pairs from quantus-apps:quantus_sdk tests, or generate them with quantus-cli and record where they came from.
Signature determinism — the same (key, message, context) must produce the identical signature every time. The chain signs with hedge: None, and anything non-deterministic here means we have accidentally introduced randomness the reference implementation does not have.
Context separation — a signature made under "QUANTUS_EXTRINSIC" must fail verification under the empty context, and vice versa. This is the cheapest possible guard against the spec-148 boundary being got wrong somewhere downstream.
Parity CI
A test that only checks our JS against our JSON will keep passing while both drift. Add a CI job that builds the Rust crates and asserts the same vectors through both paths, so that bumping a qp-* dependency version fails loudly if it changes behaviour.
Downstream
Publish the fixture in a form quantus/common can consume directly — its keyring tests need exactly these vectors and should not be maintaining a second copy.
Companion to #1. Without this, every downstream repo is testing that it agrees with itself.
## The vectors already exist
`qp-rusty-crystals-hdwallet` ships golden HD-derivation vectors, regenerated by its own `regenerate_variant_golden_vectors`:
- `src/test_vectors_65.rs` — ML-DSA-65 (the scheme new accounts use)
- `src/test_vectors_87.rs` / `src/test_vectors.rs` — ML-DSA-87 (legacy accounts)
- `src/test_vectors_44.rs` — unused by Quantus, ignore
Each entry is `(seed_bytes, path, expected)`. Extract them to a JSON fixture rather than retyping — a transcription error here produces a test that passes against the wrong answer.
## What to pin
1. **HD derivation** — mnemonic + path → public key, from the vectors above.
2. **Account id** — public key → `poseidonHashBytes` → SS58 at prefix 189. Take known pairs from `quantus-apps:quantus_sdk` tests, or generate them with `quantus-cli` and record where they came from.
3. **Signature determinism** — the same (key, message, context) must produce the identical signature every time. The chain signs with `hedge: None`, and anything non-deterministic here means we have accidentally introduced randomness the reference implementation does not have.
4. **Context separation** — a signature made under `"QUANTUS_EXTRINSIC"` must fail verification under the empty context, and vice versa. This is the cheapest possible guard against the spec-148 boundary being got wrong somewhere downstream.
## Parity CI
A test that only checks our JS against our JSON will keep passing while both drift. Add a CI job that builds the Rust crates and asserts the same vectors through both paths, so that bumping a `qp-*` dependency version fails loudly if it changes behaviour.
## Downstream
Publish the fixture in a form quantus/common can consume directly — its keyring tests need exactly these vectors and should not be maintaining a second copy.
Context separation, one direction: a signature under QUANTUS_EXTRINSIC fails under the empty context.
Nullifiers: checked against qp-wormhole-circuit in a known-answer test.
Remaining:
Generate a JSON fixture from the hdwallet crate's own test_vectors_65.rs and _87.rs, extracted rather than retyped. The only HD pins today are two CLI-derived hashes.
Assert that fixture in both tests.rs and test/consumer.mjs.
Test the reverse direction: a signature made under the empty context fails under QUANTUS_EXTRINSIC.
Add a Gitea CI job that runs both the Rust and JS suites. Today yarn test runs Rust only, and the .github workflows are upstream's.
Ship the fixture where quantus/common can import it, which also closes out quantus/common#4's golden-vector criterion.
Checked against `main` (`dc295dc3`). Staying open.
**Done:**
- **Account ids with their sources recorded:** three dev accounts from `quantus-cli`, and the node's `TEST_WORMHOLE_ADDRESS` (`src/rs/tests.rs`).
- **Signing determinism:** `signing_is_deterministic` (ML-DSA-65 only).
- **Context separation, one direction:** a signature under `QUANTUS_EXTRINSIC` fails under the empty context.
- **Nullifiers:** checked against `qp-wormhole-circuit` in a known-answer test.
**Remaining:**
1. Generate a JSON fixture from the hdwallet crate's own `test_vectors_65.rs` and `_87.rs`, extracted rather than retyped. The only HD pins today are two CLI-derived hashes.
2. Assert that fixture in both `tests.rs` and `test/consumer.mjs`.
3. Test the reverse direction: a signature made under the empty context fails under `QUANTUS_EXTRINSIC`.
4. Add a Gitea CI job that runs both the Rust and JS suites. Today `yarn test` runs Rust only, and the `.github` workflows are upstream's.
5. Ship the fixture where quantus/common can import it, which also closes out quantus/common#4's golden-vector criterion.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Companion to #1. Without this, every downstream repo is testing that it agrees with itself.
The vectors already exist
qp-rusty-crystals-hdwalletships golden HD-derivation vectors, regenerated by its ownregenerate_variant_golden_vectors:src/test_vectors_65.rs— ML-DSA-65 (the scheme new accounts use)src/test_vectors_87.rs/src/test_vectors.rs— ML-DSA-87 (legacy accounts)src/test_vectors_44.rs— unused by Quantus, ignoreEach entry is
(seed_bytes, path, expected). Extract them to a JSON fixture rather than retyping — a transcription error here produces a test that passes against the wrong answer.What to pin
poseidonHashBytes→ SS58 at prefix 189. Take known pairs fromquantus-apps:quantus_sdktests, or generate them withquantus-cliand record where they came from.hedge: None, and anything non-deterministic here means we have accidentally introduced randomness the reference implementation does not have."QUANTUS_EXTRINSIC"must fail verification under the empty context, and vice versa. This is the cheapest possible guard against the spec-148 boundary being got wrong somewhere downstream.Parity CI
A test that only checks our JS against our JSON will keep passing while both drift. Add a CI job that builds the Rust crates and asserts the same vectors through both paths, so that bumping a
qp-*dependency version fails loudly if it changes behaviour.Downstream
Publish the fixture in a form quantus/common can consume directly — its keyring tests need exactly these vectors and should not be maintaining a second copy.
Checked against
main(dc295dc3). Staying open.Done:
quantus-cli, and the node'sTEST_WORMHOLE_ADDRESS(src/rs/tests.rs).signing_is_deterministic(ML-DSA-65 only).QUANTUS_EXTRINSICfails under the empty context.qp-wormhole-circuitin a known-answer test.Remaining:
test_vectors_65.rsand_87.rs, extracted rather than retyped. The only HD pins today are two CLI-derived hashes.tests.rsandtest/consumer.mjs.QUANTUS_EXTRINSIC.yarn testruns Rust only, and the.githubworkflows are upstream's.