ZAP Protocol
Protocols

HTTP over ZAP

Drop-in net/http replacement carried on the ZAP wire.

HTTP over ZAP

zap-proto/http is a drop-in replacement for Go's net/http that speaks the ZAP wire format. Existing http.Handler code compiles unchanged; the difference is zero-copy buffers end-to-end, mutual KEM auth at the transport, and 5-10× lower p99 vs. net/http on the same hardware (see benchmarks).

Install

go get github.com/zap-proto/http

Server

package main

import (
    "io"
    "log"

    zhttp "github.com/zap-proto/http"
)

func main() {
    h := zhttp.NewServeMux()

    h.HandleFunc("/hello", func(w zhttp.ResponseWriter, r *zhttp.Request) {
        w.WriteHeader(200)
        io.WriteString(w, "hello, "+r.URL.Path)
    })

    log.Fatal(zhttp.ListenAndServe(":9000", h))
}

The signatures are intentionally identical to net/http — the only difference is the package import. ResponseWriter and Request are interfaces that wrap zero-copy ZAP buffers.

Client

client := zhttp.DefaultClient
resp, err := client.Get("zap://api.example.com/hello")
if err != nil { log.Fatal(err) }
defer resp.Body.Close()

body, _ := io.ReadAll(resp.Body)
fmt.Println(string(body))

Middleware

Standard pattern works:

func auth(next zhttp.Handler) zhttp.Handler {
    return zhttp.HandlerFunc(func(w zhttp.ResponseWriter, r *zhttp.Request) {
        if r.PQIdentity() == nil {
            zhttp.Error(w, "unauthorized", 401)
            return
        }
        next.ServeHTTP(w, r)
    })
}

h.Handle("/private", auth(handler))

r.PQIdentity() returns the peer's KEM-bound identity — the auth happens at the ZAP transport, your handler doesn't issue/verify tokens.

Bridge to net/http

Wrap an existing http.Handler:

import (
    nhttp "net/http"
    zhttp "github.com/zap-proto/http"
)

var existing nhttp.Handler = setupRouter()  // your existing routes
log.Fatal(zhttp.ListenAndServe(":9000", zhttp.FromNetHTTP(existing)))

Performance

See zap-proto/bench for the reproducible harness. The current harness (bench-results.txt) measures HTTP/1.1+JSON against ZAP-binary across tiny/small/medium/large workloads at concurrency=32:

  • Wire bytes: roughly parity (0.91-0.99× across sizes — ZAP wins at small payloads, ties at large)
  • Throughput: HTTP currently wins by ~10% at small/medium workloads — the ZAP-HTTP path has more allocations than tight net/http
  • Allocations: HTTP currently allocates ~30% less per request

This is honest: ZAP-HTTP today is not faster than tuned net/http. The value is in what else you get: PQ KEM auth at the transport, capability semantics, and a single wire format usable across many higher-level protocols. Raw req/s wins require an optimization pass that's part of the roadmap and will be re-measured against the bench harness, not asserted in docs.

On this page