Files
BackOne/SPEC.md
T
dedysutanto 86c744897b feat(pqc): identity/COM v2, pqcMode config, selftest gates
Phases 3-6 (SPEC T19-T23): type-1 identity carries ML-KEM-768 + ML-DSA-65 pubs, COM type-2 double-sign, HELLO capability bit, local.conf settings.pqcMode (off/hybrid/pqconly) with classic fallback. selftest KAT + interop matrix + fragment-loss benchmark green.
2026-10-01 15:55:09 +07:00

9.2 KiB
Raw Blame History

SPEC — BackOne

§G (goal)

Make BackOne quantum ready: phases 1-6 of backone-quantum-fork-research.md — liboqs + hybrid X25519+ML-KEM-768 / Ed25519+ML-DSA-65 handshake, identity/COM v2 double-sign, capability-bit negotiation. Phase 7 (AES-256-GCM) OUT.

§C (constraints)

  • C++17. GNU make = real build. Top CMakeLists.txt = stub, never product build.
  • Deps vendored in ext/. No new dep for few-liners.
  • Tabs always, .clang-format LLVM/Stroustrup, indent 4. No reformat of untouched lines.
  • New .cpp/.hpp/.h gets 11-line BSL header verbatim (node/Mutex.hpp:1-12).
  • node/ stays OS-independent. Sockets/files → osdep/. Orchestration → service/. Persistence → controller/.
  • No exceptions across C API. Fatal ZT_ResultCode = 100–999.
  • One reactor thread (Phy::poll). Cross-thread wake only Phy::whack().
  • New compiled file → register in objects.mk or no link.
  • Platforms: Linux (primary), macOS, BSD/NetBSD, Windows (msbuild).
  • Header edits: no -MMD dep tracking → make clean after touching .h.
  • PQC lock: liboqs static vendored ext/; hybrid key = KDF(classical ‖ pq); presets hybrid (ML-KEM-768/ML-DSA-65) + pqconly (ML-KEM-1024/ML-DSA-87)
  • wire/identity/COM use versioned v2 + capability-bit fallback to classic
  • include/ZeroTierOne.h changes additive-only (Java/libzt ripple)
  • OUT: AES-256-GCM swap, trusted-path skipCrypto, forward secrecy, protocol standardization, crypto audit, production release/signing
  • ? address v2 derivation keeping 40-bit + PoW
  • ? VL1 fragmentation capacity for +4KB identity (check node/Packet.*)
  • ? liboqs version/tag + build flags for ext/
  • ? measured ML-KEM/ML-DSA latency (doc estimates unverified)
  • ? capability-bit placement in existing handshake

§I (public surfaces)

id surface detail
I.capi C API include/ZeroTierOne.h, ZT_Node_* (lines 1796-2258), ZT_SDK_API. Ripples to Java/libzt/SDK
I.api HTTP JSON API 127.0.0.1:9993, /status /peer /network /member /controller /metrics /info, auth X-ZT1-Auth header or ?auth= from authtoken.secret
I.cli CLI backone-cli info|listpeers|listnetworks|join|leave (-j -p -D), backone-idtool generate|validate|getpublic|sign|verify|mkcom — symlink dispatch on argv[0]
I.cfg config home /var/lib/backone (macOS /Library/Application Support/BackOne), local.conf, identity.secret, networks.d/, controller.db, backone.port, backone.pid
I.build build make, make one, make selftest, make core, make debug, make install, make debian/redhat, make central-controller; env ZT_* knobs
I.ffi Rust FFI rustybits/zeroidc (zeroidc_new…), smeeclient — C header zeroidc.h, link on ZT_SSO_SUPPORTED=1/ZT_CONTROLLER=1
I.jni Java SDK java/jni/…Node.cpp, ant targets build_java/build_android/build_jar
I.pqc.cfg config local.conf settings.pqcMode (off/hybrid/pqconly), kem, sig
I.pqc.wire wire static-static hybrid, no ephemeral exchange: identity v2 (type byte 1) carries ML-KEM-768 pub + ML-DSA-65 pub; agree = KDF(X25519-identity-agree ‖ ML-KEM-encaps(peer static pub)) (node/Peer.cpp:63); capability via HELLO protocol-version bytes (node/Packet.hpp:329-333); identity.secret/identity.public v2 on disk
I.pqc.com credentials COM double-sign/verify — controller + node/CertificateOfMembership.*
I.rules rules compiler node rule-compiler/cli.js <rules> → rules/tags JSON

§V (invariants)

Derived from selftest.cpp + CI gates. ? = code-derived, no test yet.

id invariant evidence
V1 Crypto KATs pass: Salsa20 vectors, C25519 agreement, Ed25519 sign/verify, SHA512, Poly1305 selftest.cpp:137 testCrypto
V2 Identity known-good accepted, known-bad rejected selftest.cpp:475 testIdentity
V3 CertificateOfMembership signs and agreesWith roundtrip selftest.cpp:577 testCertificate
V4 Packet encode/decode roundtrip exact selftest.cpp:641 testPacket
V5 Phy UDP+TCP loopback on 127.0.0.1 works, no root selftest.cpp:1002 testPhy
V6 Zero definite leaks under valgrind; test exit code 0 .github/workflows/validate-report.sh
V7 ? No exception crosses C API; ZT_ResultCode_isFatal only 100–999 include/ZeroTierOne.h:426
V8 ? node/ contains no OS calls (sockets/files/interfaces) node/README.md rule
V9 hybrid↔vanilla negotiates classic, link stays up interop matrix
V10 identity v2 survives 1280B MTU tunnel intact; v2 = type byte 1 (wire Identity.hpp:219, string slot Identity.cpp:173); address derivation hashes X25519 material only → v1/v2 addresses bit-identical; v1 parser rejects type ≠ 0 cleanly interop matrix
V11 ML-KEM/ML-DSA KATs + hybrid KDF vector + identity v2 roundtrip + COM double-sign verify pass extended selftest.cpp
V12 pqcMode negotiation honors local.conf (off → no v2 fields) selftest
V13 hybrid agree = KDF(X25519-identity-agree ‖ ML-KEM static-static), no ephemeral exchange; hybrid↔hybrid agree + hybrid↔vanilla classic fallback pass node/Peer.cpp:63, node/IncomingPacket.cpp:400
V14 COM double-sign = type byte 1→2 appends ML-DSA sig alongside Ed25519; v1 verify path unchanged; v1 rejects type 2 cleanly node/CertificateOfMembership.hpp:222-296, node/CertificateOfMembership.cpp:97-162, selftest.cpp:714
V15 handshake vs fragment loss measured: PQC identity in clear HELLO = 3273B → 3 frags (classic 137B → 1 frag, max 7 Packet.hpp:235); Monte Carlo 20k trials obs≈analytic at p∈{.01,.05,.10,.30}; fragment loss delays HELLO (retransmit), does not break handshake selftest.cpp:1735 benchmark

§T (tasks)

id status task cites
T1 x Fix CI build smoke: build.yml runs ./zerotier-selftest, build emits backone-selftest (also tar zerotier-one → backone) I.build,V6
T2 x Fix validate-linux.sh binary names: invokes ./zerotier-one, ./zerotier-cli (lines 41-43,105,111,451), builds backone* I.cli,V6
T3 x Wire ZT_COVERAGE into makefiles — consumed by none, gcovr likely reports zeros ? I.build
T4 x make install manpage rule: expects doc/backone.8, doc/backone-cli.1, doc/backone-idtool.1; doc/ only has zerotier-*, no rename rule I.build
T5 x make redhat: backone.spec %install copies missing debian/backone.service + ext/installfiles/linux/backone.init.rhel6 (actual files zerotier-*) I.build
T6 x Rebrand make-bsd.mk/make-netbsd.mk: still emit/install zerotier-one, /var/db/zerotier-one vs code writing backone.pid I.build
T7 x Dockerfile.ci: copies zerotier-one from build → fails; binary is backone I.build
T8 . pkg/snap/snapcraft.yaml: builds upstream github.com/zerotier/zerotierone.git, expects usr/sbin/zerotier-one I.build
T9 . Wire orphaned java/test/StringUtilsTest.java (JUnit4) into java/build.xml target or delete I.jni
T10 . Replace rule-compiler/package.json npm test failing placeholder with real test of rule-compiler.js I.rules
T11 . ? Add #[test] coverage for rustybits/zeroidc FFI parse/exchange paths I.ffi,V7
T12 x Implement Redis config TODO (service/OneService.cpp:1467 // TODO: Redis config) I.cfg
T13 . Implement LFDB::eraseNetwork/eraseMember TODOs (controller/LFDB.cpp:383,388) I.cfg
T14 . Lint gate done: make lint (tools/lint.sh, changed-lines clang-format) + .github/workflows/lint.yml I.build
T15 . Fix -Wsign-compare suppression FIXME (node/Bond.cpp:23, node/Node.cpp:40) I.build
T16 x Federation identity-collision payload FIXME (node/IncomingPacket.cpp:211) ? scope I.capi,V7
T17 x Phase 1: vendor liboqs static into ext/, wire make-linux.mk + objects.mk, pin version/tag + flags I.build
T18 x Phase 2: node/PQHybrid.* hybrid agree = KDF(X25519-identity-agree ‖ ML-KEM-768 encaps over peer static pub); phase-2 ephemeral-field mockup dropped I.pqc.wire,V13
T19 x Phase 3: identity v2 type byte 1, append ML-KEM+ML-DSA pubs, address hash X25519-only, v1 clean reject type ≠ 0 I.pqc.wire,V10
T20 x Phase 4: COM type byte 2 double-sign (Ed25519+ML-DSA-65), v1 rejects cleanly I.pqc.com,V14
T21 x Phase 5: local.conf settings.pqcMode parse (off/hybrid/pqconly) + capability negotiation via HELLO protocol-version bytes, fallback classic I.pqc.cfg,V12,V9
T22 x Phase 6: selftest extension — ML-KEM/ML-DSA KATs, hybrid KDF vector, identity v2 roundtrip + address stability, COM double-sign, interop hybrid↔vanilla matrix I.build,V11,V10,V14
T23 x Phase 6: handshake-vs-fragment-loss benchmark for PQC HELLO; cap/segment if loss breaks handshake V15

T1/T2 = prerequisites — CI must invoke backone-selftest before PQC gates mean anything. T1–T16 backlog (rebrand/CI/lint leftovers); T17–T23 = PQC phases 1–6.

Not tracked (low value ?): one.cpp:256 port/token cleanup, MacKextEthernetTap.cpp:480 iface status, VLAN TODOs in NetBSDEthernetTap.cpp:468/MacKextEthernetTap.cpp:685, Phy.hpp:325 unix sock type comment.

§B (bug log)

id date cause fix