Python API Reference
Side-channel claim limit. Nothing on this page claims constant-time behaviour or side-channel resistance for any target: the side-channel harness covers nothing (finding A48) and no measurement exists. The Rust and C cores are designed for constant time and unmeasured; managed runtimes (JIT, GC, bounds checks) make no timing claim. Where this page names constant-time or side-channel techniques, in prose or in code, they are design intent or recommendations, not measured properties.
Complete API documentation for MetaMUI Crypto Primitives in Python.
Installation
No package is published on a public registry yet (release candidate 1.0.0-rc.7); the coordinates below are the decided public names. Until the launch publishes them, build from the source tree (see the Installation Guide) or install a locally built candidate. The snippet was run against such a candidate; the run is recorded in the source repository’s documents/public-release/evidence/229-documentation.md.
pip install metamui-crypto==1.0.0rc7 # Python 3.10, 3.11 or 3.12
Quick Start
from metamui_crypto.facade import profile
sig = profile("ml-dsa-65")
keys = sig.generate_keypair()
signature = sig.sign(keys.secret_key, b"message", context=b"my-app")
sig.verify(keys.public_key, b"message", signature, context=b"my-app") # raises InvalidSignatureError on failure
kem = profile("ml-kem-768")
ek, dk = kem.generate_keypair()
ct, ss = kem.encapsulate(ek)
assert kem.decapsulate(dk, ct) == ss
API Documentation
For detailed API documentation, see:
- Python package summary — the facade’s 37 profile objects and its error classes
- Public API Reference — the contract the facade follows
- Main API Reference
- Python Platform Guide
Modules
Every Python block on this page, the Quick Start included, was run on 2026-10-20 against the source tree (pip install metamui-crypto-python/ into a fresh Python 3.12 virtual environment, then python -I on each block with a trailing print); each exited 0.
metamui_crypto.facade is the contract API for the post-quantum profiles (Quick Start above). Every other algorithm is a module of metamui_crypto with its own API, imported by module name; those APIs are per-algorithm and the public API contract makes no stability promise for them:
- Hashes and XOFs:
sha2,sha3,shake,keccak,blake2b,blake2s,blake3,siphash,flathash - MACs and KDFs:
hmac,cmac,poly1305,hkdf,pbkdf2,argon2 - Ciphers and AEADs:
aes256,chacha20,chacha20_poly1305,camellia,aria256,ascon,deoxys - Random generators:
aes_ctr_drbg,hmac_drbg - Classical signatures and key agreement:
ed25519,ed25519zip215,sr25519,x25519,rsa2048 - Post-quantum families (also reachable through the facade):
falcon,mlkem,dilithium,slhdsa,smaug_t,haetae,aimer,ntru_plus - Wallet utilities:
mnemonic,hdwallet
import metamui_crypto also re-exports some classes at the top level under prefixed names (MetaMUIEd25519, MetaMUIArgon2, BLAKE3, SHA256, …; metamui_crypto.__all__ lists them). The package ships a py.typed marker. metamui_crypto.DEFERRED_FAMILIES names the families the release defers; the wheel does not contain them.
Errors
The facade raises one hierarchy: every error is a MetaMuiCryptoError subclass, importable from metamui_crypto.facade.
from metamui_crypto.facade import profile, MetaMuiCryptoError, InvalidSignatureError
sig = profile("ml-dsa-65")
keys = sig.generate_keypair()
signature = sig.sign(keys.secret_key, b"message", context=b"my-app")
try:
sig.verify(keys.public_key, b"message", signature, context=b"other-app")
except InvalidSignatureError:
print("rejected: wrong context") # every facade error is a MetaMuiCryptoError
Every exception class the package defines, the facade’s included, derives from metamui_crypto.errors.MetaMUICryptoError. The per-algorithm modules raise their own classes, defined in each module’s errors submodule (for example metamui_crypto.chacha20_poly1305.errors.ChaCha20Poly1305Error), and those derive from the shared kinds in metamui_crypto.errors (InvalidKeyError, InvalidInputError, DecryptionError, VerificationError, …). An AEAD whose tag does not authenticate raises a DecryptionError subclass (ChaCha20Poly1305DecryptionError, ARIA256DecryptionError, AES256AuthenticationError, …); a key, nonce or tag of the wrong length raises an InvalidInputError/InvalidKeyError, which is also a ValueError. Some argument checks still raise the built-in TypeError or ValueError directly.
import os
from metamui_crypto.chacha20_poly1305 import decrypt, encrypt
from metamui_crypto.errors import DecryptionError, InvalidInputError, MetaMUICryptoError
key = os.urandom(32)
ciphertext, nonce, tag = encrypt(b"Secret message", key, b"metadata")
try:
plaintext = decrypt(ciphertext, key, nonce, tag, b"metadata")
except DecryptionError as e: # the tag did not authenticate
print(f"Decryption failed: {e}")
except InvalidInputError as e: # wrong key, nonce or tag length (also a ValueError)
print(f"Invalid input: {e}")
except MetaMUICryptoError as e: # any other error the package defines
print(f"Crypto error: {e}")
Examples
Password Hashing
import os
from metamui_crypto.argon2 import Argon2
argon2 = Argon2()
salt = os.urandom(16)
tag = argon2.hash("user_password", salt) # Argon2id, t=3, m=64 MiB, p=1, 32-byte tag
assert argon2.verify("user_password", salt, tag) # returns a bool
assert not argon2.verify("wrong_password", salt, tag)
Authenticated Encryption
import os
from metamui_crypto.chacha20_poly1305 import encrypt, decrypt
from metamui_crypto.chacha20_poly1305.errors import ChaCha20Poly1305Error
key = os.urandom(32)
ciphertext, nonce, tag = encrypt(b"Secret message", key, b"metadata") # a fresh 12-byte nonce per call
assert decrypt(ciphertext, key, nonce, tag, b"metadata") == b"Secret message"
try:
decrypt(ciphertext, key, nonce, tag, b"other metadata")
except ChaCha20Poly1305Error:
print("rejected: authentication failed")
Ed25519 Signatures
from metamui_crypto.ed25519 import Ed25519
private_key, public_key = Ed25519.generate_keypair() # 32-byte seed, 32-byte public key
signature = Ed25519.sign(b"message", private_key) # 64 bytes
assert Ed25519.verify(signature, b"message", public_key) # returns a bool
assert not Ed25519.verify(signature, b"other message", public_key)
Ed25519.verify returns a bool; the facade’s profiles raise instead (Errors, above).
Post-Quantum Key Exchange
Use the facade’s ml-kem-768 profile, as in the Quick Start.
Streaming Hash
from metamui_crypto.blake3 import Blake3, blake3
assert blake3(b"").hex() == "af1349b9f5f9a1a6a0404dea36dcc9499bcb25c9adc112b7cc9a93cae41f3262"
hasher = Blake3()
hasher.update(b"first chunk, ")
hasher.update(b"second chunk")
assert hasher.finalize() == blake3(b"first chunk, second chunk") # 32 bytes
What is not claimed
- Side channels: not claimed; unmeasured for every target (A48).
- Memory clearing: none. The package erases no secret; secret material stays in memory until the garbage collector reuses it (the public API contract states this per target).
- Batch verification:
metamui_crypto.ed25519.batch(batch_verify,batch_verify_single_key,batch_sign) runsEd25519.sign/verifyonce per element, in order; it is a loop, and no batch-verification speed-up is claimed. - Performance: no figure is published for this package.