Repository navigation
Signed model manifest (M1+M2) + design: attested abliterated models on vast - #59
Conversation
Independent review (adversarial), PR #59 at
|
Independent re-review at exact head
|
…ic-weights-seed (11 always + 3 unless a flag), matching-seed coordinated row, refuse symlinks in rehashed dirs, one encoding for none, refuse deep nesting, PREREG amendment 3 (#58)
…137, 14 of 37 fields signer's word: 11 always incl. commitment.kind, 3 unless a flag; hardening rows refused) (#58)
… 3 unless a flag), regenerate README block and CLAIMS.md (#58)
Third independent review (exact head): APPROVED at
|
Independent review, PR #59: APPROVE at
|
…-manifest # Conflicts: # README.md
Closes #58. Part of #6, #36, #9.
Draft. Implements threat model mitigations M1 + M2 (PR #54) as a detached ed25519-signed manifest with a client-side verify step next to
cp_verify(prover unchanged), and adds a design note answering "vast nodes running proven abliterated models, everything attested, like amiller/dsmack?". CPU only, no GPU spend.Updated after the second independent review (CHANGES REQUESTED at
94966765, 1 must-fix). New headfacd69cd. The must-fix and all four should-fixes are addressed below. The registered threshold did not change; code and wording changed after results, so PREREG has a dated amendment 3 and every number was re-measured at code commitc0d16125(numbers in0ac5fca1, ledger infacd69cd). Needs an exact-head re-review.Second review (at
94966765): how each item was addressedMust-fix 1.
commitment.kindis the signer's word even with--public-weights-seed. Agreed: the flag checks a seed file against the signed digest, never the kind against the commitment. The split is now 11 always (the 10 one-field fields pluscommitment.kind) + 3 unless a flag (conversion.public_weights_seed_sha256,upstream.*,conversion.committed_files); total 14 of 37 unchanged.SIGNERS_WORD_UNLESS_FLAGdropscommitment.kind; newSIGNERS_WORD_COORDINATED_ALWAYS = {commitment.kind}andSIGNERS_WORD_ALWAYS(11), asserted intest_coordinated_trusted_resign. The old made-up-digest row now covers only the seed digest.tamper.coordinated, expected exit with the flag = 0): hiding->public-weights with the digest of a seed file the signer ships,--public-weights-seedwith that file: ACCEPTED (cp_verifyYES), documented as the signer's word. Plustest_public_weights_kind_with_matching_seed_accepted(a different seed file is still refused).manifest.pydocstring,tools/manifest/README.md(kind row now says the flag checks the digest, not the kind; Tests paragraph), RESULTS.md (coordinated table + split paragraph + claim), design note (rederivation paragraph),results.yaml(summary;trusted_resign_accepted_unless_flag_fields4 -> 3; newtrusted_resign_accepted_always_fields11/37), this body and the proposed claim. README block and CLAIMS.md regenerated, not hand-edited.## Amendmentsentry 3, dated 2026-11-05 00:23 UTC, says what changed and why. Earlier lines untouched.Should-fixes (all done, not just disclosed):
{"none": 1}/{"none": 1.0}: newis_none()requires exactly{"none": true}(is True), used at every former== {"none": True}. Unit test (1, 1.0, false, "true", null all refused) and 4 runner rows, trusted re-sign: all refused.check_filesnow walks withos.walk(followlinks=False)and refuses any symlink inside a rehashed dir (file or directory, listed or not) and any non-regular file. Unit test + runner row: extraadded_tokens.jsonin a symlinked subdir of--tokenizer-dir-> refused (sub is a symlink). Side effect, disclosed in RESULTS: a caller whose tokenizer/checkpoint is a symlink tree (HF cache) must copy or dereference first.loadcatches it and refuses (nested too deeply to parse). Unit test (100k nested lists and objects) + runner row: refused, exit 1, no traceback.Ledger, at
facd69cd:python3 scripts/update-results.py:update-results: wrote README block and CLAIMS.md (20 results, 102 metrics)python3 scripts/update-results.py --check(exit 0):update-results: ok (20 results, 102 metrics, README and CLAIMS.md in sync)python3 scripts/check-claims.py(exit 0):check-claims: ok (20 claims, 14 unreplicated, README block and CLAIMS.md agree, evidence paths exist, replicated_by resolves, 44 public .md files scanned)scripts/check-no-host-paths.sh HEAD:check-no-host-paths: okFirst review (at
078d7429): how each was addressedsigned-manifest(measured, unreplicated,pr: 59) with 5 metrics, allsource: experiments/20261104-58-signed-manifest/numbers.jsonat commit2699b0a0: registered_tampers_refused 137/137, untampered_accepted 10/10, trusted_resign_accepted_fields 10/37, trusted_resign_accepted_unless_flag_fields 4/37, verify_wall median 1.414 s (SD 0.026, min 1.383, max 1.452, n=10). README block and CLAIMS.md regenerated.python3 scripts/update-results.py:update-results: wrote README block and CLAIMS.md (20 results, 101 metrics)python3 scripts/update-results.py --check(exit 0):update-results: ok (20 results, 101 metrics, README and CLAIMS.md in sync)python3 scripts/check-claims.py(exit 0):check-claims: ok (20 claims, 14 unreplicated, README block and CLAIMS.md agree, evidence paths exist, replicated_by resolves, 44 public .md files scanned)verifynow refuses a public key A or commitment R with [8]A or [8]R the identity. New tests: all 8 small-order encodings recognized; identity key + R=[r]B, S=r refused for several messages (accepted by the old code, checked); each of the 8 small-order points as A with all 8 forgeries R=[r]B+T, S=r refused; each of the 8 as R under a real key refused (identity R satisfies the bare equation and was accepted before);manifest.loadrefuses the identity-key forgery. RFC 8032 3/3 andcryptography64/64 still pass. RESULTS.md and the README state verification is cofactorless.format,commitment.kind,upstream.kind,conversion.committed_files,conversion.public_weights_seed_sha256,decode_policy.{kind,C,theta,cap,sT}); 17 are bound. New coordinated arm (tamper.coordinated, 12 schema-valid alternates re-signed by the trusted key): kind hiding->public-weights + made-up seed digest, full fake huggingface upstream + made-up committed_files, the same with--upstream-dironly, and made-up committed_files under synthetic are all ACCEPTED without the rehash flag and refused with--public-weights-seed/--upstream-dir/--committed-dir; decode-policy and serving alternates are refused without any extra flag. Tests pinSIGNERS_WORD_SINGLE(10),SCHEMA_ONLY(10) andSIGNERS_WORD_UNLESS_FLAG(commitment.kind,upstream.kind,conversion.committed_files,conversion.public_weights_seed_sha256). README, RESULTS, manifest.py docstring, the design note and the claim now say those are the signer's word unless the matching flag is passed: 14 of 37 fields on this fixture.--end-tokensis required, and the caller must pass--recipe FILEor an explicit--no-recipe(exactly one). Measured: end tokens left out -> refused; recipe left out -> refused; both -> refused;--no-recipe-> accepted, including a changedscript_sha256re-signed by the trusted key (disclosed: under--no-recipethe digest is the signer's word). The "cannot skip a check by omission" sentence is rewritten: it covers the serving and recipe flags; the three rehash flags stay optional and their fields are listed as the signer's word.## Amendments: registration committed 22:16:43Z (not 22:25), first amendment committed 22:31:55Z (not 23:20). Registration line untouched. (My own amendment entries first said "2026-11-05" by mistake; fixed inaeb23646and noted in the entry.)Should-fix: design note "measured below" now points to RESULTS.md. The article nit does not apply to the committed bytes: in line 80 the word after "A" starts with a consonant (checked byte-wise with od), so that line is unchanged. Added the signer's-word sentence next to the rederivation chain.
Part A:
tools/manifest/(measured, unreplicated)Manifest binds commitment ID, upstream checkpoint (HF repo + 40-hex revision + file sha256s, or synthetic generator), conversion recipe (script sha256, repo commit, version, params, committed files, public-weights seed digest),
policy.txt/KL.bin/layout.txtdigests, tokenizer / chat template / system prompt (digest or explicit none) + end tokens, decode policy,cp_verifybuild digest.verifytakes the signer key from the caller, rehashes everything the caller holds, runs realcp_verifywith the manifest's ID and matchesresult-v1(id, build, policy limits).PREREG
experiments/20261104-58-signed-manifest/PREREG.md(first commit, amendments 1-3 dated). ResultsRESULTS.md, rawnumbers.json(re-run atc0d16125, committed in0ac5fca1; all 174 registered rows identical to the amendment 2 run):cp_verifyYES. Threshold 10/10: PASS. Verify call median 1.407 s (SD 0.027, min 1.380, max 1.471, n=10), stored small example, shared 16-vCPU EPYC VM (amendment 2 run: 1.414 / 0.026 / 1.383 / 1.452; first run: 1.44 / 0.10 / 1.40 / 1.75)cryptography41.0.7commitment.kindrow accepted (as expected); split 11 always + 3 unless a flag = 14/37{"none":1}and{"none":1.0}x 2 fields: 6/6 refusedpython3 -m pytest -q tools/manifest: 61 passedMeasured, unreplicated.
Part B:
research/security/DESIGN-VAST-ABLITERATED.mdProposed claim (ledger entry
signed-manifestadded per TICK standard 8; nothing in loop/claims.json)commitment.kind, and 3 unless the caller passes the matching rehash flag)." (measured, needs replication)Open risks
Detached binding only (not in-statement). Pure-Python signing not constant time (tests only). Verification is cofactorless; cofactored verifiers may disagree on edge cases. No real model/tokenizer exercised; rehash flags tested on synthetic files only. Code changed after results (amendments 2 and 3); the threshold did not.
commitment.kindis only checkable by rederivation (public-weights, H100). Rehashed dirs refuse symlinks, so HF-cache layouts must be dereferenced first. Abliteration determinism untested. Vast CC finding rests on vast's 2024 article + absence of evidence.