ed25519_util.py
python
sha256:a78e7e5a8740e03315f325d19edeb3aa1b306b3337d04abbaa9a9e0f3bbeb7a1
docs: MuseHub-first before ISR #74 — staging solidify NEXT
Human
22 hours ago
| 1 | """Ed25519 helpers for provenance signatures (§P0.4). |
| 2 | |
| 3 | The kit verifies signatures only; it never loads or stores private keys. |
| 4 | """ |
| 5 | |
| 6 | from __future__ import annotations |
| 7 | |
| 8 | import base64 |
| 9 | from typing import Any |
| 10 | |
| 11 | from cryptography.exceptions import InvalidSignature |
| 12 | from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey |
| 13 | |
| 14 | ED25519_PREFIX = "ed25519:" |
| 15 | |
| 16 | |
| 17 | class Ed25519FormatError(ValueError): |
| 18 | """Raised when an ``ed25519:`` token is malformed.""" |
| 19 | |
| 20 | |
| 21 | def encode_ed25519_token(raw: bytes) -> str: |
| 22 | """Encode raw bytes as ``ed25519:<base64>``.""" |
| 23 | return f"{ED25519_PREFIX}{base64.b64encode(raw).decode('ascii')}" |
| 24 | |
| 25 | |
| 26 | def decode_ed25519_token(token: Any, *, field: str) -> bytes: |
| 27 | """Decode ``ed25519:<base64>`` to raw bytes; fail closed on malformed input.""" |
| 28 | if not isinstance(token, str) or not token.startswith(ED25519_PREFIX): |
| 29 | raise Ed25519FormatError(f"{field} must be ed25519:<base64>") |
| 30 | payload = token[len(ED25519_PREFIX) :] |
| 31 | if not payload: |
| 32 | raise Ed25519FormatError(f"{field} must be ed25519:<base64>") |
| 33 | try: |
| 34 | return base64.b64decode(payload, validate=True) |
| 35 | except Exception as exc: |
| 36 | raise Ed25519FormatError(f"{field} must be valid base64") from exc |
| 37 | |
| 38 | |
| 39 | def verify_ed25519_signature(*, pubkey_token: str, entry_hash_hex: str, sig_token: str) -> bool: |
| 40 | """Return True when ``sig_token`` is a valid Ed25519 signature over ``entry_hash_hex``.""" |
| 41 | try: |
| 42 | pubkey_bytes = decode_ed25519_token(pubkey_token, field="provenance.pubkey") |
| 43 | sig_bytes = decode_ed25519_token(sig_token, field="provenance.sig") |
| 44 | public_key = Ed25519PublicKey.from_public_bytes(pubkey_bytes) |
| 45 | public_key.verify(sig_bytes, entry_hash_hex.encode("utf-8")) |
| 46 | except (Ed25519FormatError, InvalidSignature, ValueError): |
| 47 | return False |
| 48 | return True |
File History
2 commits
sha256:a78e7e5a8740e03315f325d19edeb3aa1b306b3337d04abbaa9a9e0f3bbeb7a1
docs: MuseHub-first before ISR #74 — staging solidify NEXT
Human
22 hours ago
sha256:4671b7f787ddbe63ced31c895b688c77ab495653b65a730b423329f26b3c1439
feat: K1-P1 complete — agent provenance, build-verification…
Sonnet 4.6
patch
52 days ago