Files
zeekay f21120ce2f zwing v0.1.0: Z-Wing PQ secure channel for Lux
Z-Wing is the canonical Lux post-quantum secure channel. One construction,
one wire format, no negotiation. Layered design exposes a net.Conn so
luxfi/api/zap (and any other stream protocol) runs unchanged on top.

  KEM:       X-Wing  (X25519 + ML-KEM-768, IETF draft-connolly-cfrg-xwing-kem
                     SHA3-256 combiner: "\./" || "X-Wing" || ssM || ssX || ctX || pkX)
  Identity:  Ed25519 + ML-DSA-65 hybrid signatures
  AEAD:      ChaCha20-Poly1305 with sequence-numbered nonces (per direction)
  Transport: TCP (RNS routing is a follow-up package)

Public API: GenerateIdentity / Dial / Listen / Client / Server.

Six tests cover the spec end-to-end: handshake round-trip, TCP dial+listen,
ExpectedRemote pinning, key-zero-after-handshake forward secrecy, sequenced
nonces, and ZAP-over-Z-Wing application round-trip.
2026-05-06 12:18:21 -07:00

62 lines
1.6 KiB
Go

// Copyright (C) 2020-2026, Lux Industries Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package zwing
import (
"context"
"net"
"time"
)
// Dial connects to a Z-Wing listener at addr and runs the handshake.
// The returned net.Conn is the post-handshake encrypted channel.
func Dial(ctx context.Context, addr string, cfg *Config) (net.Conn, error) {
if cfg == nil || cfg.LocalIdentity == nil {
return nil, ErrConfigMissingID
}
d := net.Dialer{}
raw, err := d.DialContext(ctx, "tcp", addr)
if err != nil {
return nil, err
}
return clientHandshake(raw, cfg)
}
// Client wraps an existing net.Conn (e.g. a TLS conn, a Unix socket, a
// pipe) and runs the Z-Wing handshake on top as the initiator.
func Client(raw net.Conn, cfg *Config) (net.Conn, error) {
return clientHandshake(raw, cfg)
}
// Server wraps an existing net.Conn and runs the handshake as the responder.
func Server(raw net.Conn, cfg *Config) (net.Conn, error) {
return serverHandshake(raw, cfg)
}
func clientHandshake(raw net.Conn, cfg *Config) (net.Conn, error) {
if cfg.HandshakeTimeout > 0 {
_ = raw.SetDeadline(time.Now().Add(cfg.HandshakeTimeout))
defer raw.SetDeadline(time.Time{})
}
res, err := runInitiator(raw, cfg)
if err != nil {
raw.Close()
return nil, err
}
return newConn(raw, res, true)
}
func serverHandshake(raw net.Conn, cfg *Config) (net.Conn, error) {
if cfg.HandshakeTimeout > 0 {
_ = raw.SetDeadline(time.Now().Add(cfg.HandshakeTimeout))
defer raw.SetDeadline(time.Time{})
}
res, err := runResponder(raw, cfg)
if err != nil {
raw.Close()
return nil, err
}
return newConn(raw, res, false)
}