"""Ed25519 signing primitive used by the review-package signing surface.The review-package signer signs a checksum-manifest digest with Ed25519 andkeeps its profile key in encrypted secure storage. Its custody, envelopemetadata, and error vocabulary stay in:mod:`~application.modelo.review_package_signing`; the cryptography liveshere.What this module owns is deliberately narrow: key generation, the raw-byteshex projection the signer persists, and the sign / verify pair over ahex-encoded digest. It knows nothing about manifests, bundles, packages,files, or storage, so it cannot acquire a custody policy by accident.The digest is passed as HEX and decoded here, because that is the shape bothcallers hold -- ``manifest_sha256`` is a hex string on the wire and in everypersisted record. Signing the decoded 32 raw bytes (not the 64 ASCIIcharacters) is the property that must not drift between the two surfaces: averifier that decoded differently from the signer would reject every genuinesignature, and the failure would look like key mismatch rather than anencoding bug.See Also: :mod:`~application.modelo.review_package_signing` Review-package signing built on this primitive."""from__future__importannotationsfromtypingimportNamedTuplefromcryptography.exceptionsimportInvalidSignaturefromcryptography.hazmat.primitives.asymmetric.ed25519import(Ed25519PrivateKey,Ed25519PublicKey,)fromcryptography.hazmat.primitives.serializationimport(Encoding,NoEncryption,PrivateFormat,PublicFormat,)
[docs]classEd25519KeypairHex(NamedTuple):"""A freshly generated Ed25519 keypair in the raw-bytes hex form callers persist. Both halves are 32 raw bytes rendered as 64 hex characters. The private half is secret: a caller is responsible for its custody (a permission-hardened file, or encrypted secure storage), and this type carries no persistence policy of its own. """private_key_hex:strpublic_key_hex:str
[docs]defgenerate_ed25519_keypair_hex()->Ed25519KeypairHex:"""Mint a fresh Ed25519 keypair and project both halves to raw-bytes hex."""private_key=Ed25519PrivateKey.generate()returnEd25519KeypairHex(private_key_hex=private_key.private_bytes(encoding=Encoding.Raw,format=PrivateFormat.Raw,encryption_algorithm=NoEncryption(),).hex(),public_key_hex=private_key.public_key().public_bytes(encoding=Encoding.Raw,format=PublicFormat.Raw,).hex(),)
[docs]defed25519_private_key_from_hex(private_key_hex:str)->Ed25519PrivateKey:"""Reconstruct a live private key from its stored raw-bytes hex."""returnEd25519PrivateKey.from_private_bytes(bytes.fromhex(private_key_hex))
[docs]defed25519_public_key_from_hex(public_key_hex:str)->Ed25519PublicKey:"""Reconstruct a live public key from its stored raw-bytes hex."""returnEd25519PublicKey.from_public_bytes(bytes.fromhex(public_key_hex))
[docs]defsign_digest_hex(*,private_key_hex:str,digest_hex:str)->str:"""Sign a hex-encoded digest, returning the signature as hex. The digest is decoded to raw bytes before signing; see the module docstring for why that decode must be shared with the verifier. """signature=ed25519_private_key_from_hex(private_key_hex).sign(bytes.fromhex(digest_hex))returnsignature.hex()
[docs]defdigest_signature_is_valid(*,public_key_hex:str,digest_hex:str,signature_hex:str)->bool:"""Return whether ``signature_hex`` is a valid signature over ``digest_hex``. Returns ``False`` rather than raising on an invalid signature: both callers treat "signed by someone else" and "tampered" as ordinary negative verification outcomes to report, not as exceptional control flow. A malformed hex input still raises, because that is a caller bug rather than a verification verdict. """try:ed25519_public_key_from_hex(public_key_hex).verify(bytes.fromhex(signature_hex),bytes.fromhex(digest_hex),)exceptInvalidSignature:returnFalsereturnTrue