mirror of
https://github.com/PR0M3TH3AN/SeedPass.git
synced 2026-11-07 21:32:25 +00:00
test(core): run the official BIP-85 spec vectors directly against the TS core
Every other derivation check compares this implementation against Python -- cross-verification, not ground truth. The BIP-85 specification's own test vectors (spec master xprv, 12- and 24-word BIP-39 children at index 0) are immune to the failure mode where both of our implementations share a misconception and agree with each other: Python has pinned them since early on (test_bip85_vectors.py), and now the TypeScript core runs them natively via a new Bip85.fromExtendedKey factory (the spec vectors start from an xprv, not a mnemonic). Python's pinned app-32 entropy and TOTP derivations from the same master ride along as cross-family anchors. All four pass on first contact -- an independent confirmation of the root derivation ahead of the external review, and recorded as such in the #34 review-strategy notes in TODO.md, along with the ultrareview size blocker (PR #989 spans 720k lines including beta's history) and its fallback options. Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Tkj4rzKBA3uhfgk7kqjsb8
This commit is contained in:
1 parent
eb67dac576
commit
ecff57e8c6
3 files changed
+79
-3
No files matched your search
@@ -127,7 +127,22 @@ everything still open, in the order it should be tackled.
|
||||
|
||||
### Blockers before real secrets
|
||||
|
||||
- [ ] **Independent security review of the TypeScript branch.** No one but the
|
||||
- [ ] **Independent security review of the TypeScript branch.** Review
|
||||
strategy (decided 2026-08-18): two AI families plus vectors, because
|
||||
they fail differently. (1) `/code-review ultra` — **blocked**: PR #989
|
||||
spans main→port including beta's 150 commits (6795 files/720k lines),
|
||||
over ultra's size limit; fallback options are a review-only PR
|
||||
containing just the `js/` tree against main, or a narrower local-diff
|
||||
target. (2) A GPT-family pass (Codex) over the four ranked targets in
|
||||
the PR body, briefed to REFUTE the security claims in file comments,
|
||||
not summarize them. (3) Third-party ground truth where possible: the
|
||||
official BIP-85 spec vectors now run directly against the TS core
|
||||
(test/bip85SpecVectors.test.ts; Python has had them all along), which
|
||||
closes the both-implementations-agree-and-are-both-wrong hole for the
|
||||
root derivation. Triage rule for findings: flagged by both families =
|
||||
almost certainly real; flagged by one = verify against code, arbiter
|
||||
is a reproduction test or the cross-impl suite, never the author's
|
||||
opinion alone. No one but the
|
||||
authoring agent has read this code. Two earlier review rounds on this
|
||||
project each found criticals that self-review missed, so a green suite and
|
||||
an author's sign-off are not evidence of much. Scope it to
|
||||
|
||||
@@ -102,14 +102,25 @@ export interface DeriveEntropyOptions {
|
||||
export class Bip85 {
|
||||
private readonly root: HDKey;
|
||||
|
||||
constructor(seed: Uint8Array) {
|
||||
this.root = HDKey.fromMasterSeed(seed);
|
||||
constructor(seed: Uint8Array | HDKey) {
|
||||
this.root = seed instanceof HDKey ? seed : HDKey.fromMasterSeed(seed);
|
||||
}
|
||||
|
||||
static fromMnemonic(mnemonic: string, passphrase = ""): Bip85 {
|
||||
return new Bip85(mnemonicToSeedSync(canonicalizeMnemonic(mnemonic), passphrase));
|
||||
}
|
||||
|
||||
/**
|
||||
* From a BIP-32 extended private key. Exists so the official BIP-85 spec
|
||||
* test vectors — which start from an xprv, not a mnemonic — can be run
|
||||
* directly against this implementation (third-party ground truth, immune
|
||||
* to the failure mode where both of our implementations agree with each
|
||||
* other and are both wrong).
|
||||
*/
|
||||
static fromExtendedKey(xprv: string): Bip85 {
|
||||
return new Bip85(HDKey.fromExtendedKey(xprv));
|
||||
}
|
||||
|
||||
deriveEntropy(opts: DeriveEntropyOptions): Uint8Array {
|
||||
const appNo = opts.appNo ?? 39;
|
||||
let path: string;
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* BIP-85 official spec test vectors, run directly against this implementation.
|
||||
*
|
||||
* Every other derivation check in this repo compares us against the Python
|
||||
* implementation — which is cross-verification, not ground truth. These
|
||||
* vectors come from the BIP-85 specification itself (also pinned in Python's
|
||||
* test_bip85_vectors.py), so a shared misconception between our two
|
||||
* implementations cannot pass here.
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { Bip85, deriveTotpSecret, bytesToHex } from "@seedpass/core";
|
||||
|
||||
// The spec's master key (BIP-85 test vectors section).
|
||||
const MASTER_XPRV =
|
||||
"xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb";
|
||||
|
||||
// Official BIP-39 application vectors (12 and 24 English words, index 0).
|
||||
const SPEC_12 =
|
||||
"girl mad pet galaxy egg matter matrix prison refuse sense ordinary nose";
|
||||
const SPEC_24 =
|
||||
"puppy ocean match cereal symbol another shed magic wrap hammer bulb intact gadget divorce twin tonight reason outdoor destroy simple truth cigar social volcano";
|
||||
|
||||
// SeedPass-specific derivations from the same master, pinned identically in
|
||||
// Python's suite (not spec vectors, but a cross-family anchor for app 32 and
|
||||
// the TOTP path).
|
||||
const PY_SSH_ENTROPY =
|
||||
"52405cd0dd21c5be78314a7c1a3c65ffd8d896536cc7dee3157db5824f0c92e2";
|
||||
const PY_TOTP_SECRET = "VQYTWDNEWYBY2G3LOGGCEKR4LZ3LNEYY";
|
||||
|
||||
describe("BIP-85 spec vectors", () => {
|
||||
const bip85 = Bip85.fromExtendedKey(MASTER_XPRV);
|
||||
|
||||
it("derives the spec's 12-word BIP-39 vector", () => {
|
||||
expect(bip85.deriveMnemonic(0, 12)).toBe(SPEC_12);
|
||||
});
|
||||
|
||||
it("derives the spec's 24-word BIP-39 vector", () => {
|
||||
expect(bip85.deriveMnemonic(0, 24)).toBe(SPEC_24);
|
||||
});
|
||||
|
||||
it("matches Python's pinned app-32 entropy from the spec master", () => {
|
||||
const entropy = bip85.deriveEntropy({ index: 0, entropyBytes: 32, appNo: 32 });
|
||||
expect(bytesToHex(entropy)).toBe(PY_SSH_ENTROPY);
|
||||
});
|
||||
|
||||
it("matches Python's pinned TOTP secret derived from the spec's 24-word child", () => {
|
||||
expect(deriveTotpSecret(SPEC_24, 0)).toBe(PY_TOTP_SECRET);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user