"""Offline signature/binding verifier; never executes candidate code or a shell.

Usage: python t09-verify-signature.py PRIVATE-proof.json --trusted-pin PIN.json
Requires cryptography. Obtain and pin PIN.json before receiving the proof.
This verifies integrity/signing authority, not independent physical attestation.
"""
import argparse
from hashlib import sha256
import json
from pathlib import Path

from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey


def canonical(value):
    return json.dumps(value, sort_keys=True, ensure_ascii=False, separators=(',', ':'), allow_nan=False).encode()


def digest(value):
    return sha256(canonical(value)).hexdigest()


def verified(proof, pin):
    if set(proof) != {'schema', 'payload', 'causal_proof', 'judge_public_key_hex', 'signature_hex'} or proof['schema'] != 'dendra.t09.signed-queue-proof.v1':
        raise ValueError('QUEUE_PROOF_FIELDS')
    public = bytes.fromhex(proof['judge_public_key_hex'])
    if len(public) != 32 or sha256(public).hexdigest() != pin['judge_public_key_sha256']:
        raise ValueError('UNTRUSTED_SIGNER')
    Ed25519PublicKey.from_public_bytes(public).verify(bytes.fromhex(proof['signature_hex']), canonical({key: proof[key] for key in ('schema', 'payload', 'causal_proof')}))
    local = proof['causal_proof']
    if local['judge_public_key_hex'] != proof['judge_public_key_hex']:
        raise ValueError('SIGNER_MISMATCH')
    statement = local['statement']
    Ed25519PublicKey.from_public_bytes(public).verify(bytes.fromhex(local['signature_hex']), canonical(statement))
    payload, evidence = proof['payload'], proof['payload']['causal_evidence']
    if (statement['protocol_sha256'] != pin['protocol_sha256'] or statement['source_hashes'] != pin['source_hashes']
            or statement['evidence_sha256'] != digest(evidence)
            or statement['scope'] != 'LOCAL_BOUNDED_COMPONENT_CAUSALITY_ONLY' or statement['os_sandbox'] is not False):
        raise ValueError('SCOPE_OR_EVIDENCE_BINDING')
    binding = payload['challenge_binding']
    if (binding['challenge_id'] != statement['run_id'] or binding['submission_commitment'] != digest({
            'salt': binding['commitment_salt'], 'submission': evidence['submission']})):
        raise ValueError('CHALLENGE_BINDING')
    return {'signature_verified': True, 'verdict': statement['verdict'], 'scores': statement['scores'],
            'scope': statement['scope'], 'independent_os_attestation': False,
            'judge_predicate_reexecuted': False, 'general_capability_pass': False}


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('proof')
    parser.add_argument('--trusted-pin', required=True)
    args = parser.parse_args()
    if Path(args.proof).stat().st_size > 2097152 or Path(args.trusted_pin).stat().st_size > 65536:
        raise ValueError('BYTE_BUDGET')
    print(json.dumps(verified(json.loads(Path(args.proof).read_bytes()), json.loads(Path(args.trusted_pin).read_bytes())), sort_keys=True))


if __name__ == '__main__':
    main()
