Technical Details

This page collects the engineering notes that are deeper than the public API reference: the design whitepaper, the CI validation harnesses, and the test fixtures that keep the calculator build honest.

Configuration Wizard

lwIP-CE has a configuration wizard that opens when you run the app. It keeps the resident stack policy in one place:

  • Hostname

  • Static IPv4 settings

  • Timezone, DST settings

  • TLS enabled/disabled

The options present end-users with a modest level of control over how the stack behaves on their device. Particularly with TLS. While this TLS implementation is decently-engineered not everyone will feel comfortable connecting to secure services from an insecure device. With TLS flagged off in the App settings, attempts by programs to use TLS will fail-closed immediately unconditionally, giving end users the final authority.

Allocator System

lwIP-CE uses a custom allocator system that can operate in two modes:

  • Dynamic: Default lwIP-CE ingests malloc, free, and realloc. Only what is needed is absorbed. The stack manages its own pbuf pool, TLS scratch, RX rings, socket rings, and user-reserved regions; heap sizing is no longer a wizard-level policy knob.

  • Static: Requires manual mem_init_static followed by lwip_init instead of lwip_start. You give lwIP-CE a pointer and a size, and it treats that region as its heap.

The allocator also exposes live accounting. mem_get_stats fills a struct mem_accounting_stats with total heap, pbuf pool size/usage, non-pool heap used/free, user-reserved bytes, TLS usage, RX ring usage, socket ring usage, and pbuf/heap/effective pressure levels. Applications can poll this each event-loop tick to render a live memory readout (the examples and test harnesses stream it to the LCD). mem_set_global_pressure_cb registers an observer that fires when the effective pressure level changes, for transport-level backpressure (for example, delaying tcp_recved window updates under load).

Ethernet Driver

The Ethernet driver is an abstraction layer on top of USBDRVCE, the TI-84+ CE USB driver provided as part of the CE toolchain.

The Ethernet driver supports USB-CDC-ECM and USB-CDC-NCM devices; in practice, ECM is common on 10/100 adapters, while NCM is common on gigabit-class adapters. It should also support hubs with a USB port that use one of those protocols, and an Ethernet adapter connected via a hub. Wi-Fi is possible only through an external Ethernet-to-Wi-Fi bridge (typically a USB Ethernet adapter connected to an Ethernet WiFi adapter). The adapter must handle association, WPA/WPA2, SSID selection, and key storage itself, typically through WPS or its own setup flow. lwIP-CE sees that device as Ethernet; it does not implement native Wi-Fi management.

The driver is event-loop driven. Applications must continue pumping the stack for RX, TX, timers, and device recovery to make progress.

TLS Stack

The TLS stack is intentionally narrow: enough to make real secure client sockets, not a general-purpose OS crypto subsystem.

Area

Position

Threat model

Algorithmic security is in scope. Side channels are partially mitigated and partially out of scope. Hardware security is out of scope: no root of trust, secure enclave, crypto accelerator, protected filesystem, or trusted clock.

RNG

SRAM-noise-derived. Entropy taps are statistically analyzed on hardware. Current dataset: correlation factor about 1.1; XOR conditioning depth 17; effective conditioning about 16; P(+) about 0.5; estimated min-entropy about 1.

TLS trust store

A curated trust store derived from CA material staged on a common Linux box, shipped as a signed AppVar and verified with RSA-PSS-SHA256 against an embedded public key at tls_truststore_init. Entries are looked up by subject name to anchor the topmost certificate in a received chain (see Certificate chain below).

Certificate chain

The stack walks the server’s certificate chain link by link. Each link is checked against the next certificate’s public key with RSA PKCS#1 v1.5 / sha256WithRSAEncryption; a bad signature on an RSA-SHA256 link is an ERROR and aborts the handshake. Unsupported signature algorithms on a link, including P-256 ECDSA, raise ALERT("unsupported signature algorithm") and are allowed to pass so the stack remains usable before P-256 verification lands.

Once the adjacent-link walk finishes, the topmost certificate’s issuer is looked up in the trust store by subject name. If found and the stored key is RSA (PSS or PKCS#1-SHA256), the topmost certificate’s signature is verified against it for real – a bad signature here is also an ERROR and aborts. If the root entry isn’t RSA, or isn’t in the trust store at all, that raises ALERT("CA not in root") and the chain is accepted. This is a temporary behavior and will normalize to fail-closed once P-256 (and possibly RSA-4096) is implemented.

CertificateVerify

CertificateVerify is mandatory. For the current RSA path, the signature is verified against the leaf certificate’s public key, proving possession of the leaf private key. This complements the best-effort chain walk above, but it is not a root-of-trust anchor by itself.

For more details, proofs, and datasets, see the whitepaper below.

Application Interfaces

Network services and sockets

Applications request netif-level services and drive sockets through a small C API rather than touching raw lwIP PCBs directly. lwip_request_services (and the per-netif lwip_netif_request_services) start DHCP, the DNS resolver, and SNTP on demand using LWIP_SOCKET_SVC_* flags; the per-netif form takes a status callback that fires once per requested service with a lwip_netif_service_status_t (up / timeout / failed), so an application can react to “DHCP is up” without polling. lwip_default_netif_info fills a lwip_netif_info_t snapshot (link/admin state, DHCP state, assigned IPv4 address, gateway) for status displays.

Unified debug logging

Diagnostics across the whole stack go through a single callback registered with lwip_set_debug(fn, mode, depth), replacing the former per-module debug hooks. Each event arrives as a struct lwip_debug_info carrying the emitting module, the module_state (where in the code it fired), an errnum (0 = ok), the source line, a verbosity depth (MILESTONE vs VERBOSE), and a severity:

  • INFO — normal progress / informational milestone.

  • ALERT — the stack noticed something wrong but chose to proceed (for example, an unsupported-but-tolerated certificate link).

  • ERROR — an operation is failing or aborting (always delivered, regardless of the configured depth).

The callback’s mode selects whether every emit is delivered (LWIP_DBG_INFO) or only error emits (LWIP_DBG_ERROR), and depth gates verbosity. This gives an application one place to surface a clean high-level progress view or a deep trace, with the ALERT level making “proceeded despite a problem” distinguishable from a hard error.

CI And Test Harnesses

The test harnesses are not decoration. They are there because the platform is weird, the toolchain matters, and it is easy to pass a host-side test that says nothing about the calculator binary.

Harness

What it proves

CAVP primitive validation

Packs CAVP-derived vectors into CAVPIN.8xv, runs the calculator-side primitive dispatcher in CEmu, saves CAVPOUT.8xv, and grades the output on the host. This is regression evidence, not a formal NIST certificate.

Timing profiler

Runs calculator-side timing captures so crypto and stack hot paths can be measured in the environment that actually ships.

RNG entropy capture

Emits AppVars for raw and conditioned entropy paths, then analyzes the bit streams off-device. Entropy tests are not useful in the emulated CI pipeline because SRAM emulation is deterministic, so those captures are run on hardware and analyzed in the whitepaper instead.

DAST hardware-in-the-loop

Runs the calculator-side tests/profiling/lwip_dast harness on real hardware because CEmu does not emulate Ethernet devices. The host-side build-tools/dast/lwip-dast.sh runner probes the calculator over the live network, advances the harness through UDP, TCP, raw/IP, and control states, writes tests/dast.json, and CI gates the committed report.

Doxygen/Sphinx docs build

Builds the generated API reference and the project docs with the same release headers users will see.

The CAVP harness uses AppVars because that is the natural calculator transport boundary: host tools generate inputs, CEmu runs the app, and host tools parse the saved output. That keeps the validation path close to how a real program interacts with calculator storage instead of pretending this is a POSIX target.

Whitepaper

The whitepaper is published as the latest generated PDF from the GitHub release workflow. The docs build downloads that release asset and embeds it here so the page renders the same PDF users would get from GitHub.

Latest release PDF

This covers the TLS work, RNG design, cryptographic constraints, and platform tradeoffs behind lwIP-CE.

Open the release PDF

Your browser did not render the embedded PDF. Open the release PDF .