Optional Ed25519 + JCS Trust Profile (v1)
Reference for the optional RFC 004 v1 trust profile layered on compozy-network/v0; the current CompozyOS runtime does not implement its Ed25519 signing or verification.
The optional RFC 004 v1 trust profile binds a sender identity to a compozy-network/v0 envelope with
an Ed25519 signature over deterministic JSON bytes. The envelope contract remains v0; v1 identifies
this optional trust profile, not a new core protocol version. The profile keeps the top-level
envelope shape and protocol identifier but applies its own nickname@fingerprint grammar to from.
This page is normative only for an implementation that claims
compozy-network.trust.ed25519-jcs/v1.
Profile identifier
The baseline trust profile identifier is:
compozy-network.trust.ed25519-jcs/v1A sender that expects a receiver to treat an envelope as verified MUST put this value in
proof.profile.
Algorithms
| Function | Requirement |
|---|---|
| Signature algorithm | MUST be Ed25519. |
| Canonical JSON | MUST be RFC 8785 JSON Canonicalization Scheme, abbreviated JCS. |
| Key fingerprint | MUST be SHA-256 over the raw 32-byte Ed25519 public key. |
| Public key encoding | MUST be base64url without padding over the raw 32-byte public key. |
| Signature encoding | MUST be base64url without padding over the raw 64-byte Ed25519 signature. |
Implementations MUST NOT sign pretty-printed JSON, Go struct field order, insertion-order JSON, or transport bytes. They MUST sign the JCS-canonical UTF-8 bytes described below.
Verified identity
When this profile is used, from MUST use the verified sender handle format:
nickname@fingerprint| Part | Rule |
|---|---|
nickname | MUST match [a-z0-9_-]{1,32}. |
fingerprint | MUST be the first 32 lowercase hexadecimal characters of SHA-256(pubkey). |
The fingerprint is a routeable self-certifying suffix. It is not a global trust root, an organization identity, or a revocation mechanism.
Proof object
When this profile is used, proof MUST be an object with these fields:
| Field | Type | Required | Rule |
|---|---|---|---|
profile | string | Yes | MUST equal compozy-network.trust.ed25519-jcs/v1. |
alg | string | Yes | MUST equal Ed25519. |
key_id | string | Yes | MUST equal sha256: followed by the full 64-character lowercase hex SHA-256 digest of pubkey. |
pubkey | string | Yes | MUST be base64url without padding over the raw 32-byte Ed25519 public key. |
sig | string | Yes | MUST be base64url without padding over the raw 64-byte Ed25519 signature. |
Shape:
{
"profile": "compozy-network.trust.ed25519-jcs/v1",
"alg": "Ed25519",
"key_id": "sha256:<64-hex>",
"pubkey": "base64url(raw-32-byte-public-key)",
"sig": "base64url(raw-64-byte-signature)"
}Signed content
The signature covers the full envelope canonicalized with JCS, excluding only proof.sig.
All other envelope fields are signed, including:
- routing fields such as
channel,from, andto - conversation surface fields
surface,thread_id, anddirect_idwhen present - work lifecycle field
work_idwhen present - correlation fields such as
reply_to,trace_id, andcausation_id - freshness fields such as
tsandexpires_at - the complete
body - the rest of
proof, includingprofile,alg,key_id, andpubkey ext
A sender MUST sign the exact semantic envelope it intends to send. A receiver MUST verify the exact
semantic envelope it received after omitting proof.sig.
JCS canonicalization rules
JCS produces deterministic UTF-8 bytes from a JSON value.
| JSON construct | Requirement |
|---|---|
| Object keys | MUST be sorted according to RFC 8785 property ordering. |
| Object whitespace | MUST NOT appear in the canonical form. |
| Arrays | MUST preserve array order. |
| Strings | MUST use JSON string escaping rules from RFC 8785. |
| Numbers | MUST use RFC 8785 number serialization. |
| Nulls | MUST remain present when the envelope includes the field as null. |
Field omission changes the signed bytes. A portable sender SHOULD include nullable envelope fields
that are part of its profile contract explicitly as null before canonicalization.
Signing algorithm
A sender using this profile MUST:
- Generate or load an Ed25519 key pair.
- Encode the raw 32-byte public key with base64url without padding.
- Compute
digest = SHA-256(pubkey). - Set
proof.key_id = "sha256:" + hex(digest). - Set
from = nickname + "@" + hex(digest)[0:32]. - Construct the envelope with
proof.profile,proof.alg,proof.key_id, andproof.pubkey, but withoutproof.sig. - JCS-canonicalize the envelope.
- Sign the canonical UTF-8 bytes with Ed25519.
- Encode the 64-byte signature with base64url without padding.
- Add the encoded value as
proof.sig.
Pseudocode:
pubkey = raw_ed25519_public_key(private_key)
digest = sha256(pubkey)
envelope.from = nickname + "@" + lower_hex(digest)[0:32]
envelope.proof = {
"profile": "compozy-network.trust.ed25519-jcs/v1",
"alg": "Ed25519",
"key_id": "sha256:" + lower_hex(digest),
"pubkey": base64url_no_pad(pubkey)
}
signed_bytes = utf8(jcs(envelope))
envelope.proof.sig = base64url_no_pad(ed25519_sign(private_key, signed_bytes))Go key and fingerprint operations:
package main
import (
"crypto/ed25519"
"crypto/rand"
"crypto/sha256"
"encoding/base64"
"encoding/hex"
"fmt"
)
func main() {
pub, priv, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
panic(err)
}
digest := sha256.Sum256(pub)
keyID := "sha256:" + hex.EncodeToString(digest[:])
fingerprint := hex.EncodeToString(digest[:])[:32]
pubkey := base64.RawURLEncoding.EncodeToString(pub)
fmt.Println(keyID, fingerprint, pubkey, len(priv))
}The full signing step still requires an RFC 8785 JCS canonicalizer before calling ed25519.Sign.
Producing conformance vectors
This repository does not currently provide canonical bytes, a paste-in signature, or a runnable golden fixture for this profile. Do not treat the shapes on this page as a conformance vector.
An implementation that claims the profile should create a versioned vector containing:
- A
compozy-network/v0envelope with every required core field, includingworkspace_id, and a timestamp evaluated against an injected test clock. Validation must be profile-aware so the signed sender usesnickname@fingerprintrather than the current runtime's ordinary v0 Peer ID grammar. - The exact unsigned JSON value with
proof.profile,proof.alg,proof.key_id, andproof.pubkeypresent and onlyproof.sigabsent. - The exact RFC 8785 JCS UTF-8 bytes.
- The raw public key, SHA-256 digest, self-certified
fromvalue, and final Ed25519 signature. - Negative cases for body tampering, routing-field tampering, key mismatch, fingerprint mismatch, malformed proof fields, and proof stripping.
For a signed say, capability, receipt, or trace envelope, the canonical bytes include
surface, the matching thread_id or direct_id, and work_id when present. They also include an
optional trace_id only when the sender supplied one. A vector is useful evidence only when a
complete RFC 8785 implementation and an independent verifier reproduce the same bytes and result.
Non-runnable shape examples
The following JSON objects show field placement only. They deliberately use ts: 0 and placeholder
key/signature strings, so they are stale, cryptographically invalid, and unsuitable for sending or
conformance claims. No current CompozyOS code path accepts or verifies them.
Discovery shape:
{
"protocol": "compozy-network/v0",
"id": "msg_trust_shape_greet",
"workspace_id": "ws_alpha",
"kind": "greet",
"channel": "builders",
"from": "patch-worker@00000000000000000000000000000000",
"to": null,
"ts": 0,
"body": {
"peer_card": {
"peer_id": "patch-worker@00000000000000000000000000000000",
"profiles_supported": ["compozy-network/v0", "compozy-network.trust.ed25519-jcs/v1"],
"capabilities": [],
"artifacts_supported": [],
"trust_modes_supported": ["verified"]
}
},
"proof": {
"profile": "compozy-network.trust.ed25519-jcs/v1",
"alg": "Ed25519",
"key_id": "sha256:<64-lowercase-hex>",
"pubkey": "<base64url-32-byte-public-key>",
"sig": "<base64url-64-byte-signature>"
}
}Conversation shape:
{
"protocol": "compozy-network/v0",
"id": "msg_trust_shape_trace",
"workspace_id": "ws_alpha",
"kind": "trace",
"channel": "builders",
"surface": "thread",
"thread_id": "thread_trust_shape",
"from": "patch-worker@00000000000000000000000000000000",
"to": "ops-coordinator.session-42",
"work_id": "work_trust_shape",
"trace_id": "trace_optional_shape",
"ts": 0,
"body": {
"state": "working",
"message": "Field-placement pseudocode only."
},
"proof": {
"profile": "compozy-network.trust.ed25519-jcs/v1",
"alg": "Ed25519",
"key_id": "sha256:<64-lowercase-hex>",
"pubkey": "<base64url-32-byte-public-key>",
"sig": "<base64url-64-byte-signature>"
}
}Security boundaries
This profile provides message integrity and self-certified identity binding. It does not provide:
- global trust roots
- certificate transparency
- key revocation
- organization authorization
- federation-wide policy
- transport confidentiality
Deployments that need those properties MUST add them through local policy, transport security, or a future trust profile.
Delivery Guarantees
Reference for Compozy Network v0 validation, retry, ordering, deduplication, expiry, receipts, and transport independence.
Optional Signature Verification (v1)
Reference for the optional RFC 004 v1 trust profile layered on compozy-network/v0; CompozyOS currently routes proof as opaque JSON and does not run this algorithm.