sign

package
v0.64.21 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 28, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

Documentation

Overview

Package sign is the cross-cutting signing primitive: per-file ephemeral Ed25519 keypair generation, canonical JSON encoding (RFC 8785-style), and envelope signing/verification. The private key is discarded the instant the signature is computed; the public key + signature live inside the envelope, so every file is independently verifiable offline.

See ARCHITECTURE.md §Core principles #4 and docs/architecture/02-layers.md §Per-file signing.

Index

Constants

View Source
const AlgorithmEd25519 = "ed25519"

AlgorithmEd25519 is the built-in default signature algorithm. Its name travels in Signature.Algorithm (and thus in every envelope and manifest), so a verifier selects the right implementation from the signed artifact alone — adding a new algorithm never changes the wire format.

Variables

This section is empty.

Functions

func Algorithms added in v0.27.2

func Algorithms() []string

Algorithms returns the sorted list of registered algorithm names.

func Encode

func Encode(v any) ([]byte, error)

Encode returns the RFC 8785-style canonical JSON encoding of v. Output is byte-identical for any Go input that represents the same logical JSON document — which is what makes Ed25519 signatures reproducible across processes, languages, and time.

Canonicalization rules implemented:

  • UTF-8 output (delegated to encoding/json).
  • No insignificant whitespace.
  • Object keys sorted lexicographically by Unicode code-point.
  • String escaping follows encoding/json with SetEscapeHTML(false); '<', '>', '&' are emitted verbatim, not as \u escapes.
  • Numbers are preserved as their exact JSON source text via a UseNumber re-parse, so arbitrary-precision integers (64-bit IDs, epoch-nanosecond timestamps) survive canonicalization with no precision loss. Floats are emitted verbatim from their source text; signed payloads in this CLI are not expected to contain floats, but if one appears it round-trips unchanged.
  • Array order is preserved.

The strategy is to leverage encoding/json for marshaling and string escaping (the parts most likely to go subtly wrong if hand-rolled), then re-emit the resulting generic tree with sorted keys and no whitespace.

func EncodeEnvelope

func EncodeEnvelope(e *core.Envelope) ([]byte, error)

EncodeEnvelope returns the canonical JSON bytes of e (signature included). This is the form written to the vault: the on-disk bytes are byte-identical across writers, so an auditor can verify by either re-canonicalizing on read or checking the file's SHA-256 against a recorded hash.

Returns an error if e has not been signed.

func EncodeManifest

func EncodeManifest(m *core.Manifest) ([]byte, error)

EncodeManifest returns the canonical JSON bytes of m (signature included). Returns an error if m has not been signed.

func Envelope

func Envelope(e *core.Envelope) error

Envelope signs e in place. After return, e.Signature carries the ephemeral keypair's public key and the signature value. The signature covers canonical JSON of {format_version, produced_at, records} — three fields, no signature sentinel.

func Manifest

func Manifest(m *core.Manifest) error

Manifest signs m in place using a fresh ephemeral Ed25519 keypair. The signature covers canonical JSON of every Manifest field except Signature itself — including FileHashes, which is the single-level Merkle root binding every file in the run folder.

func Register added in v0.27.2

func Register(name string, signer Signer, verify VerifyFunc)

Register adds or replaces the Signer + VerifyFunc for an algorithm name. Intended for eager package-level registration by built-in algorithms and for project-local or HSM/KMS-backed signers compiled in via `sigcomply build`. Panics on an empty name or nil signer/verify — a misconfigured signer must fail loudly at startup, never silently produce unverifiable evidence.

The registry is the sole coupling point between "how we sign" and "what we sign": Envelope/Manifest call Sign/Verify and never name an algorithm, mirroring how the source/vault/framework registries decouple policies from plugins.

func SetDefaultAlgorithm added in v0.27.2

func SetDefaultAlgorithm(name string) error

SetDefaultAlgorithm changes the algorithm Sign uses. Returns an error if the algorithm is not registered. Used by a FIPS build profile or a project policy to make, e.g., ECDSA-P256 the default signer without changing any calling code.

func Verify

func Verify(payload []byte, sig Signature) error

Verify checks signature against payload by dispatching on sig.Algorithm to the registered VerifyFunc. Returns a non-nil error on any failure mode (unregistered algorithm, malformed key/value, or cryptographic mismatch).

Verification answers "this payload was signed by whoever holds this key", not "this key is authorized". The caller is responsible for any trust-establishment beyond that.

func VerifyEnvelope

func VerifyEnvelope(e *core.Envelope) error

VerifyEnvelope checks the embedded signature against the envelope's content fields. Returns nil if the signature is valid.

func VerifyManifest

func VerifyManifest(m *core.Manifest) error

VerifyManifest checks the embedded signature against m's content fields. Returns nil if valid.

Types

type Signature

type Signature struct {
	Algorithm string
	PublicKey []byte
	Value     []byte
}

Signature is the on-the-wire shape of a signature: an algorithm identifier, the public verification key, and the signature value. Bytes are raw; envelopes/manifests encode them as base64 via JSON marshaling. The shape is algorithm-agnostic — Ed25519, ECDSA, RSA, an HSM/KMS-backed signer, or a post-quantum scheme all populate the same three fields.

func Sign

func Sign(payload []byte) (Signature, error)

Sign signs payload with the default algorithm's Signer.

func With added in v0.27.2

func With(algorithm string, payload []byte) (Signature, error)

With signs payload using the named algorithm's Signer. Returns an error if the algorithm is not registered. Named With (not SignWith) so callers read sign.With(alg, payload) without stutter.

type Signer added in v0.27.2

type Signer interface {
	// Algorithm is the identifier stamped into Signature.Algorithm and
	// used by Verify to dispatch to the matching VerifyFunc.
	Algorithm() string
	// Sign returns a Signature over payload.
	Sign(payload []byte) (Signature, error)
}

Signer produces a Signature over a payload using one algorithm.

The per-file ephemeral-keypair discipline (CLAUDE.md Invariant #3) is a property of the built-in ed25519Signer, NOT a requirement of this interface: an HSM/KMS-backed signer legitimately holds a long-lived key whose private half never leaves the device. What every Signer must guarantee is that the returned Signature carries enough to verify offline — for asymmetric schemes that means the public key in Signature.PublicKey; a future KMS signer that verifies by key reference would register a matching VerifyFunc.

type VerifyFunc added in v0.27.2

type VerifyFunc func(payload, publicKey, value []byte) error

VerifyFunc checks a signature's raw public key + value against a payload for one algorithm. Registered alongside a Signer so Verify can dispatch on Signature.Algorithm.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL