2024-02-05 09:04:02 +01:00
|
|
|
from __future__ import annotations
|
|
|
|
|
2024-07-05 17:01:11 +09:00
|
|
|
import hashlib
|
2024-02-05 09:04:02 +01:00
|
|
|
import random
|
2024-07-05 17:01:11 +09:00
|
|
|
from dataclasses import dataclass, field
|
2024-06-26 15:55:00 +09:00
|
|
|
from typing import List
|
2024-02-05 09:04:02 +01:00
|
|
|
|
|
|
|
from cryptography.hazmat.primitives.asymmetric.x25519 import (
|
|
|
|
X25519PrivateKey,
|
|
|
|
X25519PublicKey,
|
|
|
|
)
|
2024-06-26 15:55:00 +09:00
|
|
|
from pysphinx.sphinx import Node as SphinxNode
|
2024-02-05 09:04:02 +01:00
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
2024-06-27 17:32:22 +09:00
|
|
|
class GlobalConfig:
|
2024-06-26 15:55:00 +09:00
|
|
|
membership: MixMembership
|
2024-07-03 23:29:26 +09:00
|
|
|
transmission_rate_per_sec: float # Global Transmission Rate
|
2024-06-27 17:32:22 +09:00
|
|
|
# TODO: use this to make the size of Sphinx packet constant
|
|
|
|
max_mix_path_length: int
|
2024-02-08 15:39:50 +09:00
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
2024-06-26 15:55:00 +09:00
|
|
|
class NodeConfig:
|
|
|
|
private_key: X25519PrivateKey
|
2024-07-03 11:41:29 +09:00
|
|
|
# The target number of peers a node should maintain in its p2p network
|
2024-06-28 12:26:44 +09:00
|
|
|
peering_degree: int
|
2024-06-27 17:32:22 +09:00
|
|
|
mix_path_length: int # TODO: use this when creating Sphinx packets
|
2024-02-08 15:39:50 +09:00
|
|
|
|
2024-07-05 17:01:11 +09:00
|
|
|
def id(self, short=False) -> str:
|
|
|
|
id = (
|
|
|
|
hashlib.sha256(self.private_key.public_key().public_bytes_raw())
|
|
|
|
.digest()
|
|
|
|
.hex()
|
|
|
|
)
|
|
|
|
return id[:8] if short else id
|
|
|
|
|
2024-02-08 15:39:50 +09:00
|
|
|
|
|
|
|
@dataclass
|
2024-06-26 15:55:00 +09:00
|
|
|
class MixMembership:
|
|
|
|
nodes: List[NodeInfo]
|
2024-07-05 17:01:11 +09:00
|
|
|
rng: random.Random = field(default_factory=random.Random)
|
2024-02-08 15:39:50 +09:00
|
|
|
|
2024-06-26 15:55:00 +09:00
|
|
|
def generate_route(self, num_hops: int, last_mix: NodeInfo) -> list[NodeInfo]:
|
2024-02-05 09:04:02 +01:00
|
|
|
"""
|
|
|
|
Generate a mix route for a Sphinx packet.
|
|
|
|
The pre-selected mix_destination is used as a last mix node in the route,
|
|
|
|
so that associated packets can be merged together into a original message.
|
|
|
|
"""
|
2024-06-28 17:37:02 +09:00
|
|
|
return [*(self.choose() for _ in range(num_hops - 1)), last_mix]
|
2024-02-05 09:04:02 +01:00
|
|
|
|
2024-06-26 15:55:00 +09:00
|
|
|
def choose(self) -> NodeInfo:
|
2024-02-05 09:04:02 +01:00
|
|
|
"""
|
2024-06-26 15:55:00 +09:00
|
|
|
Choose a mix node as a mix destination that will reconstruct a message from Sphinx packets.
|
2024-02-05 09:04:02 +01:00
|
|
|
"""
|
2024-07-05 17:01:11 +09:00
|
|
|
return self.rng.choice(self.nodes)
|
2024-02-05 09:04:02 +01:00
|
|
|
|
|
|
|
|
2024-02-08 15:39:50 +09:00
|
|
|
@dataclass
|
2024-06-26 15:55:00 +09:00
|
|
|
class NodeInfo:
|
2024-06-27 18:04:51 +09:00
|
|
|
public_key: X25519PublicKey
|
2024-02-05 09:04:02 +01:00
|
|
|
|
2024-06-26 15:55:00 +09:00
|
|
|
def sphinx_node(self) -> SphinxNode:
|
|
|
|
# TODO: Use a pre-signed incentive tx, instead of NodeAddress
|
|
|
|
dummy_node_addr = bytes(32)
|
2024-06-27 18:04:51 +09:00
|
|
|
return SphinxNode(self.public_key, dummy_node_addr)
|