Spaces:
Running on Zero
Running on Zero
File size: 9,238 Bytes
d191420 f75eb4e d191420 f75eb4e d191420 f75eb4e d191420 f75eb4e d191420 f75eb4e d191420 f75eb4e d191420 f75eb4e d191420 f75eb4e d191420 f75eb4e d191420 f75eb4e d191420 f75eb4e d191420 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | #!/usr/bin/env python3
# SPDX-License-Identifier: Apache-2.0
# Copyright (c) 2026 FALCONS.AI. Licensed under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with the
# License. You may obtain a copy of the License at
# http://www.apache.org/licenses/LICENSE-2.0
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations.
# This file — the free verifier — is the open-source component of Model
# Surgeon (T3-a, operator-ruled Apache-2.0, 2026-08-31). The product itself
# is proprietary; see LICENSE-verifier and NOTICE in the package.
"""
FALCONS.AI Model Surgeon — FREE attestation verifier.
Anyone can verify a Surgeon package without a subscription:
python verify_attestation.py package.zip [--key HEXKEY-OR-STRING]
Checks, in order:
1. the package carries a lineage.intoto.jsonl attestation;
2. every subject artifact's SHA-256 matches the signed digest;
3. the DSSE HMAC signature verifies under the given key
(--key or FALCONSAI_HMAC_KEY; defaults to the public key).
Exit codes: 0 VERIFIED · 1 TAMPERED/INCOMPLETE · 2 not a Surgeon package.
Verification is free by design: signed creation is the paid act, universal
verification is what makes the signature worth anything.
"""
VERIFIER_VERSION = "2" # D-4 (V6.98): chain-aware
import argparse
import base64
import hashlib
import hmac
import json
import os
import sys
import zipfile
# SEC-7: this script used to default to a shipped secret — which meant the
# signing key travelled inside every exported package. Anyone holding a
# package could mint forgeries that verified. No default now: the verifier
# requires the key out of band, exactly like any other shared secret.
DEFAULT_KEY = None
def main():
ap = argparse.ArgumentParser()
ap.add_argument("package")
ap.add_argument("--key", default=os.environ.get("FALCONSAI_HMAC_KEY"))
a = ap.parse_args()
try:
z = zipfile.ZipFile(a.package)
except Exception as e:
print(f"✖ cannot open {a.package}: {e}")
sys.exit(2)
names = z.namelist()
# v6.51 container fix (UPSTREAM_NOTE): some Windows tools zip with
# backslash separators — normalize member names so those packages
# verify instead of reading "not a Surgeon package".
canon = {n.replace("\\", "/"): n for n in names}
names = list(canon)
prefix = ""
roots = {n.split("/", 1)[0] for n in names if n.strip("/")}
if len(roots) == 1 and all("/" in n for n in names if n.strip("/")):
prefix = next(iter(roots)) + "/" # Explorer-style re-zip: descend
def _zread(nm):
return z.read(canon.get(prefix + nm, prefix + nm))
try:
att = json.loads(_zread("lineage.intoto.jsonl"))
except KeyError:
print("✖ no lineage.intoto.jsonl — not a Surgeon package "
"(or the attestation was stripped).")
sys.exit(2)
payload = base64.b64decode(att.get("payload", ""))
want = (att.get("signatures") or [{}])[0].get("sig", "")
# SEC-1: asymmetric first — the package carries the publisher's PUBLIC
# key, so verification needs no secret and forgery needs the private
# key. Free verification, restored properly.
env_missing = False
sig_uncheckable = False
sig_entry = (att.get("signatures") or [{}])[0] or {}
scheme = sig_entry.get("scheme") or "hmac"
if scheme == "ed25519" and sig_entry.get("publicKey"):
try:
from cryptography.hazmat.primitives.asymmetric.ed25519 import (
Ed25519PublicKey)
Ed25519PublicKey.from_public_bytes(
bytes.fromhex(sig_entry["publicKey"])).verify(
bytes.fromhex(want), payload)
have = want
print(f"signature : ed25519 OK · publisher {sig_entry.get('keyid')}")
print(" (pin this fingerprint to establish WHO "
"signed it)")
except ImportError:
# A missing library is an ENVIRONMENT problem, not evidence of
# tampering — say so, keep checking digests, verdict INCOMPLETE.
have = None
env_missing = True
print("signature : cannot check — install the 'cryptography' "
"package (pip install cryptography) to verify ed25519")
except Exception as e:
have = None
print(f"signature : ed25519 INVALID ({e})")
elif a.key:
have = hmac.new(a.key.encode(), payload, hashlib.sha256).hexdigest()
print("signature : legacy shared-key (hmac) — anyone with the "
"key could have produced this package")
else:
have = None
sig_uncheckable = True
print("signature : legacy shared-key package; supply --key or "
"FALCONSAI_HMAC_KEY to check it (digests still verified)")
sig_ok = have is not None and hmac.compare_digest(want, have)
stmt = json.loads(payload)
print(f"verifier : {VERIFIER_VERSION}")
pt = stmt.get("predicateType")
if pt == "https://falcons.ai/model-surgeon/lineage/v1": # packages written before V7.13: the legacy id (same schema)
print(f"attestation : https://surgeon.falcons.ai/lineage/v1 (predicate type; this package carries the legacy id {pt})")
else:
print(f"attestation : {pt}")
print(f"tool : {(stmt.get('predicate') or {}).get('tool')}")
all_ok = True
for sub in stmt.get("subject", []):
nm, digest = sub["name"], sub["digest"]["sha256"]
try:
actual = hashlib.sha256(_zread(nm)).hexdigest()
ok = actual == digest
except KeyError:
actual, ok = "<missing from zip>", False
except Exception:
# e.g. the archive's own CRC rejects the entry — the byte-flip
# case. Corruption is tampering evidence, not a crash.
actual, ok = "<unreadable — fails the archive's own checksum>", False
all_ok &= ok
print(f" {'✔' if ok else '✖'} {nm}")
if not ok:
print(f" signed {digest}\n actual {actual}")
print(f"signature : {'✔ valid under this key' if sig_ok else '✖ does NOT verify under this key'}")
# D-4 (V6.98, VERIFIER 2): the lineage CHAIN. A prior attestation, when the
# package carries one, is checked for payload integrity and — when it was
# signed by THIS package's key — for signature. A prior that cannot be
# verified here is reported AMBER; it never makes this package TAMPERED.
chain = (stmt.get("predicate") or {}).get("chain")
if chain:
depth = chain.get("depth")
pr = chain.get("prior")
if not pr:
print(f"chain : depth {depth} · no prior attestation reachable at load")
else:
try:
p_env = pr.get("envelope") or {}
p_payload = base64.b64decode(p_env.get("payload", ""))
p_digest = hashlib.sha256(p_payload).hexdigest()
p_sig = (p_env.get("signatures") or [{}])[0]
intact = p_digest == pr.get("digest")
same_key = bool(sig_entry.get("publicKey")) and p_sig.get("keyid") == sig_entry.get("keyid")
p_ok = None
if intact and same_key and p_sig.get("scheme") == "ed25519" and p_sig.get("sig"):
try:
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey as _PK
_PK.from_public_bytes(bytes.fromhex(sig_entry["publicKey"])).verify(
bytes.fromhex(p_sig["sig"]), p_payload)
p_ok = True
except Exception:
p_ok = False
state = ("prior VERIFIED (same publisher key)" if p_ok else
"prior INVALID under this key — AMBER" if p_ok is False else
"prior intact · signed by another key — not verified here (AMBER)" if intact else
"prior payload does not match its recorded digest — AMBER")
print(f"chain : depth {depth} · {state} · prior keyid {str(p_sig.get('keyid') or '?')[:20]} · {len(pr.get('operations') or [])} earlier operation(s)")
except Exception as e:
print(f"chain : depth {depth} · prior present but unreadable ({e}) — AMBER")
merges = (stmt.get("predicate") or {}).get("merges") or []
if merges:
print(f"merges : {len(merges)} recorded "
f"({', '.join(sorted({m.get('method','lerp') for m in merges}))})")
verdict = "VERIFIED" if sig_ok and all_ok and stmt.get("subject") \
else "INCOMPLETE" if ((env_missing or sig_uncheckable) and all_ok) \
else "TAMPERED" if stmt.get("subject") else "INCOMPLETE"
print(f"\nVERDICT: {verdict}")
sys.exit(0 if verdict == "VERIFIED" else 1)
if __name__ == "__main__":
main()
|