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:

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:

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

See Also