betanet-layer-prototype/betanet_quick_impl.py
2025-08-12 08:48:19 +06:00

124 lines
4.2 KiB
Python

"""
Quick prototype of Betanet layers L1, L2, L3 and L5 in an asyncio simulation.
Disclaimer: This is a simplified educational prototype. Cryptography is simulated using
hash/HMAC placeholders (not real Ed25519/X25519). Replace placeholders with real
crypto libraries (PyNaCl / cryptography) for production-quality code.
Mapping to spec:
- L1: Path and AS-hop validation (simple path object + signature checks)
- L2: HTX session with outer 'fingerprint' mirroring and inner Noise-like handshake
- L3: Overlay mesh with simple peerstore and content exchange (bitswap-like)
- L5: Self-certifying IDs and a tiny alias ledger with finality simulation
"""
import asyncio
import time
from src.alias_ledger import AliasLedger
from src.ashop import ASHop
from src.betanet_cryptography import KeyPair
from src.htx_frame import FT_CLOSE, FT_KEY_UPDATE, FT_PING, FT_STREAM
from src.htx_session import HTXSession
from src.overlay_node import OverlayNode
from src.path import L1Path, PathSegment
async def demo():
# Create AS keys for L1 hop validation
as_keys = {
"AS1": KeyPair(),
"AS2": KeyPair(),
"AS3": KeyPair(),
}
# Create overlay nodes (L3) with keys (these also act as service endpoints L5)
nodeA = OverlayNode("Alice", KeyPair())
nodeB = OverlayNode("Bob", KeyPair())
nodeC = OverlayNode("Carol", KeyPair())
# Connect peers (mesh)
nodeA.add_peer(nodeB)
nodeB.add_peer(nodeC)
nodeA.add_peer(nodeC)
# L5: register an alias for Carol
ledger = AliasLedger()
ledger.register_alias("carol.service", nodeC.kp, seq=1, exp=int(time.time()) + 3600)
# L1: Build a SCION-like path A -> AS1 -> AS2 -> C
hop1_sig = as_keys["AS1"].sign(b"AS1")
hop2_sig = as_keys["AS2"].sign(b"AS2")
segment = PathSegment([ASHop("AS1", hop1_sig), ASHop("AS2", hop2_sig)])
path = L1Path([segment])
assert path.validate(as_keys), "L1 path validation failed"
print("[L1] Path validated")
# L2: Setup HTX session between A and C (outer fingerprint mirrored)
fingerprint = "origin:example.com:ja3hash" # placeholder
sessionAC_local = HTXSession(nodeA.kp, nodeC.kp.pub, fingerprint)
sessionAC_remote = HTXSession(nodeC.kp, nodeA.kp.pub, fingerprint)
# link peers
sessionAC_local.peer = sessionAC_remote
sessionAC_remote.peer = sessionAC_local
await asyncio.gather(
sessionAC_local.perform_handshake(), sessionAC_remote.perform_handshake()
)
# Start receive loops
async def handler_a(ftype, sid, plain):
print(
f"[L2][A] Received frame type={ftype} sid={sid} payload={plain.decode(errors='ignore')}"
)
async def handler_c(ftype, sid, plain):
print(
f"[L2][C] Received frame type={ftype} sid={sid} payload={plain.decode(errors='ignore')}"
)
asyncio.create_task(sessionAC_local.recv_loop(handler_a))
asyncio.create_task(sessionAC_remote.recv_loop(handler_c))
# L3: publish content from Carol
cid = nodeC.publish(b"Hello from Carol's content!")
print(f"[L3] Carol published CID {cid[:16]}...")
# A resolves 'carol.service' via L5
resolved_pk_hex = ledger.resolve("carol.service")
if not resolved_pk_hex:
print("[L5] Alias resolution failed")
return
print(f"[L5] Resolved carol.service -> {resolved_pk_hex[:16]}...")
# A asks overlay for CID (bitswap)
content = await nodeA.bitswap_get(cid)
if content:
print("[L3] Alice retrieved content via overlay:", content.data)
else:
print("[L3] Alice failed to retrieve content from overlay")
# A sends a message to C over HTX inner frames (L2)
await sessionAC_local.send_frame(
FT_STREAM, 1, b"GET /resource HTTP/1.1\r\nHost: carol.service\r\n\r\n"
)
await asyncio.sleep(0.2)
# Simulate KEY_UPDATE
await sessionAC_local.send_frame(FT_KEY_UPDATE, None, b"KEY_UPDATE")
await asyncio.sleep(0.2)
# Send a ping
await sessionAC_local.send_frame(FT_PING, None, b"PING")
await asyncio.sleep(0.2)
# Close
await sessionAC_local.send_frame(FT_CLOSE, None, b"GOODBYE")
await asyncio.sleep(0.2)
print("\nDemo complete.")
if __name__ == "__main__":
asyncio.run(demo())