Protocol Specification v0.6

Open Issues

This page records the limits of this edition so an implementer can choose the correct integration boundary. It describes only what this edition implements. A feature outside this contract must not be assumed merely because its name or discriminator appears in a design document.

Edition limits

A request that meets a limit of this edition stops at a fixed step with a named result and no effect.

A request that meets a limit of this edition stops at a fixed step with a named result and no effect. The Rust reference checks a received request in four drawn steps. The version profile refuses an operation outside the accepted set with UNSUPPORTED_VERSION; Write, Timeout, CorrelatedResponse, Capabilities, Liveness and InstallEpoch are in the operation table but not accepted. After the source binding and delivery window checks, a packet that names signature scheme 2, THRESHOLD, is refused with INVALID_THRESHOLD_SIGNATURE, and operand decoding refuses an amount above u64 with INVALID_FORMAT. These three refusals are not recorded. A request signed at a cut that another commit has moved is BUSY; that outcome is recorded and consumes the call identifier. A request that passes every step produces its effect and result. 1 Version profile accepted operations outside the accepted setUNSUPPORTED_VERSION Write Timeout CorrelatedResponse Capabilities Liveness InstallEpoch source bindingdelivery window 2 Signature scheme SINGLE with Ed25519 scheme 2, THRESHOLDINVALID_THRESHOLD_SIGNATURE 3 Operands layout of the opcode amount above u64INVALID_FORMAT 4 Commit at the current cut the cut has movedBUSY, recorded Effect and result
  1. 1

    In the table, not accepted

    Six operations keep their full layout in the operation table. The reference answers each with UNSUPPORTED_VERSION before any signature is checked.

  2. 2

    No THRESHOLD verifier

    SINGLE with Ed25519 is the implemented scheme. A packet that names scheme 2 is refused before any signature verification.

  3. 3

    Amounts fit in u64

    An amount travels as 32 bytes. The product accepts it only when the first 24 bytes are zero and never truncates it.

  4. 4

    Busy is recorded

    Requests on different assets share one cut, so a request signed at a cut that another commit has moved is BUSY without effect. The outcome is recorded and consumes the call identifier; a resend needs a new signed cut and a new call sequence number.

  • Path of a request that passes
  • Refused with this result and no effect
  • In the operation table, not accepted by the reference

Schematic: refusals for frame size, source binding, the delivery window and an invalid signature are not drawn. The drawn steps run in this order in the Rust reference.

Figure 1: The fixed steps where a request beyond this edition's limits stops, with the result of each

Executable scope#

NormativeBytes, test vectors and proofs

The reference profile (opens in a new tab)'s supported inbound operations are listed in Field Tables. SINGLE (opens in a new tab) with Ed25519 (opens in a new tab) is implemented; a THRESHOLD (opens in a new tab) discriminator does not provide a threshold verifier. The Go package implements its documented wire/admission (opens in a new tab) surface and is not a durable authority or signed-response verifier.

LimitIntegration consequence
Position-based operandsMatch the family, opcode, exact counts and each operand's meaning
Registered 64-bit handlesEstablish identity and domain registration out of band
Product amounts limited to u64Reject out-of-range base-unit amounts instead of truncating
Global revision and epoch cutAnother committed write can make a fresh signed request Busy
Configured size, depth and time limitsRead the host profile; do not assume universal constants
Absent and indefinite appeal deadlineDifferent wire forms, same product meaning in this edition
JSON reference signing inputsReproduce the exact defined serialization
Request-admission errors before signature verificationAccount for the documented registration-disclosure limitation

Where the reference stops#

An operation outside the reference set keeps its full layout in the operation table and is marked as not accepted:

JSONWrite: in the table, not acceptedspec/operations.jsonL609-L627Highlighted lines are discussed in the textSource (opens the lines on GitHub in a new tab)
{  "family": 3, "opcode": 7, "name": "Write", "title": "write",  "summary": "Writes a permitted data value for the asset.",  "reference_accepts": false,  "words": [    {"kind": "use", "group": "call_prefix"},    {"kind": "use", "group": "credential"},    {"kind": "use", "group": "version_vector"},    {"kind": "word", "name": "generation", "type": "generation"},    {"kind": "word", "name": "value", "type": "u64", "description": "Data value to write."}  ],  "blobs": [    {"name": "amount", "type": "amount_u256"}  ],  "deadline": "absent",  "target_domain": "origin_domain",  "call": true,  "recorded_codes": [1, 2, 3, 20]},

The reference configuration accepts a fixed set of opcodes per family (opens in a new tab), none for heartbeat (opens in a new tab), and its receiving path answers any other operation with UNSUPPORTED_VERSION before the signature is checked:

RustOperations the reference acceptssrc/authority/recovery/wire/ed25519.rsL455-L465Source (opens the lines on GitHub in a new tab)
fn supported_frame(core: &Core) -> bool {    match core.body.as_ref() {        Some(Body::StateSync(op)) => matches!(op.opcode, Some(1..=6)),        Some(Body::RegulatoryAction(op)) => matches!(op.opcode, Some(1..=3)),        Some(Body::Ack(op)) => op.opcode == Some(1),        Some(Body::Query(op)) => matches!(op.opcode, Some(1..=8)),        Some(Body::LockManagement(op)) => matches!(op.opcode, Some(1..=6)),        Some(Body::Governance(op)) => op.opcode == Some(1),        _ => false,    }}

Generic admission then checks the negotiated version and family, the source binding and the delivery window, and refuses scheme 2 before any signature verification because this edition has no THRESHOLD verifier:

RustScope first, no THRESHOLD verifiersrc/wire/admission.rsL87-L110Highlighted lines are discussed in the textSource (opens the lines on GitHub in a new tab)
pub fn admit_packet(    packet: &CanonicalPacket,    profile: &Profile,    boundary: &Boundary,) -> Result<()> {    check_scope(packet.core(), profile, boundary)?;    let scheme = packet        .core()        .signature_scheme        .ok_or(WireError::InvalidFormat)?;    if scheme == 2 {        return Err(WireError::InvalidThresholdSignature);    }    if !profile.schemes.contains(&scheme)        || !verify(            &boundary.public_key,            &packet.signing_bytes()?,            packet.signature(),        )    {        return Err(WireError::InvalidSignature);    }    Ok(())}

An amount travels as a 32-byte unsigned integer, and the product accepts it only when its first 24 bytes are zero:

Product amount rangesrc/wire/codec.rsL374-L388Highlighted lines are discussed in the textSource (opens the lines on GitHub in a new tab)
#[derive(Clone, Copy, Debug, Eq, PartialEq)]pub struct Unsigned256(pub [u8; 32]);impl Unsigned256 {    pub fn from_bytes(bytes: &[u8]) -> Result<Self> {        Ok(Self(bytes.try_into().map_err(|_| BAD)?))    }    pub fn product_amount(self) -> Result<u64> {        if self.0[..24].iter().any(|&byte| byte != 0) {            return Err(BAD);        }        Ok(u64::from_be_bytes(self.0[24..].try_into().unwrap()))    }}

Two requests on different assets share one authority cut, so the second request signed at that cut is Busy without effect once the first commits:

TextDifferent assets, one cuttests/vectors/parallel-composition.tsvL8-L8Source (opens the lines on GitHub in a new tab)

Columnsidoperationinputsexpectedevidence

distinct-assets-share-the-authority-cut	pair	operation_a=execute;operation_b=execute;asset_a=17;asset_b=22;epoch=9;same_initial_cut=true;request_exchange=true	schedule=serial;second_fresh_result=busy;second_effect=false	compatible_actions_have_no_shared_writer,actual_primary_write_changes_the_reply_to_the_same_signed_cut,prior_call_on_any_route_cannot_repeat_an_authority_effect

The size and nesting limits, the clock skew and the TTL (opens in a new tab) floor are fields of the receiving boundary that the host fills in, and the largest signed delivery TTL is a separate configuration value. The code fixes no number for any of them:

RustHost-supplied limitssrc/wire/admission.rsL12-L29Highlighted lines are discussed in the textSource (opens the lines on GitHub in a new tab)
#[derive(Clone, Copy, Debug, Eq, PartialEq)]pub struct Boundary {    pub deployment: u64,    pub source: u64,    pub target: u64,    pub principal: u64,    pub key_id: u64,    pub epoch: u64,    pub route_scope: u64,    pub now: u64,    pub asset_ttl_floor: u64,    pub future_skew: u64,    pub max_frame: usize,    pub max_nesting: usize,    pub version_floor: u64,    pub critical_allowed: bool,    pub public_key: [u8; 32],}

The schema gives a regulatory operation three appeal deadline (opens in a new tab) forms on the wire, and this edition gives the absent and the indefinite form one meaning:

Protocol BuffersAppeal deadline formsproto/oip.protoL55-L63Highlighted lines are discussed in the textSource (opens the lines on GitHub in a new tab)
// The appeal deadline of a regulatory action (family 2). Operations of// other families reject both members. In this version an absent member and// appeal_deadline_indefinite both mean that no appeal deadline applies.oneof appeal_deadline {  // Only the value true is canonical.  bool appeal_deadline_indefinite = 4;  // Unix time in UTC seconds.  fixed64 appeal_deadline_utc_seconds = 5;}

Recovery assumptions#

NormativeBytes, test vectors and proofs

The rollback-resistant profile requires separately administered authority and witness transports, exact authenticated control values, durable archive selection and the configured key custody. A stale but cryptographically valid snapshot must hold. The protocol does not make an unavailable independent witness available or turn a local timeout into evidence of reversal.

Architecture outside this profile#

DesignCarried from v0.5, without bytes or test vectors in this version

Channels are installed out of band. General peer discovery, multi-hop relaying, condition expressions (opens in a new tab), signed Registry records on the wire, retention periods and the complete deployed OSS (opens in a new tab) service are outside this edition. Migration from v0.5 states how the related v0.5 topics are treated.

Assurance and reporting#

The formal result applies to the model and source correspondence (opens in a new tab) stated in the artifact mapping, under its assumptions. It is not a security audit of the entire compiled service, external adapters or operating environment.

Reproduce the relevant checks in Conformance and report a concrete difference with the exact input, selected profile and observed outcome through the repository's support or security process.


Edition history#

  • 0.6.0: Added this edition. The v0.5 specification remains available at its original addresses.