class Security(enum.IntEnum) Values
NONE | 0 | |
|---|---|---|
NOISE_XX | 1 | |
NOISE_IK | 2 | |
NOISE_KK | 3 |
Examples
>>> ucall.Security["NOISE_XX"]
<Security.NOISE_XX: 1>
Interfaces and calls can run over the Noise protocol instead of plain TCP, authenticating both sides by 32-byte Curve25519 static keys.
import threading
import ucall
server_private_key, server_public_key = ucall.generate_noise_keypair()
client_private_key, _ = ucall.generate_noise_keypair()
client_public_key = ucall.derive_noise_public_key(client_private_key)
sealed = ucall.Interface(
"127.0.0.1:0",
security=ucall.Security.NOISE_XX,
noise_private_key=server_private_key,
peer_authorizer=lambda key: key == client_public_key,
)
server = ucall.Server(sealed)
@server.get("/whoami")
def whoami(request: ucall.Request):
_, static_key = request.peer
return static_key
runner = threading.Thread(target=server.run)
runner.start()
client = ucall.Client(
connections=1,
noise_private_key=client_private_key,
peer_authorizer=lambda key: key == server_public_key,
)
response = client.get(f"http+noise://{server.addresses[0]}/whoami")
server.stop()
runner.join()
assert bytes(response.body) == client_public_keygenerate_noise_keypair draws from the operating system’s entropy and raises ucall.Error with Status.IO when it is refused. derive_noise_public_key recovers the public half of a stored private key, which peers compare in their authorizers.
Under Noise XX both sides learn each other’s key during the handshake, so both need an authorizer; Noise IK has the client name the server’s key in advance through noise_peer_key=.
Noise KK has both sides name each other in advance: the interface admits one caller through noise_peer_key=, and the call names its own private key with noise_private_key= and the server’s with noise_peer_key=.
An http+noise:// URL implies Noise XX, and a handler reads the client’s authenticated key through request.peer.
SecurityTransport encryption of an Interface or a client call: plaintext or a Noise pattern.class Security(enum.IntEnum) NONE | 0 | |
|---|---|---|
NOISE_XX | 1 | |
NOISE_IK | 2 | |
NOISE_KK | 3 |
>>> ucall.Security["NOISE_XX"]
<Security.NOISE_XX: 1>
generate_noise_keypairDraws a fresh Noise identity from the operating system's entropy.def generate_noise_keypair() -> tuple[bytes, bytes] Interface and Client, and
the 32-byte public key that peer authorizers compare.Error: The operating system refused the entropy.>>> private_key, public_key = ucall.generate_noise_keypair()
>>> len(private_key), len(public_key)
(32, 32)
derive_noise_public_keyRecovers the public half of a stored Noise private key.def derive_noise_public_key(private_key: bytes, /) -> bytes private_keybytes | The 32-byte private key. |
|---|
ValueError: private_key is not 32 bytes long.>>> private_key, public_key = ucall.generate_noise_keypair()
>>> ucall.derive_noise_public_key(private_key) == public_key
True