<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Cradicle Explorer</title>
    <link href="/css/bootstrap/bootstrap.min.css" rel="stylesheet">
    <style>
      .form-control-dark::placeholder {
          color: #aaa;
          opacity: 1;
      }
    </style>
    <link rel="stylesheet" href="/assets/fontawesome/css/all.min.css">
    <link rel="icon" type="image/png" href="/favicon.png">


                <link href="/css/dashboard.css" rel="stylesheet">
                </head>
                <body>
                <header class="navbar navbar-dark sticky-top bg-dark flex-md-nowrap p-0 shadow">
                  <a class="navbar-brand col-md-3 col-lg-2 me-0 px-3 fs-6" href="/">Cradicle Explorer</a>
                  <button class="navbar-toggler position-absolute d-md-none collapsed" type="button" data-bs-toggle="collapse" data-bs-target="#sidebarMenu" aria-controls="sidebarMenu" aria-expanded="false" aria-label="Toggle navigation">
                    <span class="navbar-toggler-icon"></span>
                  </button>
                  <form method="get" action="/cgi-bin/main" style="width:100%;"><input class="form-control form-control-dark w-100 rounded-0 border-0" type="text" name="q" placeholder="Search repos" aria-label="Search"></form>
                  <div class="navbar-nav flex-row">
                    <div class="nav-item text-nowrap">
                      <a class="nav-link px-3 active" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX">abzu</a>
                    </div>
                  </div>
                </header>
                <div class="container-fluid">
                  <div class="row">
                    <nav id="sidebarMenu" class="col-md-3 col-lg-2 d-md-block bg-dark sidebar collapse">
                      <div class="position-sticky pt-3 sidebar-sticky">
                        <ul class="nav flex-column">
                          <li class="nav-item">
                            <a class="nav-link" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX">
                              <i class="align-text-bottom fa-solid fa-info"></i>
                              Info
                            </a>
                          </li>
                          <li class="nav-item">
                            <a class="nav-link" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&issue=list">
                              <i class="align-text-bottom fa-solid fa-layer-group"></i>
                              Issues
                            </a>
                          </li>
                          <li class="nav-item">
                            <a class="nav-link" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&patch=list">
                              <i class="align-text-bottom fa-solid fa-vest-patches"></i>
                              Patches
                            </a>
                          </li>
                          <li class="nav-item">
                            <a class="nav-link" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&wallet=list">
                              <i class="align-text-bottom fa-solid fa-wallet"></i>
                              Wallets
                            </a>
                          </li>
                          <li class="nav-item">
                            <a class="nav-link active" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=.">
                              <i class="align-text-bottom fa-solid fa-code"></i>
                              Source
                            </a>
                          </li>
                        <h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-4 mb-1 text-muted text-uppercase">
                          <span></span>
                        </h6>
                        <ul class="nav flex-column mb-2">
                        
    <h6 class="sidebar-heading d-flex justify-content-between align-items-center px-3 mt-1 mb-1 text-muted text-uppercase">
      <span>Source</span>
    </h6>
    <li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=.agent"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> .agent</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=.library_data"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> .library_data</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=.seeker_data"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> .seeker_data</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=.test_data"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> .test_data</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=_vendor"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> _vendor</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=abzu-account"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> abzu-account</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=abzu-chameleon"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> abzu-chameleon</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=abzu-core"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> abzu-core</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=abzu-daemon"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> abzu-daemon</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=abzu-dht"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> abzu-dht</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=abzu-ffi"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> abzu-ffi</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=abzu-inference"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> abzu-inference</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=abzu-router"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> abzu-router</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=abzu-sdk"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> abzu-sdk</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=abzu-token"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> abzu-token</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=abzu-transport"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> abzu-transport</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=apps"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> apps</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=docs"><i class="fa-solid fa-folder-open" style="color:#f0c040;"></i> docs</a></li><li><a class="nav-link py-0" style="padding-left:32px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=docs%2F.context"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> .context</a></li><li><a class="nav-link py-0" style="padding-left:32px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=docs%2Fabzu_handbook"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> abzu_handbook</a></li><li><a class="nav-link py-0" style="padding-left:32px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=docs%2Farchive"><i class="fa-solid fa-folder-open" style="color:#f0c040;"></i> archive</a></li><li><a class="nav-link py-0" style="padding-left:48px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=docs%2Farchive%2Faudit-2026-01"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> audit-2026-01</a></li><li><a class="nav-link py-0" style="padding-left:48px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2Farchive%2FARCHITECTURE_old.md"><i class="fa-solid fa-file" style="color:#888;"></i> ARCHITECTURE_old.md</a></li><li><a class="nav-link py-0" style="padding-left:48px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2Farchive%2FAbzu_Design_Overview_v0.3.1.md"><i class="fa-solid fa-file" style="color:#888;"></i> Abzu_Design_Overview_v0.3.1.md</a></li><li><a class="nav-link py-0" style="padding-left:48px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2Farchive%2FAbzu_Technical_Overview_v0.2.html"><i class="fa-solid fa-file" style="color:#888;"></i> Abzu_Technical_Overview_v0.2.html</a></li><li><a class="nav-link py-0" style="padding-left:48px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2Farchive%2FAbzu_Technical_Overview_v0.2.md"><i class="fa-solid fa-file" style="color:#888;"></i> Abzu_Technical_Overview_v0.2.md</a></li><li><a class="nav-link py-0" style="padding-left:48px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2Farchive%2FAbzu_Technical_Overview_v0.2.pdf"><i class="fa-solid fa-file" style="color:#888;"></i> Abzu_Technical_Overview_v0.2.pdf</a></li><li><a class="nav-link py-0" style="padding-left:48px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2Farchive%2FCIRCLE_TRUST_POLICIES_old.md"><i class="fa-solid fa-file" style="color:#888;"></i> CIRCLE_TRUST_POLICIES_old.md</a></li><li><a class="nav-link py-0" style="padding-left:48px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2Farchive%2FDHT_DESIGN_old.md"><i class="fa-solid fa-file" style="color:#888;"></i> DHT_DESIGN_old.md</a></li><li><a class="nav-link py-0" style="padding-left:48px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2Farchive%2FGhost_Mode_old.md"><i class="fa-solid fa-file" style="color:#888;"></i> Ghost_Mode_old.md</a></li><li><a class="nav-link py-0 active" style="padding-left:48px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2Farchive%2FNAT_TRAVERSAL_old.md"><i class="fa-solid fa-file" style="color:#888;"></i> NAT_TRAVERSAL_old.md</a></li><li><a class="nav-link py-0" style="padding-left:48px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2Farchive%2FREADME.md"><i class="fa-solid fa-file" style="color:#888;"></i> README.md</a></li><li><a class="nav-link py-0" style="padding-left:48px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2Farchive%2FSTUN_NAT_TRAVERSAL.md"><i class="fa-solid fa-file" style="color:#888;"></i> STUN_NAT_TRAVERSAL.md</a></li><li><a class="nav-link py-0" style="padding-left:48px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2Farchive%2FTECHNICAL_SPECIFICATION_old.md"><i class="fa-solid fa-file" style="color:#888;"></i> TECHNICAL_SPECIFICATION_old.md</a></li><li><a class="nav-link py-0" style="padding-left:48px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2Farchive%2FUNIFIED_DOCUMENTATION_v0.3.md"><i class="fa-solid fa-file" style="color:#888;"></i> UNIFIED_DOCUMENTATION_v0.3.md</a></li><li><a class="nav-link py-0" style="padding-left:48px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2Farchive%2FWHITE_PAPER_old.md"><i class="fa-solid fa-file" style="color:#888;"></i> WHITE_PAPER_old.md</a></li><li><a class="nav-link py-0" style="padding-left:48px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2Farchive%2FWHITE_PAPER_v0.3.md"><i class="fa-solid fa-file" style="color:#888;"></i> WHITE_PAPER_v0.3.md</a></li><li><a class="nav-link py-0" style="padding-left:48px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2Farchive%2FWHITE_PAPER_v0.3.pdf"><i class="fa-solid fa-file" style="color:#888;"></i> WHITE_PAPER_v0.3.pdf</a></li><li><a class="nav-link py-0" style="padding-left:32px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=docs%2Fassets"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> assets</a></li><li><a class="nav-link py-0" style="padding-left:32px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=docs%2Fdeep-dive"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> deep-dive</a></li><li><a class="nav-link py-0" style="padding-left:32px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=docs%2Fhuman"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> human</a></li><li><a class="nav-link py-0" style="padding-left:32px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=docs%2Fnotebooklm"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> notebooklm</a></li><li><a class="nav-link py-0" style="padding-left:32px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=docs%2Ftests"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> tests</a></li><li><a class="nav-link py-0" style="padding-left:32px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2FAGENT_BRIEFING.md"><i class="fa-solid fa-file" style="color:#888;"></i> AGENT_BRIEFING.md</a></li><li><a class="nav-link py-0" style="padding-left:32px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2FCODEBASE_GUIDE.md"><i class="fa-solid fa-file" style="color:#888;"></i> CODEBASE_GUIDE.md</a></li><li><a class="nav-link py-0" style="padding-left:32px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2FCOMPONENT_REFERENCE.md"><i class="fa-solid fa-file" style="color:#888;"></i> COMPONENT_REFERENCE.md</a></li><li><a class="nav-link py-0" style="padding-left:32px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2FCRATE_MAP.md"><i class="fa-solid fa-file" style="color:#888;"></i> CRATE_MAP.md</a></li><li><a class="nav-link py-0" style="padding-left:32px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2FFAULT_TOLERANCE_IMPLEMENTATION.md"><i class="fa-solid fa-file" style="color:#888;"></i> FAULT_TOLERANCE_IMPLEMENTATION.md</a></li><li><a class="nav-link py-0" style="padding-left:32px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2FGhost_Mode_Security_Audit.md"><i class="fa-solid fa-file" style="color:#888;"></i> Ghost_Mode_Security_Audit.md</a></li><li><a class="nav-link py-0" style="padding-left:32px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2FINDEX.md"><i class="fa-solid fa-file" style="color:#888;"></i> INDEX.md</a></li><li><a class="nav-link py-0" style="padding-left:32px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2FMEMORY.md"><i class="fa-solid fa-file" style="color:#888;"></i> MEMORY.md</a></li><li><a class="nav-link py-0" style="padding-left:32px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2FMULTI_TENANT_ARCHITECTURE.md"><i class="fa-solid fa-file" style="color:#888;"></i> MULTI_TENANT_ARCHITECTURE.md</a></li><li><a class="nav-link py-0" style="padding-left:32px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2FSDK_API_REFERENCE.md"><i class="fa-solid fa-file" style="color:#888;"></i> SDK_API_REFERENCE.md</a></li><li><a class="nav-link py-0" style="padding-left:32px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2FTOKEN_ARCHITECTURE.md"><i class="fa-solid fa-file" style="color:#888;"></i> TOKEN_ARCHITECTURE.md</a></li><li><a class="nav-link py-0" style="padding-left:32px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=docs%2FWIRE_PROTOCOL_API.md"><i class="fa-solid fa-file" style="color:#888;"></i> WIRE_PROTOCOL_API.md</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=network"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> network</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=packages"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> packages</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=scripts"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> scripts</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=sovereign-agent"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> sovereign-agent</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=sovereign-wallet"><i class="fa-solid fa-folder" style="color:#f0c040;"></i> sovereign-wallet</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=.gitignore"><i class="fa-solid fa-file" style="color:#888;"></i> .gitignore</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=.markdownlintrc"><i class="fa-solid fa-file" style="color:#888;"></i> .markdownlintrc</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=AGENTS.md"><i class="fa-solid fa-file" style="color:#888;"></i> AGENTS.md</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=CLAUDE.md"><i class="fa-solid fa-file" style="color:#888;"></i> CLAUDE.md</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=CONTRIBUTING.md"><i class="fa-solid fa-file" style="color:#888;"></i> CONTRIBUTING.md</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=Cargo.lock"><i class="fa-solid fa-file" style="color:#888;"></i> Cargo.lock</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=Cargo.toml"><i class="fa-solid fa-file" style="color:#888;"></i> Cargo.toml</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=Gemini_Generated_Image_b955xfb955xfb955.jpg"><i class="fa-solid fa-file" style="color:#888;"></i> Gemini_Generated_Image_b955xfb955xfb955.jpg</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=LICENSE"><i class="fa-solid fa-file" style="color:#888;"></i> LICENSE</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=NOTICE"><i class="fa-solid fa-file" style="color:#888;"></i> NOTICE</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=README.md"><i class="fa-solid fa-file" style="color:#888;"></i> README.md</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=deny.toml"><i class="fa-solid fa-file" style="color:#888;"></i> deny.toml</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=following.json"><i class="fa-solid fa-file" style="color:#888;"></i> following.json</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=moltbook.json"><i class="fa-solid fa-file" style="color:#888;"></i> moltbook.json</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=prepare_nlm.sh"><i class="fa-solid fa-file" style="color:#888;"></i> prepare_nlm.sh</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=prepare_nlm_full.sh"><i class="fa-solid fa-file" style="color:#888;"></i> prepare_nlm_full.sh</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=profile.json"><i class="fa-solid fa-file" style="color:#888;"></i> profile.json</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=sovereign_agent.db"><i class="fa-solid fa-file" style="color:#888;"></i> sovereign_agent.db</a></li><li><a class="nav-link py-0" style="padding-left:16px;" href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&file=teleport_test.sh"><i class="fa-solid fa-file" style="color:#888;"></i> teleport_test.sh</a></li>
    
                        </ul>
                      </div>
                    </nav>
                <main class="col-md-9 ms-sm-auto col-lg-10">
                  <div class="container px-1 py-3">
        
<div class="mb-2" style="font-size:1.1rem;"><a href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=.">/</a> <a href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=docs">docs</a> / <a href="/cgi-bin/repo?id=z3g8vEyv3XfBUnDq17xgVegmBvyFX&source=docs%2Farchive">archive</a> / NAT_TRAVERSAL_old.md</div>
        <div class="list-group">
        <div class="list-group-item">
        <div class="mb-2" style="font-weight:bold;"><i class="fa-solid fa-file"></i> NAT_TRAVERSAL_old.md</div>
        <pre style="margin:0; font-size:0.85rem; overflow-x:auto; color:#fafafa;"><span style="color:#666; user-select:none;">  1</span>  # NAT Traversal &amp; Perfect Forward Secrecy
<span style="color:#666; user-select:none;">  2</span>  
<span style="color:#666; user-select:none;">  3</span>  Technical deep-dive into Abzu&#x27;s network traversal and cryptographic key exchange systems.
<span style="color:#666; user-select:none;">  4</span>  
<span style="color:#666; user-select:none;">  5</span>  ---
<span style="color:#666; user-select:none;">  6</span>  
<span style="color:#666; user-select:none;">  7</span>  ## 1. Sovereign STUN Server
<span style="color:#666; user-select:none;">  8</span>  
<span style="color:#666; user-select:none;">  9</span>  Abzu includes a **zero-log STUN server** that enables nodes to discover their public-facing address without relying on external infrastructure.
<span style="color:#666; user-select:none;"> 10</span>  
<span style="color:#666; user-select:none;"> 11</span>  ### Architecture
<span style="color:#666; user-select:none;"> 12</span>  
<span style="color:#666; user-select:none;"> 13</span>  ```
<span style="color:#666; user-select:none;"> 14</span>  ┌─────────────────┐       UDP :3478        ┌──────────────────┐
<span style="color:#666; user-select:none;"> 15</span>  │   Abzu Client   │ ────────────────────► │   Abzu Daemon    │
<span style="color:#666; user-select:none;"> 16</span>  │  (behind NAT)   │ ◄──────────────────── │   (STUN Server)  │
<span style="color:#666; user-select:none;"> 17</span>  │                 │   XorMappedAddress    │                  │
<span style="color:#666; user-select:none;"> 18</span>  └─────────────────┘                        └──────────────────┘
<span style="color:#666; user-select:none;"> 19</span>  ```
<span style="color:#666; user-select:none;"> 20</span>  
<span style="color:#666; user-select:none;"> 21</span>  ### Location
<span style="color:#666; user-select:none;"> 22</span>  
<span style="color:#666; user-select:none;"> 23</span>  - **Module**: `abzu-daemon/src/stun.rs`
<span style="color:#666; user-select:none;"> 24</span>  - **Binding**: UDP port 3478 (RFC 5389 default)
<span style="color:#666; user-select:none;"> 25</span>  - **Startup**: Concurrent with daemon&#x27;s main event loop
<span style="color:#666; user-select:none;"> 26</span>  
<span style="color:#666; user-select:none;"> 27</span>  ### Protocol Flow
<span style="color:#666; user-select:none;"> 28</span>  
<span style="color:#666; user-select:none;"> 29</span>  1. Client sends `BindingRequest` with random 96-bit transaction ID
<span style="color:#666; user-select:none;"> 30</span>  2. Server parses request via `stun_proto` crate
<span style="color:#666; user-select:none;"> 31</span>  3. Server responds with `XorMappedAddress` containing client&#x27;s observed IP:port
<span style="color:#666; user-select:none;"> 32</span>  4. Client now knows its public endpoint
<span style="color:#666; user-select:none;"> 33</span>  
<span style="color:#666; user-select:none;"> 34</span>  ### Zero-Log Policy
<span style="color:#666; user-select:none;"> 35</span>  
<span style="color:#666; user-select:none;"> 36</span>  The STUN server implements strict privacy:
<span style="color:#666; user-select:none;"> 37</span>  
<span style="color:#666; user-select:none;"> 38</span>  ```rust
<span style="color:#666; user-select:none;"> 39</span>  // No source IP logging
<span style="color:#666; user-select:none;"> 40</span>  // No transaction ID logging  
<span style="color:#666; user-select:none;"> 41</span>  // No timestamps
<span style="color:#666; user-select:none;"> 42</span>  // Stateless operation - no binding tables
<span style="color:#666; user-select:none;"> 43</span>  ```
<span style="color:#666; user-select:none;"> 44</span>  
<span style="color:#666; user-select:none;"> 45</span>  ### Code Highlights
<span style="color:#666; user-select:none;"> 46</span>  
<span style="color:#666; user-select:none;"> 47</span>  ```rust
<span style="color:#666; user-select:none;"> 48</span>  pub fn build_binding_response(
<span style="color:#666; user-select:none;"> 49</span>      source: SocketAddr,
<span style="color:#666; user-select:none;"> 50</span>      transaction_id: TransactionId,
<span style="color:#666; user-select:none;"> 51</span>  ) -&gt; Option&lt;Vec&lt;u8&gt;&gt; {
<span style="color:#666; user-select:none;"> 52</span>      let mtype = MessageType::new(BINDING, Class::Success);
<span style="color:#666; user-select:none;"> 53</span>      let mut builder = Message::builder(mtype, transaction_id, MessageWriteVec::new());
<span style="color:#666; user-select:none;"> 54</span>      
<span style="color:#666; user-select:none;"> 55</span>      // XOR masking per RFC 5389 - prevents ALG interference
<span style="color:#666; user-select:none;"> 56</span>      let xma = XorMappedAddress::new(source, transaction_id);
<span style="color:#666; user-select:none;"> 57</span>      builder.add_attribute(&amp;xma).ok()?;
<span style="color:#666; user-select:none;"> 58</span>      
<span style="color:#666; user-select:none;"> 59</span>      Some(builder.into_owned().to_vec())
<span style="color:#666; user-select:none;"> 60</span>  }
<span style="color:#666; user-select:none;"> 61</span>  ```
<span style="color:#666; user-select:none;"> 62</span>  
<span style="color:#666; user-select:none;"> 63</span>  ---
<span style="color:#666; user-select:none;"> 64</span>  
<span style="color:#666; user-select:none;"> 65</span>  ## 2. NAT Type Detection
<span style="color:#666; user-select:none;"> 66</span>  
<span style="color:#666; user-select:none;"> 67</span>  Before establishing peer connections, Abzu determines the NAT type to select the appropriate traversal strategy.
<span style="color:#666; user-select:none;"> 68</span>  
<span style="color:#666; user-select:none;"> 69</span>  ### NAT Classification
<span style="color:#666; user-select:none;"> 70</span>  
<span style="color:#666; user-select:none;"> 71</span>  | Type | Behavior | Traversability |
<span style="color:#666; user-select:none;"> 72</span>  |------|----------|----------------|
<span style="color:#666; user-select:none;"> 73</span>  | **Full Cone** | Any external host can send to mapped port | ✅ Easy |
<span style="color:#666; user-select:none;"> 74</span>  | **Restricted Cone** | Only hosts the client contacted can reply | ⚠️ Moderate |
<span style="color:#666; user-select:none;"> 75</span>  | **Port Restricted** | Only exact IP:port pairs can reply | ⚠️ Hard |
<span style="color:#666; user-select:none;"> 76</span>  | **Symmetric** | Different mapping per destination | ❌ Relay needed |
<span style="color:#666; user-select:none;"> 77</span>  
<span style="color:#666; user-select:none;"> 78</span>  ### Detection Algorithm
<span style="color:#666; user-select:none;"> 79</span>  
<span style="color:#666; user-select:none;"> 80</span>  ```
<span style="color:#666; user-select:none;"> 81</span>  ┌──────────────────────────────────────────────────────────────┐
<span style="color:#666; user-select:none;"> 82</span>  │                    NAT Detection Flow                        │
<span style="color:#666; user-select:none;"> 83</span>  ├──────────────────────────────────────────────────────────────┤
<span style="color:#666; user-select:none;"> 84</span>  │                                                              │
<span style="color:#666; user-select:none;"> 85</span>  │  1. Query STUN Server A ──► Get mapped address X:P1          │
<span style="color:#666; user-select:none;"> 86</span>  │                                                              │
<span style="color:#666; user-select:none;"> 87</span>  │  2. Query STUN Server B ──► Get mapped address Y:P2          │
<span style="color:#666; user-select:none;"> 88</span>  │                                                              │
<span style="color:#666; user-select:none;"> 89</span>  │  3. Compare results:                                         │
<span style="color:#666; user-select:none;"> 90</span>  │     • X:P1 == Y:P2  →  Cone NAT (predictable)               │
<span style="color:#666; user-select:none;"> 91</span>  │     • X:P1 != Y:P2  →  Symmetric NAT (unpredictable)        │
<span style="color:#666; user-select:none;"> 92</span>  │                                                              │
<span style="color:#666; user-select:none;"> 93</span>  └──────────────────────────────────────────────────────────────┘
<span style="color:#666; user-select:none;"> 94</span>  ```
<span style="color:#666; user-select:none;"> 95</span>  
<span style="color:#666; user-select:none;"> 96</span>  ### Configuration
<span style="color:#666; user-select:none;"> 97</span>  
<span style="color:#666; user-select:none;"> 98</span>  ```rust
<span style="color:#666; user-select:none;"> 99</span>  pub struct NatConfig {
<span style="color:#666; user-select:none;">100</span>      pub stun_servers: Vec&lt;String&gt;,  // Prioritizes localhost:3478
<span style="color:#666; user-select:none;">101</span>      pub timeout: Duration,           // Default: 3s
<span style="color:#666; user-select:none;">102</span>      pub retries: u32,                // Default: 3
<span style="color:#666; user-select:none;">103</span>  }
<span style="color:#666; user-select:none;">104</span>  ```
<span style="color:#666; user-select:none;">105</span>  
<span style="color:#666; user-select:none;">106</span>  ### Retry Logic
<span style="color:#666; user-select:none;">107</span>  
<span style="color:#666; user-select:none;">108</span>  Exponential backoff with jitter prevents thundering herd:
<span style="color:#666; user-select:none;">109</span>  
<span style="color:#666; user-select:none;">110</span>  ```rust
<span style="color:#666; user-select:none;">111</span>  let delay = base_timeout * 2^attempt + random_jitter(0..100ms)
<span style="color:#666; user-select:none;">112</span>  ```
<span style="color:#666; user-select:none;">113</span>  
<span style="color:#666; user-select:none;">114</span>  ---
<span style="color:#666; user-select:none;">115</span>  
<span style="color:#666; user-select:none;">116</span>  ## 3. Hole Punching
<span style="color:#666; user-select:none;">117</span>  
<span style="color:#666; user-select:none;">118</span>  For nodes behind NAT, Abzu performs coordinated hole punching to establish direct connections.
<span style="color:#666; user-select:none;">119</span>  
<span style="color:#666; user-select:none;">120</span>  ### Rendezvous Protocol
<span style="color:#666; user-select:none;">121</span>  
<span style="color:#666; user-select:none;">122</span>  ```
<span style="color:#666; user-select:none;">123</span>      Node A                    Relay                    Node B
<span style="color:#666; user-select:none;">124</span>        │                         │                         │
<span style="color:#666; user-select:none;">125</span>        │── Announce(A_pub) ────►│                         │
<span style="color:#666; user-select:none;">126</span>        │                         │◄── Announce(B_pub) ────│
<span style="color:#666; user-select:none;">127</span>        │◄── PeerInfo(B_pub) ────│                         │
<span style="color:#666; user-select:none;">128</span>        │                         │──── PeerInfo(A_pub) ──►│
<span style="color:#666; user-select:none;">129</span>        │                         │                         │
<span style="color:#666; user-select:none;">130</span>        │◄═══════════════════════ Simultaneous Open ═════════════════════►│
<span style="color:#666; user-select:none;">131</span>        │                         │                         │
<span style="color:#666; user-select:none;">132</span>  ```
<span style="color:#666; user-select:none;">133</span>  
<span style="color:#666; user-select:none;">134</span>  ### Address Exchange Wire Format
<span style="color:#666; user-select:none;">135</span>  
<span style="color:#666; user-select:none;">136</span>  ```rust
<span style="color:#666; user-select:none;">137</span>  AbzuFrame::Announce {
<span style="color:#666; user-select:none;">138</span>      peer_id: [u8; 32],      // Ed25519 public key
<span style="color:#666; user-select:none;">139</span>      addresses: Vec&lt;String&gt;, // Candidate addresses
<span style="color:#666; user-select:none;">140</span>      nat_type: NatType,      // Detected NAT classification
<span style="color:#666; user-select:none;">141</span>      timestamp: u64,         // Unix epoch, validated ±5 min
<span style="color:#666; user-select:none;">142</span>  }
<span style="color:#666; user-select:none;">143</span>  ```
<span style="color:#666; user-select:none;">144</span>  
<span style="color:#666; user-select:none;">145</span>  ### Timestamp Validation
<span style="color:#666; user-select:none;">146</span>  
<span style="color:#666; user-select:none;">147</span>  Announcements are rejected if older than 5 minutes to prevent replay attacks:
<span style="color:#666; user-select:none;">148</span>  
<span style="color:#666; user-select:none;">149</span>  ```rust
<span style="color:#666; user-select:none;">150</span>  let age = now.saturating_sub(announce.timestamp);
<span style="color:#666; user-select:none;">151</span>  if age &gt; 300 {
<span style="color:#666; user-select:none;">152</span>      return Err(TransportError::StaleAnnouncement);
<span style="color:#666; user-select:none;">153</span>  }
<span style="color:#666; user-select:none;">154</span>  ```
<span style="color:#666; user-select:none;">155</span>  
<span style="color:#666; user-select:none;">156</span>  ---
<span style="color:#666; user-select:none;">157</span>  
<span style="color:#666; user-select:none;">158</span>  ## 4. Perfect Forward Secrecy
<span style="color:#666; user-select:none;">159</span>  
<span style="color:#666; user-select:none;">160</span>  Every FakeTLS connection performs **ephemeral X25519 key exchange**, ensuring that compromise of the pre-shared key (PSK) doesn&#x27;t expose past sessions.
<span style="color:#666; user-select:none;">161</span>  
<span style="color:#666; user-select:none;">162</span>  ### Cryptographic Stack
<span style="color:#666; user-select:none;">163</span>  
<span style="color:#666; user-select:none;">164</span>  | Layer | Algorithm | Purpose |
<span style="color:#666; user-select:none;">165</span>  |-------|-----------|---------|
<span style="color:#666; user-select:none;">166</span>  | Key Agreement | X25519 | Ephemeral Diffie-Hellman |
<span style="color:#666; user-select:none;">167</span>  | Key Derivation | HKDF-SHA256 | Session key extraction |
<span style="color:#666; user-select:none;">168</span>  | Encryption | ChaCha20-Poly1305 | Authenticated encryption |
<span style="color:#666; user-select:none;">169</span>  
<span style="color:#666; user-select:none;">170</span>  ### Module Structure
<span style="color:#666; user-select:none;">171</span>  
<span style="color:#666; user-select:none;">172</span>  ```
<span style="color:#666; user-select:none;">173</span>  abzu-transport/src/
<span style="color:#666; user-select:none;">174</span>  ├── key_exchange.rs      # EphemeralKeypair, derive_session_key()
<span style="color:#666; user-select:none;">175</span>  └── transports/
<span style="color:#666; user-select:none;">176</span>      └── fake_tls.rs      # connect_pfs(), accept_pfs()
<span style="color:#666; user-select:none;">177</span>  ```
<span style="color:#666; user-select:none;">178</span>  
<span style="color:#666; user-select:none;">179</span>  ### Handshake Sequence
<span style="color:#666; user-select:none;">180</span>  
<span style="color:#666; user-select:none;">181</span>  ```
<span style="color:#666; user-select:none;">182</span>      Client                                          Server
<span style="color:#666; user-select:none;">183</span>        │                                               │
<span style="color:#666; user-select:none;">184</span>        │  1. Generate ephemeral X25519 keypair         │
<span style="color:#666; user-select:none;">185</span>        │  2. Embed public key in ClientHello           │
<span style="color:#666; user-select:none;">186</span>        │                                               │
<span style="color:#666; user-select:none;">187</span>        │──────── ClientHello [client_pub] ───────────►│
<span style="color:#666; user-select:none;">188</span>        │                                               │
<span style="color:#666; user-select:none;">189</span>        │                       3. Extract client_pub   │
<span style="color:#666; user-select:none;">190</span>        │                       4. Generate server keypair
<span style="color:#666; user-select:none;">191</span>        │                       5. Compute DH shared secret
<span style="color:#666; user-select:none;">192</span>        │                       6. Derive session key   │
<span style="color:#666; user-select:none;">193</span>        │                                               │
<span style="color:#666; user-select:none;">194</span>        │◄─────── ServerHello [server_pub] ────────────│
<span style="color:#666; user-select:none;">195</span>        │                                               │
<span style="color:#666; user-select:none;">196</span>        │  7. Extract server_pub                        │
<span style="color:#666; user-select:none;">197</span>        │  8. Compute DH shared secret                  │
<span style="color:#666; user-select:none;">198</span>        │  9. Derive session key                        │
<span style="color:#666; user-select:none;">199</span>        │                                               │
<span style="color:#666; user-select:none;">200</span>        │◄═══════ Encrypted with session_key ═════════►│
<span style="color:#666; user-select:none;">201</span>  ```
<span style="color:#666; user-select:none;">202</span>  
<span style="color:#666; user-select:none;">203</span>  ### Session Key Derivation
<span style="color:#666; user-select:none;">204</span>  
<span style="color:#666; user-select:none;">205</span>  The session key binds both ephemeral secrecy and authentication:
<span style="color:#666; user-select:none;">206</span>  
<span style="color:#666; user-select:none;">207</span>  ```rust
<span style="color:#666; user-select:none;">208</span>  pub fn derive_session_key(
<span style="color:#666; user-select:none;">209</span>      dh_shared: &amp;[u8; 32],    // X25519 shared secret
<span style="color:#666; user-select:none;">210</span>      psk: Option&lt;&amp;[u8; 32]&gt;,  // Pre-shared key for authentication
<span style="color:#666; user-select:none;">211</span>      salt: Option&lt;&amp;[u8]&gt;,      // Optional additional context
<span style="color:#666; user-select:none;">212</span>  ) -&gt; [u8; 32] {
<span style="color:#666; user-select:none;">213</span>      // Combine DH secret with PSK
<span style="color:#666; user-select:none;">214</span>      let mut ikm = dh_shared.to_vec();
<span style="color:#666; user-select:none;">215</span>      if let Some(key) = psk {
<span style="color:#666; user-select:none;">216</span>          ikm.extend_from_slice(key);
<span style="color:#666; user-select:none;">217</span>      }
<span style="color:#666; user-select:none;">218</span>      
<span style="color:#666; user-select:none;">219</span>      // HKDF extraction and expansion
<span style="color:#666; user-select:none;">220</span>      let hk = Hkdf::&lt;Sha256&gt;::new(salt, &amp;ikm);
<span style="color:#666; user-select:none;">221</span>      let mut session_key = [0u8; 32];
<span style="color:#666; user-select:none;">222</span>      hk.expand(b&quot;abzu-session-v1&quot;, &amp;mut session_key).unwrap();
<span style="color:#666; user-select:none;">223</span>      
<span style="color:#666; user-select:none;">224</span>      session_key
<span style="color:#666; user-select:none;">225</span>  }
<span style="color:#666; user-select:none;">226</span>  ```
<span style="color:#666; user-select:none;">227</span>  
<span style="color:#666; user-select:none;">228</span>  ### Key Security Properties
<span style="color:#666; user-select:none;">229</span>  
<span style="color:#666; user-select:none;">230</span>  | Property | Mechanism | Guarantee |
<span style="color:#666; user-select:none;">231</span>  |----------|-----------|-----------|
<span style="color:#666; user-select:none;">232</span>  | **Forward Secrecy** | Ephemeral X25519 | Past sessions safe if PSK leaks |
<span style="color:#666; user-select:none;">233</span>  | **Authentication** | PSK binding | Only nodes with PSK derive same key |
<span style="color:#666; user-select:none;">234</span>  | **Key Separation** | HKDF context | Each session has unique key material |
<span style="color:#666; user-select:none;">235</span>  | **No Key Reuse** | Fresh keypairs | Every connection isolated |
<span style="color:#666; user-select:none;">236</span>  
<span style="color:#666; user-select:none;">237</span>  ### TLS Camouflage Integration
<span style="color:#666; user-select:none;">238</span>  
<span style="color:#666; user-select:none;">239</span>  Public keys are embedded in the `key_share` extension of the fake TLS handshake:
<span style="color:#666; user-select:none;">240</span>  
<span style="color:#666; user-select:none;">241</span>  ```
<span style="color:#666; user-select:none;">242</span>  ClientHello structure:
<span style="color:#666; user-select:none;">243</span>  ┌─────────────────────────────────────────┐
<span style="color:#666; user-select:none;">244</span>  │ TLS Record Header (5 bytes)             │
<span style="color:#666; user-select:none;">245</span>  │ Handshake Header (4 bytes)              │
<span style="color:#666; user-select:none;">246</span>  │ Client Version (2 bytes)                │
<span style="color:#666; user-select:none;">247</span>  │ Random (32 bytes)                       │
<span style="color:#666; user-select:none;">248</span>  │ Session ID (variable)                   │
<span style="color:#666; user-select:none;">249</span>  │ Cipher Suites (variable)                │
<span style="color:#666; user-select:none;">250</span>  │ Extensions:                             │
<span style="color:#666; user-select:none;">251</span>  │   ├─ server_name (SNI)                  │
<span style="color:#666; user-select:none;">252</span>  │   ├─ supported_versions (TLS 1.3)       │
<span style="color:#666; user-select:none;">253</span>  │   └─ key_share ◄── X25519 public key    │
<span style="color:#666; user-select:none;">254</span>  │         └─ 32 bytes at offset 79        │
<span style="color:#666; user-select:none;">255</span>  └─────────────────────────────────────────┘
<span style="color:#666; user-select:none;">256</span>  ```
<span style="color:#666; user-select:none;">257</span>  
<span style="color:#666; user-select:none;">258</span>  ### Connection Methods
<span style="color:#666; user-select:none;">259</span>  
<span style="color:#666; user-select:none;">260</span>  ```rust
<span style="color:#666; user-select:none;">261</span>  // Client initiates PFS connection
<span style="color:#666; user-select:none;">262</span>  let stream = FakeTlsStream::connect_pfs(
<span style="color:#666; user-select:none;">263</span>      &quot;relay.example.com:443&quot;,
<span style="color:#666; user-select:none;">264</span>      Some(&amp;psk),  // Optional PSK for authentication
<span style="color:#666; user-select:none;">265</span>  ).await?;
<span style="color:#666; user-select:none;">266</span>  
<span style="color:#666; user-select:none;">267</span>  // Server accepts PFS connection
<span style="color:#666; user-select:none;">268</span>  let stream = FakeTlsStream::accept_pfs(
<span style="color:#666; user-select:none;">269</span>      tcp_stream,
<span style="color:#666; user-select:none;">270</span>      Some(&amp;psk),
<span style="color:#666; user-select:none;">271</span>  ).await?;
<span style="color:#666; user-select:none;">272</span>  ```
<span style="color:#666; user-select:none;">273</span>  
<span style="color:#666; user-select:none;">274</span>  ---
<span style="color:#666; user-select:none;">275</span>  
<span style="color:#666; user-select:none;">276</span>  ## 5. Session Key Rotation
<span style="color:#666; user-select:none;">277</span>  
<span style="color:#666; user-select:none;">278</span>  For long-lived connections, Abzu performs **periodic key rotation** to limit cryptographic exposure. Rotation uses the existing `Hello`/`HelloAck` wire frames for in-band rekeying.
<span style="color:#666; user-select:none;">279</span>  
<span style="color:#666; user-select:none;">280</span>  ### Rotation Thresholds
<span style="color:#666; user-select:none;">281</span>  
<span style="color:#666; user-select:none;">282</span>  | Trigger | Threshold | Rationale |
<span style="color:#666; user-select:none;">283</span>  |---------|-----------|----------|
<span style="color:#666; user-select:none;">284</span>  | **Bytes transferred** | 1 GB | Limit nonce reuse risk |
<span style="color:#666; user-select:none;">285</span>  | **Time elapsed** | 1 hour | Bound temporal exposure |
<span style="color:#666; user-select:none;">286</span>  | **Messages sent** | 1 million | AEAD safety margin |
<span style="color:#666; user-select:none;">287</span>  
<span style="color:#666; user-select:none;">288</span>  ### Rekey Protocol
<span style="color:#666; user-select:none;">289</span>  
<span style="color:#666; user-select:none;">290</span>  ```
<span style="color:#666; user-select:none;">291</span>      Initiator                                      Responder
<span style="color:#666; user-select:none;">292</span>          │                                               │
<span style="color:#666; user-select:none;">293</span>          │  1. Detect threshold met (needs_rotation)     │
<span style="color:#666; user-select:none;">294</span>          │  2. Generate fresh X25519 keypair             │
<span style="color:#666; user-select:none;">295</span>          │                                               │
<span style="color:#666; user-select:none;">296</span>          │──────── Hello [new_pub] ─────────────────────►│
<span style="color:#666; user-select:none;">297</span>          │                                               │
<span style="color:#666; user-select:none;">298</span>          │                       3. Generate fresh keypair
<span style="color:#666; user-select:none;">299</span>          │                       4. Compute new DH secret
<span style="color:#666; user-select:none;">300</span>          │                       5. Derive new session key
<span style="color:#666; user-select:none;">301</span>          │                       6. Replace cipher atomically
<span style="color:#666; user-select:none;">302</span>          │                       7. Reset nonce counter   │
<span style="color:#666; user-select:none;">303</span>          │                                               │
<span style="color:#666; user-select:none;">304</span>          │◄─────── HelloAck [resp_pub, confirm] ────────│
<span style="color:#666; user-select:none;">305</span>          │                                               │
<span style="color:#666; user-select:none;">306</span>          │  8. Compute new DH secret                     │
<span style="color:#666; user-select:none;">307</span>          │  9. Derive new session key                    │
<span style="color:#666; user-select:none;">308</span>          │ 10. Replace cipher atomically                 │
<span style="color:#666; user-select:none;">309</span>          │ 11. Reset nonce counter                       │
<span style="color:#666; user-select:none;">310</span>          │                                               │
<span style="color:#666; user-select:none;">311</span>          │◄═════ Encrypted with NEW session_key ════════►│
<span style="color:#666; user-select:none;">312</span>  ```
<span style="color:#666; user-select:none;">313</span>  
<span style="color:#666; user-select:none;">314</span>  ### Implementation
<span style="color:#666; user-select:none;">315</span>  
<span style="color:#666; user-select:none;">316</span>  ```rust
<span style="color:#666; user-select:none;">317</span>  // Check if rotation needed
<span style="color:#666; user-select:none;">318</span>  if stream.needs_rotation() {
<span style="color:#666; user-select:none;">319</span>      stream.rotate_key().await?;
<span style="color:#666; user-select:none;">320</span>  }
<span style="color:#666; user-select:none;">321</span>  
<span style="color:#666; user-select:none;">322</span>  // Thresholds checked automatically in send()/recv()
<span style="color:#666; user-select:none;">323</span>  pub fn needs_rotation(&amp;self) -&gt; bool {
<span style="color:#666; user-select:none;">324</span>      let bytes = self.bytes_this_key.load(Ordering::Relaxed);
<span style="color:#666; user-select:none;">325</span>      let msgs = self.messages_this_key.load(Ordering::Relaxed);
<span style="color:#666; user-select:none;">326</span>      let elapsed = self.key_established_at.elapsed().as_secs();
<span style="color:#666; user-select:none;">327</span>      
<span style="color:#666; user-select:none;">328</span>      bytes &gt;= ROTATION_BYTES_THRESHOLD      // 1 GB
<span style="color:#666; user-select:none;">329</span>          || msgs &gt;= ROTATION_MESSAGE_THRESHOLD  // 1M
<span style="color:#666; user-select:none;">330</span>          || elapsed &gt;= ROTATION_TIME_SECS       // 1 hour
<span style="color:#666; user-select:none;">331</span>  }
<span style="color:#666; user-select:none;">332</span>  ```
<span style="color:#666; user-select:none;">333</span>  
<span style="color:#666; user-select:none;">334</span>  ### Atomic Key Replacement
<span style="color:#666; user-select:none;">335</span>  
<span style="color:#666; user-select:none;">336</span>  The cipher is wrapped in `Arc&lt;RwLock&lt;ChaCha20Poly1305&gt;&gt;` allowing:
<span style="color:#666; user-select:none;">337</span>  
<span style="color:#666; user-select:none;">338</span>  - **Concurrent reads** during normal encryption/decryption
<span style="color:#666; user-select:none;">339</span>  - **Exclusive write** during key rotation
<span style="color:#666; user-select:none;">340</span>  - **Zero message loss** — rotation completes between frames
<span style="color:#666; user-select:none;">341</span>  
<span style="color:#666; user-select:none;">342</span>  ### Nonce Reset
<span style="color:#666; user-select:none;">343</span>  
<span style="color:#666; user-select:none;">344</span>  After rotation, the nonce counter resets to `0`. This is safe because:
<span style="color:#666; user-select:none;">345</span>  
<span style="color:#666; user-select:none;">346</span>  1. New key = new keystream
<span style="color:#666; user-select:none;">347</span>  2. Nonce-key pairs never repeat
<span style="color:#666; user-select:none;">348</span>  3. Each rotation creates fresh cryptographic context
<span style="color:#666; user-select:none;">349</span>  
<span style="color:#666; user-select:none;">350</span>  ---
<span style="color:#666; user-select:none;">351</span>  
<span style="color:#666; user-select:none;">352</span>  ## 6. Threat Model
<span style="color:#666; user-select:none;">353</span>  
<span style="color:#666; user-select:none;">354</span>  ### Attacks Mitigated
<span style="color:#666; user-select:none;">355</span>  
<span style="color:#666; user-select:none;">356</span>  | Attack | Mitigation |
<span style="color:#666; user-select:none;">357</span>  |--------|------------|
<span style="color:#666; user-select:none;">358</span>  | **Passive eavesdropping** | ChaCha20-Poly1305 encryption |
<span style="color:#666; user-select:none;">359</span>  | **Key compromise (future)** | Ephemeral X25519 per-connection |
<span style="color:#666; user-select:none;">360</span>  | **Replay attacks** | Timestamp validation, unique nonces |
<span style="color:#666; user-select:none;">361</span>  | **Traffic analysis** | TLS 1.3 camouflage, cover traffic |
<span style="color:#666; user-select:none;">362</span>  | **STUN server logging** | Zero-log policy, self-hosted |
<span style="color:#666; user-select:none;">363</span>  
<span style="color:#666; user-select:none;">364</span>  ### Trust Boundaries
<span style="color:#666; user-select:none;">365</span>  
<span style="color:#666; user-select:none;">366</span>  ```
<span style="color:#666; user-select:none;">367</span>  ┌─────────────────────────────────────────────────────────┐
<span style="color:#666; user-select:none;">368</span>  │                    Trusted Zone                         │
<span style="color:#666; user-select:none;">369</span>  │  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐ │
<span style="color:#666; user-select:none;">370</span>  │  │ Your Node   │────│   Relay     │────│ Peer Node   │ │
<span style="color:#666; user-select:none;">371</span>  │  │ (PSK holder)│    │ (PSK holder)│    │ (PSK holder)│ │
<span style="color:#666; user-select:none;">372</span>  │  └─────────────┘    └─────────────┘    └─────────────┘ │
<span style="color:#666; user-select:none;">373</span>  └─────────────────────────────────────────────────────────┘
<span style="color:#666; user-select:none;">374</span>            ▲                   ▲                   ▲
<span style="color:#666; user-select:none;">375</span>            │     End-to-end encryption with PFS    │
<span style="color:#666; user-select:none;">376</span>            └───────────────────────────────────────┘
<span style="color:#666; user-select:none;">377</span>  ```
<span style="color:#666; user-select:none;">378</span>  
<span style="color:#666; user-select:none;">379</span>  ---
<span style="color:#666; user-select:none;">380</span>  
<span style="color:#666; user-select:none;">381</span>  ## 7. Dependencies
<span style="color:#666; user-select:none;">382</span>  
<span style="color:#666; user-select:none;">383</span>  | Crate | Version | Purpose |
<span style="color:#666; user-select:none;">384</span>  |-------|---------|---------|
<span style="color:#666; user-select:none;">385</span>  | `x25519-dalek` | 2.0 | Elliptic curve Diffie-Hellman |
<span style="color:#666; user-select:none;">386</span>  | `hkdf` | 0.12 | Key derivation function |
<span style="color:#666; user-select:none;">387</span>  | `sha2` | 0.10 | SHA-256 for HKDF |
<span style="color:#666; user-select:none;">388</span>  | `stun-proto` | 1.0 | STUN message parsing |
<span style="color:#666; user-select:none;">389</span>  | `chacha20poly1305` | 0.10 | AEAD encryption |
<span style="color:#666; user-select:none;">390</span>  
<span style="color:#666; user-select:none;">391</span>  ---
<span style="color:#666; user-select:none;">392</span>  
<span style="color:#666; user-select:none;">393</span>  ## 8. Testing
<span style="color:#666; user-select:none;">394</span>  
<span style="color:#666; user-select:none;">395</span>  ```bash
<span style="color:#666; user-select:none;">396</span>  # Run all key exchange tests
<span style="color:#666; user-select:none;">397</span>  cargo test -p abzu-transport key_exchange
<span style="color:#666; user-select:none;">398</span>  
<span style="color:#666; user-select:none;">399</span>  # Full workspace verification
<span style="color:#666; user-select:none;">400</span>  cargo test --workspace
<span style="color:#666; user-select:none;">401</span>  # Result: 106 passed, 0 failed, 2 ignored
<span style="color:#666; user-select:none;">402</span>  ```
<span style="color:#666; user-select:none;">403</span>  
<span style="color:#666; user-select:none;">404</span>  ### Test Coverage
<span style="color:#666; user-select:none;">405</span>  
<span style="color:#666; user-select:none;">406</span>  - `ephemeral_keypair_roundtrip` — Key generation and DH agreement
<span style="color:#666; user-select:none;">407</span>  - `derive_session_key_deterministic` — Same inputs = same output
<span style="color:#666; user-select:none;">408</span>  - `derive_session_key_psk_affects_output` — PSK changes derived key
<span style="color:#666; user-select:none;">409</span>  - `key_share_embed_extract_roundtrip` — TLS extension manipulation
<span style="color:#666; user-select:none;">410</span>  - `extract_key_share_short_message` — Handles malformed input
<span style="color:#666; user-select:none;">411</span>  - `full_pfs_handshake_derives_same_key` — End-to-end simulation
</pre>
        </div>
        </div>

</div>
</main>
</div>
</div>


</body>
</html>

