mirror of
https://github.com/zap-proto/go.git
synced 2026-10-30 15:05:00 +00:00
zapgen — interface (RPC) support: - Parse `interface` decls (brace + whitespace forms, one parser) with 1-based auto-assigned method ordinals; methods take ≤1 struct request and (after `returns`) ≤1 struct response, matching the spec README grammar. - desugar: `interface` opens a whitespace block; method lines pass through verbatim (no @N). Block headers now honored only at file scope, so a struct field NAMED `interface`/`struct` stays a field (H4 preserved). - emit: per interface a 1-based ordinal table, a typed Client over a Channel seam, and an abstract Handler + Dispatch<Iface> ordinal router, all over the new runtime call envelope. Method names exported. - New `rpc` package: the ZAP call envelope (BuildRequest/ParseRequest, BuildResponse/ParseResponse, Call, Response, status codes), byte-compatible with the other runtimes' transport envelopes (Version2 header + router msgType flags). Adds zap.NewBuilderV2. - examples/echo: generated service + end-to-end client↔dispatch↔handler test covering request/response, void, no-request, bare, handler-error, and unknown-ordinal paths. Golden fixtures for the interface codegen. cap — reconcile to SPEC v1.1: - B3 signature scope: sign SPEC §3 canonical bytes (Capability[0..164) || canonical(Caveats), Kind:u32||len:u32||Value), via Cap.CanonicalBytes — one definition shared by signer and verifier; excludes Sig and heap indirection so caps verify cross-language. CapID = Hash32(Canonical||Sig). - B2 delegation gate: define cross-cutting Permission bits (PermAttenuate 1<<32, PermAudit, PermRoot); enforce SPEC §2.3 step 3d in VerifyChain and at mint time in Attenuate (refuse a cap the verifier would reject). - B4/B6: VerifyRevocation is scheme-aware (dispatches on the tag byte); verifySig fails closed on SchemeReserved/unknown instead of falling back to ed25519. Verifier.VerifyRevocation added for PQ revocations. - spec_test.go covers all four. Rebrand finish + docs: - Zero capnp/Cap'n Proto and zero hanzo/avalabs/capnproto.org tokens in zap-native source (zap.go doc neutralized; cap doc-comment brand refs generalized). LLM.md refreshed: zapgen shipped (not "forthcoming"), rpc package, interface DSL, cap signature scope. Ignore the agents example binary. go build ./... and go test ./... -count=1 pass; race-clean on changed pkgs.
69 lines
2.6 KiB
Go
69 lines
2.6 KiB
Go
// Copyright (C) 2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package cap
|
|
|
|
import "encoding/binary"
|
|
|
|
// signedHeaderLen is the length of the fixed-header prefix that the
|
|
// signature covers: Capability bytes [0..164), i.e. Kind through the
|
|
// Caveats list pointer, NOT including Sig. Equal to capabilityViewSigOff
|
|
// (Sig begins exactly where the signed header ends).
|
|
const signedHeaderLen = capabilityViewSigOff
|
|
|
|
// CanonicalBytes returns the exact bytes a Capability's signature is
|
|
// computed over, per SPEC.md §3 "Signature chain":
|
|
//
|
|
// Capability[0..164) || for each Caveat in list order:
|
|
// Kind:u32-LE || len(Value):u32-LE || Value
|
|
//
|
|
// The fixed-header prefix is read verbatim from the wire buffer (so the
|
|
// signer and verifier agree on the on-wire field bytes), but the caveat
|
|
// section is RECOMPUTED from the decoded caveats rather than copied from
|
|
// the ZAP heap. This is deliberate: it excludes the heap-area pointer
|
|
// indirection bytes, so a tamperer cannot perturb the signature by
|
|
// rewriting heap layout, and it makes the signed bytes identical across
|
|
// language runtimes regardless of how each lays out its heap.
|
|
//
|
|
// CanonicalBytes does NOT include Sig (bytes [164..3572)); that is the
|
|
// field being authenticated.
|
|
func (c Cap) CanonicalBytes() []byte {
|
|
hdrOff := capRootOff(c.raw)
|
|
// Fixed header [0..164).
|
|
out := make([]byte, 0, signedHeaderLen+caveatsCanonicalLen(c.Caveats()))
|
|
out = append(out, c.raw[hdrOff:hdrOff+signedHeaderLen]...)
|
|
// Canonical caveat encoding, in list order.
|
|
for _, cv := range c.Caveats() {
|
|
out = appendCaveatCanonical(out, cv)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// appendCaveatCanonical appends one caveat's canonical encoding (Kind:u32-LE
|
|
// || len(Value):u32-LE || Value) to dst and returns the extended slice.
|
|
func appendCaveatCanonical(dst []byte, cv Caveat) []byte {
|
|
var hdr [8]byte
|
|
binary.LittleEndian.PutUint32(hdr[0:4], uint32(cv.Kind))
|
|
binary.LittleEndian.PutUint32(hdr[4:8], uint32(len(cv.Value)))
|
|
dst = append(dst, hdr[:]...)
|
|
dst = append(dst, cv.Value...)
|
|
return dst
|
|
}
|
|
|
|
// caveatsCanonicalLen returns the byte length the canonical caveat
|
|
// section will occupy, used to size the CanonicalBytes buffer up front.
|
|
func caveatsCanonicalLen(cvs []Caveat) int {
|
|
n := 0
|
|
for _, cv := range cvs {
|
|
n += 8 + len(cv.Value)
|
|
}
|
|
return n
|
|
}
|
|
|
|
// capRootOff returns the absolute offset of the root object (the start of
|
|
// the Capability fixed header) within a wire buffer. The root offset is
|
|
// stored in the ZAP header at bytes [8:12].
|
|
func capRootOff(raw []byte) int {
|
|
return int(binary.LittleEndian.Uint32(raw[8:12]))
|
|
}
|