Files
zeekay e8ec8eed73 py: real zero-copy wire + RPC + PQ crypto; fix broken package
Make the published zap-proto package contain real code instead of stubs.

Wire (the product, was entirely absent):
- src/zap/wire.py — pure-stdlib port of the canonical Go runtime (zap.go +
  builder.py + accessors + list cursors). Message/Object/List zero-copy reads,
  Builder/ObjectBuilder/ListBuilder writes, 16-byte ZAP\x00 header, Version1+2
  accept, reader hardening (reject backward pointers into the header, clamp list
  length). Byte-faithful to Go — pinned by the shared cross-wire golden vector.

RPC (was a sleep-loop server + all-mock client):
- src/zap/rpc.py — real TCP request/response transport, Server dispatches the
  Zap interface method ordinals (@0..@8 from zap.zap), Client calls them.
- app.run() now serves real RPC; client.Client is a real RPC client.

Crypto (was secrets.token_bytes() fakes whose two sides never agreed and whose
verify() accepted any blob):
- src/zap/crypto.py — real ML-KEM-768 / ML-DSA-65 (pqcrypto) + X25519
  (cryptography), hybrid HKDF-SHA256 KEX. Hard-fails with CryptoError when a
  backend is missing — never fabricates bytes.

Package wiring:
- __init__.py exposes the wire API with ZERO third-party dep on the import path;
  pydantic/httpx are lazy (app.ZAP, Client). All __all__ names resolve on a
  default install (was 18 of 22 unresolved, swallowed ImportError).
- pyproject: drop nonexistent pyzap>=2.0.0; pydantic -> [app]; add [crypto];
  fix repo URL to zap-proto/py; target py312.

Bug fixes (audit PoCs):
- frame.py: reject oversize routing ids cleanly (was u16 struct crash); lenient
  decode of non-UTF8 ids (was strict-decode crash); encode/decode_cmd type tag
  so str round-trips to str (was silently bytes).
- protocol.py: decode_stream reports bytes consumed (decode dropped 2nd frame).
- app.py: _match_uri_template escapes literal template text (was regex over-match).
- consensus.py: fix votes int/dict type collision.

Quality: ruff clean, ruff format clean, mypy --strict 0 issues, 52 tests pass.
Add .github/workflows/ci.yml (ruff + format + mypy + pytest, py3.10-3.13).
Rebrand: zap.capnp -> zap.zap, $Go.import -> github.com/zap-proto/go.
2026-06-20 00:00:29 -07:00

837 lines
21 KiB
Plaintext

@0xb2a3f4c5d6e7f8a9;
# ZAP - Zero-Copy App Proto
# ZAP schema for high-performance agent communication
using Go = import "/go.zap";
$Go.package("zap");
$Go.import("github.com/zap-proto/go");
# Core types
struct Timestamp {
seconds @0 :Int64;
nanos @1 :UInt32;
}
struct Metadata {
entries @0 :List(Entry);
struct Entry {
key @0 :Text;
value @1 :Text;
}
}
# Tool definitions
struct Tool {
name @0 :Text;
description @1 :Text;
schema @2 :Data; # JSON Schema as bytes
annotations @3 :Metadata;
}
struct ToolList {
tools @0 :List(Tool);
}
struct ToolCall {
id @0 :Text;
name @1 :Text;
args @2 :Data; # JSON arguments as bytes
metadata @3 :Metadata;
}
struct ToolResult {
id @0 :Text;
content @1 :Data; # Result content as bytes
error @2 :Text;
metadata @3 :Metadata;
}
# Resource definitions
struct Resource {
uri @0 :Text;
name @1 :Text;
description @2 :Text;
mimeType @3 :Text;
annotations @4 :Metadata;
}
struct ResourceList {
resources @0 :List(Resource);
}
struct ResourceContent {
uri @0 :Text;
mimeType @1 :Text;
content :union {
text @2 :Text;
blob @3 :Data;
}
}
# Prompt definitions
struct Prompt {
name @0 :Text;
description @1 :Text;
arguments @2 :List(Argument);
struct Argument {
name @0 :Text;
description @1 :Text;
required @2 :Bool;
}
}
struct PromptList {
prompts @0 :List(Prompt);
}
struct PromptMessage {
role @0 :Role;
content @1 :Content;
enum Role {
user @0;
assistant @1;
system @2;
}
struct Content {
union {
text @0 :Text;
image @1 :ImageContent;
resource @2 :ResourceContent;
}
}
struct ImageContent {
data @0 :Data;
mimeType @1 :Text;
}
}
# Server info
struct ServerInfo {
name @0 :Text;
version @1 :Text;
capabilities @2 :Capabilities;
struct Capabilities {
tools @0 :Bool;
resources @1 :Bool;
prompts @2 :Bool;
logging @3 :Bool;
}
}
# Main ZAP interface
interface Zap {
# Initialize connection
init @0 (client :ClientInfo) -> (server :ServerInfo);
# Tool operations
listTools @1 () -> (tools :ToolList);
callTool @2 (call :ToolCall) -> (result :ToolResult);
# Resource operations
listResources @3 () -> (resources :ResourceList);
readResource @4 (uri :Text) -> (content :ResourceContent);
subscribe @5 (uri :Text) -> (stream :ResourceStream);
# Prompt operations
listPrompts @6 () -> (prompts :PromptList);
getPrompt @7 (name :Text, args :Metadata) -> (messages :List(PromptMessage));
# Logging
log @8 (level :LogLevel, message :Text, data :Data);
enum LogLevel {
debug @0;
info @1;
warn @2;
error @3;
}
}
struct ClientInfo {
name @0 :Text;
version @1 :Text;
}
interface ResourceStream {
next @0 () -> (content :ResourceContent, done :Bool);
cancel @1 () -> ();
}
# Gateway interface for MCP bridging
interface Gateway extends(Zap) {
# Add MCP server
addServer @0 (name :Text, url :Text, config :ServerConfig) -> (id :Text);
# Remove MCP server
removeServer @1 (id :Text) -> ();
# List connected servers
listServers @2 () -> (servers :List(ConnectedServer));
# Get server status
serverStatus @3 (id :Text) -> (status :ServerStatus);
struct ServerConfig {
transport @0 :Transport;
auth @1 :Auth;
timeout @2 :UInt32; # milliseconds
enum Transport {
stdio @0;
http @1;
websocket @2;
zap @3;
unix @4;
}
struct Auth {
union {
none @0 :Void;
bearer @1 :Text;
basic @2 :BasicAuth;
}
struct BasicAuth {
username @0 :Text;
password @1 :Text;
}
}
}
struct ConnectedServer {
id @0 :Text;
name @1 :Text;
url @2 :Text;
status @3 :ServerStatus;
tools @4 :UInt32;
resources @5 :UInt32;
}
enum ServerStatus {
connecting @0;
connected @1;
disconnected @2;
error @3;
}
}
# Coordination interface for distributed agents
interface Coordinator {
# Register agent
register @0 (agent :AgentInfo) -> (id :Text, gateway :Gateway);
# Heartbeat
heartbeat @1 (id :Text) -> (ok :Bool);
# Discover agents
discover @2 (filter :AgentFilter) -> (agents :List(AgentInfo));
struct AgentInfo {
id @0 :Text;
name @1 :Text;
capabilities @2 :List(Text);
metadata @3 :Metadata;
}
struct AgentFilter {
capabilities @0 :List(Text);
metadata @1 :Metadata;
}
}
# Post-Quantum Cryptography Types
# Implements NIST FIPS 203 (ML-KEM) and FIPS 204 (ML-DSA)
struct MLKEMPublicKey {
# ML-KEM-768 public key (1184 bytes)
data @0 :Data;
}
struct MLKEMCiphertext {
# ML-KEM-768 ciphertext (1088 bytes)
data @0 :Data;
}
struct MLDSAPublicKey {
# ML-DSA-65 public key (1952 bytes)
data @0 :Data;
}
struct MLDSASignature {
# ML-DSA-65 detached signature (3293 bytes)
data @0 :Data;
}
struct X25519PublicKey {
# X25519 public key (32 bytes)
data @0 :Data;
}
# Hybrid X25519 + ML-KEM handshake for post-quantum key exchange
struct PQHandshake {
# Initiator's X25519 ephemeral public key
x25519PublicKey @0 :Data;
# Initiator's ML-KEM-768 public key
mlkemPublicKey @1 :MLKEMPublicKey;
# Responder's ML-KEM ciphertext (encapsulated shared secret)
mlkemCiphertext @2 :MLKEMCiphertext;
# Optional: signature over handshake transcript for authentication
signature @3 :MLDSASignature;
}
# Handshake message for initiating a PQ-secure connection
struct PQHandshakeInit {
# Client's X25519 ephemeral public key (32 bytes)
x25519PublicKey @0 :Data;
# Client's ML-KEM-768 public key for key encapsulation
mlkemPublicKey @1 :MLKEMPublicKey;
# Optional: Client's ML-DSA identity public key for authentication
identityKey @2 :MLDSAPublicKey;
# Optional: signature over (x25519PublicKey || mlkemPublicKey)
identitySignature @3 :MLDSASignature;
# Random nonce to prevent replay attacks
nonce @4 :Data;
# Protocol version
version @5 :UInt16;
}
# Handshake response from server
struct PQHandshakeResponse {
# Server's X25519 ephemeral public key (32 bytes)
x25519PublicKey @0 :Data;
# ML-KEM ciphertext containing encapsulated shared secret
mlkemCiphertext @1 :MLKEMCiphertext;
# Optional: Server's ML-DSA identity public key
identityKey @2 :MLDSAPublicKey;
# Optional: signature over (clientNonce || x25519PublicKey || mlkemCiphertext)
identitySignature @3 :MLDSASignature;
# Echo client nonce to bind response to request
clientNonce @4 :Data;
# Server nonce for session binding
serverNonce @5 :Data;
}
# Authenticated channel after PQ handshake
struct PQChannelMessage {
# Sequence number for replay protection
sequence @0 :UInt64;
# AEAD-encrypted payload (using derived session key)
ciphertext @1 :Data;
# AEAD authentication tag
tag @2 :Data;
# Associated data (plaintext, authenticated but not encrypted)
associatedData @3 :Data;
}
# Key rotation message for long-lived sessions
struct PQKeyRotation {
# New ML-KEM public key for next epoch
newMlkemPublicKey @0 :MLKEMPublicKey;
# ML-KEM ciphertext for the new key
mlkemCiphertext @1 :MLKEMCiphertext;
# Signature over (epoch || newMlkemPublicKey) with identity key
signature @2 :MLDSASignature;
# Epoch number (monotonically increasing)
epoch @3 :UInt64;
}
# =============================================================================
# Ringtail Consensus Types
# Threshold lattice-based signing protocol for post-quantum security
# =============================================================================
# Ring polynomial coefficients mod Q
struct Poly {
# Coefficients in Z_Q[X]/(X^phi + 1), phi=256
coeffs @0 :List(UInt64);
}
struct PolyVector {
polys @0 :List(Poly);
}
struct PolyMatrix {
rows @0 :List(PolyVector);
}
# Ringtail protocol parameters
struct RingtailParams {
m @0 :UInt16 = 8; # Matrix rows
n @1 :UInt16 = 7; # Matrix columns
dbar @2 :UInt16 = 48; # Commitment dimension
kappa @3 :UInt16 = 23; # Challenge weight (Hamming weight)
phi @4 :UInt16 = 256; # Ring dimension (2^8)
keySize @5 :UInt16 = 32; # Key size in bytes (256 bits)
q @6 :UInt64 = 0x1000000004A01; # 48-bit NTT-friendly prime modulus
xi @7 :UInt32 = 30; # Rounding parameter
nu @8 :UInt32 = 29; # Rounding parameter
}
# Party information for threshold signing
struct RingtailPartyInfo {
partyId @0 :UInt32; # This party's ID (0-indexed)
totalParties @1 :UInt32; # Total number of parties (K)
threshold @2 :UInt32; # Signing threshold (t-of-K)
address @3 :Text; # Network address
publicKey @4 :Data; # Party's public key share
}
# MAC for authenticating round 1 commitments
struct RingtailMac {
senderId @0 :UInt32;
recipientId @1 :UInt32;
value @2 :Data; # 32-byte BLAKE3 MAC
}
# Round 1 output: commitment D_i and MACs
struct RingtailRound1Output {
partyId @0 :UInt32;
sessionId @1 :UInt64;
dMatrix @2 :PolyMatrix; # M x (Dbar+1) commitment matrix D_i
macs @3 :List(RingtailMac); # MACs for other participating parties
timestamp @4 :Timestamp;
}
# Round 2 output: response share z_i
struct RingtailRound2Output {
partyId @0 :UInt32;
sessionId @1 :UInt64;
zShare @2 :PolyVector; # N-dimensional response vector z_i
timestamp @3 :Timestamp;
}
# Final Ringtail threshold signature (c, z, Delta)
struct RingtailSignature {
c @0 :Poly; # Challenge polynomial (sparse, Hamming weight kappa)
z @1 :PolyVector; # Aggregated response vector (N-dimensional)
delta @2 :PolyVector; # Correction term (M-dimensional)
signers @3 :List(UInt32); # IDs of parties that contributed
sessionId @4 :UInt64; # Signing session identifier
}
# Request to initiate threshold signing
struct RingtailSignRequest {
message @0 :Data; # Message to sign
sessionId @1 :UInt64; # Unique session identifier
participants @2 :List(UInt32); # Party IDs participating in this signing
timeoutMs @3 :UInt32; # Timeout in milliseconds
}
# Response from signing operation
struct RingtailSignResponse {
union {
signature @0 :RingtailSignature; # Completed signature
error @1 :Text; # Error message
progress @2 :RingtailSignProgress; # Still in progress
}
}
# Progress update during threshold signing
struct RingtailSignProgress {
sessionId @0 :UInt64;
currentRound @1 :UInt8; # 1 or 2
completedParties @2 :List(UInt32);
pendingParties @3 :List(UInt32);
estimatedTimeMs @4 :UInt32;
}
# Request to verify a Ringtail signature
struct RingtailVerifyRequest {
message @0 :Data;
signature @1 :RingtailSignature;
publicKey @2 :PolyVector; # Public key b_tilde
publicMatrix @3 :PolyMatrix; # Public matrix A
}
# Response from verification
struct RingtailVerifyResponse {
valid @0 :Bool;
error @1 :Text;
}
# Peer-to-peer message for distributed signing
struct RingtailPeerMessage {
from @0 :UInt32; # Sender party ID
to @1 :UInt32; # Recipient (0 = broadcast)
sessionId @2 :UInt64;
timestamp @3 :Timestamp;
union {
round1 @4 :RingtailRound1Output;
round2 @5 :RingtailRound2Output;
signRequest @6 :RingtailSignRequest;
signResponse @7 :RingtailSignResponse;
heartbeat @8 :RingtailHeartbeat;
abort @9 :RingtailAbort;
}
}
# Heartbeat for liveness checking
struct RingtailHeartbeat {
partyId @0 :UInt32;
status @1 :RingtailPartyStatus;
currentSession @2 :UInt64;
load @3 :Float32; # Current load (0.0-1.0)
}
enum RingtailPartyStatus {
idle @0;
signingRound1 @1;
signingRound2 @2;
combining @3;
busy @4;
offline @5;
}
# Abort message to cancel a signing session
struct RingtailAbort {
sessionId @0 :UInt64;
reason @1 :Text;
partyId @2 :UInt32;
}
# =============================================================================
# Agent Consensus Types
# Simplified voting-based consensus for AI agent response aggregation
# =============================================================================
# Query identifier (32-byte hash)
struct AgentQueryId {
hash @0 :Data; # BLAKE3 hash of query content
}
# State of a consensus query
struct AgentQueryState {
queryId @0 :AgentQueryId;
query @1 :Text; # Original query content
responses @2 :List(AgentResponseEntry);
votes @3 :List(AgentResponseVote);
finalized @4 :Bool;
result @5 :Text; # Final consensus result (if finalized)
createdAt @6 :Timestamp;
}
# Response from an agent
struct AgentResponseEntry {
agentId @0 :Text;
response @1 :Text;
timestamp @2 :Timestamp;
signature @3 :Data; # Optional signature over response
confidence @4 :Float32; # Agent's confidence (0.0-1.0)
}
# Vote tally for a response
struct AgentResponseVote {
responseHash @0 :Data; # BLAKE3 hash of response content
voteCount @1 :UInt32;
voters @2 :List(Text); # Agent IDs that voted for this response
}
# Configuration for agent consensus
struct AgentConsensusConfig {
threshold @0 :Float64; # Required vote fraction (0.0-1.0)
minResponses @1 :UInt32; # Minimum responses before consensus check
timeoutSecs @2 :UInt32; # Query timeout in seconds
requireSignatures @3 :Bool; # Whether agent signatures are required
}
# Request to submit a new query
struct AgentSubmitQueryRequest {
query @0 :Text;
config @1 :AgentConsensusConfig;
}
# Response from submitting a query
struct AgentSubmitQueryResponse {
queryId @0 :AgentQueryId;
}
# Request to submit an agent's response
struct AgentSubmitResponseRequest {
queryId @0 :AgentQueryId;
agentId @1 :Text;
response @2 :Text;
signature @3 :Data; # Optional signature
confidence @4 :Float32;
}
# Result of submitting a response
struct AgentSubmitResponseResult {
union {
success @0 :Void;
error @1 :Text;
duplicate @2 :Void; # Agent already submitted
}
}
# Request to check for consensus
struct AgentTryConsensusRequest {
queryId @0 :AgentQueryId;
}
# Result of consensus check
struct AgentTryConsensusResponse {
union {
result @0 :Text; # Consensus reached - final answer
pending @1 :AgentQueryState; # Still collecting responses
noConsensus @2 :AgentQueryState; # Min responses met but no consensus
error @3 :Text;
}
}
# =============================================================================
# RPC Interfaces for Consensus
# =============================================================================
# Threshold signing party interface
interface RingtailParty {
# Get party information
getInfo @0 () -> (info :RingtailPartyInfo);
# Execute Round 1 of signing protocol
signRound1 @1 (request :RingtailSignRequest) -> (output :RingtailRound1Output);
# Execute Round 2 of signing protocol
signRound2 @2 (
request :RingtailSignRequest,
round1Outputs :List(RingtailRound1Output)
) -> (output :RingtailRound2Output);
# Finalize signature (combiner only)
finalize @3 (
request :RingtailSignRequest,
round2Outputs :List(RingtailRound2Output)
) -> (response :RingtailSignResponse);
# Verify a signature
verify @4 (request :RingtailVerifyRequest) -> (response :RingtailVerifyResponse);
}
# Agent consensus voting service
interface AgentConsensusService {
# Submit a new query for consensus
submitQuery @0 (request :AgentSubmitQueryRequest) -> (response :AgentSubmitQueryResponse);
# Submit an agent's response to a query
submitResponse @1 (request :AgentSubmitResponseRequest) -> (result :AgentSubmitResponseResult);
# Try to reach consensus on a query
tryConsensus @2 (request :AgentTryConsensusRequest) -> (response :AgentTryConsensusResponse);
# Get current query state
getQuery @3 (queryId :AgentQueryId) -> (state :AgentQueryState);
# Clean up expired queries
cleanup @4 () -> ();
# Get number of active queries
activeQueries @5 () -> (count :UInt32);
}
# Coordinator for distributed signing sessions
interface RingtailCoordinator {
# Initialize a new signing session
initSession @0 (
message :Data,
participants :List(UInt32)
) -> (sessionId :UInt64);
# Collect Round 1 outputs from all parties
collectRound1 @1 (sessionId :UInt64) -> (outputs :List(RingtailRound1Output));
# Collect Round 2 outputs from all parties
collectRound2 @2 (sessionId :UInt64) -> (outputs :List(RingtailRound2Output));
# Get final signature for a session
getSignature @3 (sessionId :UInt64) -> (response :RingtailSignResponse);
# Cancel a signing session
cancelSession @4 (sessionId :UInt64) -> ();
# List active sessions
listSessions @5 () -> (sessions :List(UInt64));
}
# =============================================================================
# W3C Decentralized Identifier (DID) Types
# Implements W3C DID Core 1.0 specification
# =============================================================================
# DID Method enum
enum DidMethod {
lux @0; # Lux blockchain-anchored DID
key @1; # Self-certifying DID from cryptographic key
web @2; # DNS-based DID
}
# Decentralized Identifier
struct Did {
method @0 :DidMethod;
id @1 :Text; # Method-specific identifier (e.g., z6Mk...)
}
# Verification method type
enum VerificationMethodType {
jsonWebKey2020 @0;
multikey @1;
mlDsa65VerificationKey2024 @2;
}
# Verification method (public key) in DID Document
struct VerificationMethod {
id @0 :Text; # e.g., "did:lux:z6Mk...#keys-1"
type @1 :VerificationMethodType;
controller @2 :Text; # Controller DID
publicKeyMultibase @3 :Text; # Multibase-encoded public key
publicKeyJwk @4 :Data; # JSON Web Key (optional, as JSON bytes)
blockchainAccountId @5 :Text; # Blockchain account ID (for Lux DIDs)
}
# Service type
enum ServiceType {
zapAgent @0; # ZAP Agent service
didCommMessaging @1; # DID Communication
linkedDomains @2; # Linked Domains
credentialRegistry @3; # Credential Registry
}
# Service endpoint
struct ServiceEndpoint {
union {
uri @0 :Text; # Single URI endpoint
uris @1 :List(Text); # Multiple URI endpoints
structured @2 :StructuredEndpoint;
}
struct StructuredEndpoint {
uri @0 :Text;
accept @1 :List(Text);
routingKeys @2 :List(Text);
}
}
# Service in DID Document
struct Service {
id @0 :Text; # e.g., "did:lux:z6Mk...#zap-agent"
type @1 :ServiceType;
serviceEndpoint @2 :ServiceEndpoint;
}
# W3C DID Document
struct DidDocument {
context @0 :List(Text); # JSON-LD context
id @1 :Text; # DID subject
controller @2 :Text; # Optional controller DID
# Verification methods (public keys)
verificationMethod @3 :List(VerificationMethod);
# Verification relationships (references to verification method IDs)
authentication @4 :List(Text);
assertionMethod @5 :List(Text);
keyAgreement @6 :List(Text);
capabilityInvocation @7 :List(Text);
capabilityDelegation @8 :List(Text);
# Service endpoints
service @9 :List(Service);
}
# Node identity for ZAP network participation
struct NodeIdentity {
did @0 :Did;
publicKey @1 :Data; # ML-DSA-65 public key (1952 bytes)
stake @2 :UInt64; # Staked amount (optional, 0 if none)
stakeRegistry @3 :Text; # Stake registry reference
}
# Stake registry entry
struct StakeEntry {
did @0 :Did;
amount @1 :UInt64;
timestamp @2 :Timestamp;
}
# Request to resolve a DID to its document
struct DidResolveRequest {
did @0 :Text; # Full DID URI string
}
# Response from DID resolution
struct DidResolveResponse {
union {
document @0 :DidDocument;
error @1 :Text;
notFound @2 :Void;
}
}
# Request to create/register a new DID
struct DidCreateRequest {
method @0 :DidMethod;
publicKey @1 :Data; # ML-DSA-65 public key
services @2 :List(Service); # Optional initial services
}
# Response from DID creation
struct DidCreateResponse {
union {
did @0 :Did;
error @1 :Text;
}
}
# DID Registry interface for resolution and management
interface DidRegistry {
# Resolve a DID to its document
resolve @0 (request :DidResolveRequest) -> (response :DidResolveResponse);
# Create/register a new DID
create @1 (request :DidCreateRequest) -> (response :DidCreateResponse);
# Update a DID document (requires authentication)
update @2 (did :Text, document :DidDocument, signature :Data) -> (success :Bool, error :Text);
# Deactivate a DID (requires authentication)
deactivate @3 (did :Text, signature :Data) -> (success :Bool, error :Text);
# Get stake for a DID
getStake @4 (did :Text) -> (amount :UInt64);
# Set stake for a DID (requires authentication)
setStake @5 (did :Text, amount :UInt64, signature :Data) -> (success :Bool, error :Text);
}