Python · Noise Keys

Noise Keys

import ucall 1.0.0-rc.1 · 60202332

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_key

generate_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.

API

Types

SecurityTransport encryption of an Interface or a client call: plaintext or a Noise pattern.
__init__.py:157 ↗
class Security(enum.IntEnum)

Values

NONE0
NOISE_XX1
NOISE_IK2
NOISE_KK3

Examples

>>> ucall.Security["NOISE_XX"]
<Security.NOISE_XX: 1>

Functions

generate_noise_keypairDraws a fresh Noise identity from the operating system's entropy.
__init__.py:42 ↗
def generate_noise_keypair() -> tuple[bytes, bytes]

Returns

tuple[bytes, bytes]: The 32-byte private key, for Interface and Client, and the 32-byte public key that peer authorizers compare.

Raises

  • Error: The operating system refused the entropy.

Examples

>>> 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.
__init__.py:58 ↗
def derive_noise_public_key(private_key: bytes, /) -> bytes

Parameters

private_keybytesThe 32-byte private key.

Returns

The 32-byte public key, as a peer authorizer on the other side sees it.

Raises

  • ValueError: private_key is not 32 bytes long.

Examples

>>> private_key, public_key = ucall.generate_noise_keypair()
>>> ucall.derive_noise_public_key(private_key) == public_key
True