signet

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Mar 20, 2026 License: Apache-2.0 Imports: 11 Imported by: 0

README ¶

pkg/signet

Core Signet token structures and encoding.

Status: 🧪 Experimental

Token format and CBOR encoding implementation.

What It Does

Defines the Signet token structure using CBOR with integer keys:

graph LR
    subgraph "Token Structure (Integer Keys)"
        Token[CBOR Map]
        Token --> K1["1: IssuerID (string)"]
        Token --> K2["2: ConfirmationID (32 bytes)"]
        Token --> K3["3: ExpiresAt (int64)"]
        Token --> K4["4: Nonce (16 bytes)"]
        Token --> K5["5: EphemeralKeyID (32 bytes)"]
        Token --> K6["6: NotBefore (int64)"]
    end

    Token --> Encode[CBOR Encode]
    Encode --> Compact["~100 bytes<br/>(40% smaller than JSON)"]

    style Token fill:#99ccff
    style Compact fill:#99ff99

Files

  • token.go - Token structure and encoding

Token Fields

Key Field Type Purpose
1 IssuerID string Identity of token issuer
2 ConfirmationID []byte SHA-256 of master public key
3 ExpiresAt int64 Unix timestamp expiry
4 Nonce []byte 16-byte random for replay protection
5 EphemeralKeyID []byte SHA-256 of ephemeral public key
6 NotBefore int64 Unix timestamp for activation

Why Integer Keys?

  • Smaller tokens: ~40% size reduction vs string keys
  • Deterministic encoding: Same token always produces same bytes
  • Efficient parsing: Faster to decode integers than strings
  • Version-friendly: New keys can be added without breaking parsers

CBOR Benefits

  • Binary format (smaller than JSON)
  • Self-describing (includes type information)
  • RFC 8949 standard
  • Deterministic encoding mode available
  • Widely supported across languages

Wire Format (Planned)

SIG1.<base64url(cbor_token)>.<base64url(signature)>

Note: Full wire format not yet implemented in v0.0.1

Usage Example

token := &Token{
    IssuerID:        "did:key:signet",
    ConfirmationID:  sha256(masterPubKey),
    ExpiresAt:       time.Now().Add(5*time.Minute).Unix(),
    Nonce:           generateNonce(),
    EphemeralKeyID:  sha256(ephemeralPubKey),
    NotBefore:       time.Now().Unix(),
}

encoded, err := cbor.Marshal(token)  // ~100 bytes

Documentation ¶

Index ¶

Constants ¶

View Source
const (
	// SIG1Prefix is the wire format prefix
	SIG1Prefix = "SIG1"

	// SIG1Separator is the field separator in the wire format
	SIG1Separator = "."
)

Variables ¶

View Source
var (
	// ErrTokenExpired indicates the token has expired
	ErrTokenExpired = errors.New("token has expired")

	// ErrInvalidToken indicates the token payload failed validation
	ErrInvalidToken = errors.New("token is invalid")
)

Common errors

Functions ¶

func ComputeCapabilityID ¶

func ComputeCapabilityID(capTokens []uint64) ([]byte, error)

ComputeCapabilityID computes the 128-bit capability identifier from capability tokens per ADR-002 section 3.1.

The computation: 1. Sort tokens numerically 2. Deduplicate (keep first occurrence after sort) 3. Encode as canonical CBOR array 4. Hash with domain separation and truncate to 128 bits

Empty capability lists:

  • nil or []uint64{} both normalize to empty array
  • Empty capabilities produce a deterministic hash
  • Semantics: "no capabilities" typically means "no access" unless the authorization layer explicitly grants default permissions
  • This allows tokens to be issued without capabilities for revocation checking or identity verification only

func EncodeSIG1 ¶

func EncodeSIG1(token *Token, signer cose.Signer) (string, error)

EncodeSIG1 encodes a token into SIG1 wire format using COSE Sign1

Format: SIG1.<base64url(CBOR)>.<base64url(COSE_Sign1)>

func ValidateCapabilityID ¶

func ValidateCapabilityID(capID []byte, capTokens []uint64) error

ValidateCapabilityID verifies that a capability ID matches the computed hash of the provided capability tokens.

Types ¶

type SIG1 ¶

type SIG1 struct {
	// Token is the decoded Signet token
	Token *Token

	// Signature is the COSE Sign1 signature bytes
	Signature []byte

	// Raw is the original wire format string
	Raw string
}

SIG1 represents a Signet token in SIG1 wire format.

Format: SIG1.<base64url(CBOR)>.<base64url(COSE_Sign1)>

The structure contains the decoded token, the COSE signature bytes, and the original wire format string for reference.

func DecodeSIG1 ¶

func DecodeSIG1(sig1 string) (*SIG1, error)

DecodeSIG1 decodes a SIG1 wire format string and verifies the signature

Returns the token and COSE signature. Does NOT verify signature - caller must verify using cose.Verifier.

func (*SIG1) String ¶

func (s *SIG1) String() string

String returns the SIG1 wire format representation

type Token ¶

type Token struct {
	IssuerID       string                 `cbor:"1,keyasint"`
	AudienceID     string                 `cbor:"2,keyasint,omitempty"`
	SubjectPPID    []byte                 `cbor:"3,keyasint"`
	ExpiresAt      int64                  `cbor:"4,keyasint"`
	NotBefore      int64                  `cbor:"5,keyasint"`
	IssuedAt       int64                  `cbor:"6,keyasint"`
	CapabilityID   []byte                 `cbor:"7,keyasint"`
	CapabilityVer  uint32                 `cbor:"8,keyasint,omitempty"`
	ConfirmationID []byte                 `cbor:"9,keyasint"`
	KeyID          []byte                 `cbor:"10,keyasint,omitempty"`
	CapTokens      []uint64               `cbor:"11,keyasint,omitempty"`
	CapCustom      map[string]interface{} `cbor:"12,keyasint,omitempty"`
	JTI            []byte                 `cbor:"13,keyasint"`
	Actor          map[string]interface{} `cbor:"14,keyasint,omitempty"`
	Delegator      map[string]interface{} `cbor:"15,keyasint,omitempty"`
	AudienceStr    string                 `cbor:"16,keyasint,omitempty"`
	Nonce          []byte                 `cbor:"17,keyasint,omitempty"`
	EphemeralKeyID []byte                 `cbor:"18,keyasint,omitempty"`
	Epoch          uint64                 `cbor:"19,keyasint,omitempty"`
}

Token represents the CBOR-encoded Signet token structure as defined in ADR-002. Integer keys are used to keep payloads compact and deterministic across languages.

Optional fields are omitted from the encoding when zero-valued.

func NewToken ¶

func NewToken(issuerID string, confirmationID []byte, ephemeralKeyID []byte, nonce []byte, validityDuration time.Duration) (*Token, error)

NewToken creates a new Signet token with sensible defaults derived from the provided cryptographic context. Additional fields can be set by mutating the returned Token before marshaling.

func Unmarshal ¶

func Unmarshal(data []byte) (*Token, error)

Unmarshal deserializes a token from CBOR bytes.

func VerifySIG1 ¶

func VerifySIG1(sig1 string, verifier cose.Verifier) (*Token, error)

VerifySIG1 decodes and verifies a SIG1 wire format string

func (*Token) IsExpired ¶

func (t *Token) IsExpired() bool

IsExpired reports whether the token has surpassed its expiry time.

func (*Token) IsValid ¶

func (t *Token) IsValid() bool

IsValid checks if the token is within its validity period.

func (*Token) Marshal ¶

func (t *Token) Marshal() ([]byte, error)

Marshal serializes the token to canonical CBOR bytes.

Jump to

Keyboard shortcuts

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