nomos-specs/mixnet/mixnet.py

67 lines
1.9 KiB
Python
Raw Normal View History

from __future__ import annotations
from dataclasses import dataclass
from typing import List, TypeAlias
from cryptography.hazmat.primitives.asymmetric.x25519 import (
X25519PrivateKey,
X25519PublicKey,
)
from mixnet.bls import BlsPrivateKey, BlsPublicKey
from mixnet.fisheryates import FisherYates
NodeId: TypeAlias = BlsPublicKey
# 32-byte that represents an IP address and a port of a mix node.
NodeAddress: TypeAlias = bytes
@dataclass
class Mixnet:
mix_nodes: List[MixNode]
# Build a new topology deterministically using an entropy.
# The entropy is expected to be injected from outside.
#
# TODO: Implement constructing a new topology in advance to minimize the topology transition time.
# https://www.notion.so/Mixnet-Specification-807b624444a54a4b88afa1cc80e100c2?pvs=4#9a7f6089e210454bb11fe1c10fceff68
def build_topology(
self,
entropy: bytes,
n_layers: int,
n_nodes_per_layer: int,
) -> MixnetTopology:
num_nodes = n_nodes_per_layer * n_layers
assert num_nodes < len(self.mix_nodes)
shuffled = FisherYates.shuffle(self.mix_nodes, entropy)
sampled = shuffled[:num_nodes]
layers = []
for l in range(n_layers):
start = l * n_nodes_per_layer
layer = sampled[start : start + n_nodes_per_layer]
layers.append(layer)
return MixnetTopology(layers)
@dataclass
class MixNode:
identity_public_key: BlsPublicKey
encryption_public_key: X25519PublicKey
addr: NodeAddress
def __init__(
self,
identity_private_key: BlsPrivateKey,
encryption_private_key: X25519PrivateKey,
addr: NodeAddress,
):
self.identity_public_key = identity_private_key.get_g1()
self.encryption_public_key = encryption_private_key.public_key()
self.addr = addr
@dataclass
class MixnetTopology:
layers: List[List[MixNode]]