112 lines
2.8 KiB
Markdown
112 lines
2.8 KiB
Markdown
|
|
# ENC/FER1-RECEIPT/1 — Canonical Encoding for FER/1 Receipts
|
||
|
|
|
||
|
|
Status: Draft
|
||
|
|
Owner: Architecture
|
||
|
|
Version: 0.1.0
|
||
|
|
SoT: Yes
|
||
|
|
Last Updated: 2025-12-01
|
||
|
|
Linked Phase Pack: PH07
|
||
|
|
Tags: [evidence, receipt, deterministic, execution]
|
||
|
|
|
||
|
|
**Document ID:** `ENC/FER1-RECEIPT/1`
|
||
|
|
**Profile ID:** `FER_ENC_RECEIPT_V1 = 0x0301`
|
||
|
|
**TypeTag:** `TYPE_TAG_FER1_RECEIPT_1 = 0x00000301`
|
||
|
|
|
||
|
|
**Depends on (normative):**
|
||
|
|
|
||
|
|
* `ASL/1-CORE v0.4.x` — value model (`Artifact`, `Reference`, `OctetString`)
|
||
|
|
* `ENC/ASL1-CORE v1.0.x` — canonical encoding for `Reference`
|
||
|
|
* `FER/1` — receipt semantics and required fields
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 0. Overview
|
||
|
|
|
||
|
|
`ENC/FER1-RECEIPT/1` defines the canonical binary encoding for FER/1 receipts.
|
||
|
|
Receipts are stored as ASL/1 Artifacts with:
|
||
|
|
|
||
|
|
```
|
||
|
|
Artifact.type_tag = TYPE_TAG_FER1_RECEIPT_1
|
||
|
|
Artifact.bytes = ReceiptBytes
|
||
|
|
```
|
||
|
|
|
||
|
|
This encoding is deterministic and injective. Ordering is fixed and list
|
||
|
|
ordering is required for canonicalization.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 1. ReceiptBytes Layout (v1)
|
||
|
|
|
||
|
|
All integers are **big-endian**. Lengths are unsigned.
|
||
|
|
|
||
|
|
```
|
||
|
|
ReceiptBytes =
|
||
|
|
fer1_version : U16
|
||
|
|
function_ref : EncodedRef
|
||
|
|
input_manifest_ref : EncodedRef
|
||
|
|
environment_ref : EncodedRef
|
||
|
|
evaluator_id_len : U32
|
||
|
|
evaluator_id_bytes : BYTES
|
||
|
|
output_ref : EncodedRef
|
||
|
|
executor_count : U32
|
||
|
|
executor_refs : EncodedRef[executor_count]
|
||
|
|
parity_count : U32
|
||
|
|
parity_entries : ParityEntry[parity_count]
|
||
|
|
started_at : U64
|
||
|
|
completed_at : U64
|
||
|
|
```
|
||
|
|
|
||
|
|
Rules (normative):
|
||
|
|
|
||
|
|
* `fer1_version` MUST be `0x0001`.
|
||
|
|
* `parity_count` MUST equal `executor_count`.
|
||
|
|
* Every `ParityEntry.output_ref` MUST equal the top-level `output_ref`.
|
||
|
|
* `parity_entries[i].executor_ref` MUST equal `executor_refs[i]`.
|
||
|
|
* `started_at` MUST be less than or equal to `completed_at`.
|
||
|
|
* `executor_refs` and `parity_entries` MUST be ordered by ascending
|
||
|
|
`EncodedRef` byte order to ensure canonicalization.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 2. EncodedRef
|
||
|
|
|
||
|
|
`EncodedRef` embeds an ASL/1 `Reference` using a length prefix:
|
||
|
|
|
||
|
|
```
|
||
|
|
EncodedRef =
|
||
|
|
ref_len : U32
|
||
|
|
ref_bytes : BYTES // ReferenceBytes (ENC/ASL1-CORE v1)
|
||
|
|
```
|
||
|
|
|
||
|
|
`ref_len` is the length of `ReferenceBytes`. `ReferenceBytes` uses the
|
||
|
|
canonical encoding from `ENC/ASL1-CORE v1`.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 3. ParityEntry
|
||
|
|
|
||
|
|
```
|
||
|
|
ParityEntry =
|
||
|
|
executor_ref : EncodedRef
|
||
|
|
output_ref : EncodedRef
|
||
|
|
has_sbom_ref : U8
|
||
|
|
sbom_ref? : EncodedRef // if has_sbom_ref == 1
|
||
|
|
parity_digest_len : U32
|
||
|
|
parity_digest : BYTES
|
||
|
|
```
|
||
|
|
|
||
|
|
`parity_digest` is an opaque, executor-specific digest. Empty digests are
|
||
|
|
allowed (`parity_digest_len = 0`).
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 4. Canonicalization and Validation
|
||
|
|
|
||
|
|
Implementations MUST:
|
||
|
|
|
||
|
|
* enforce list ordering for `executor_refs` and `parity_entries`,
|
||
|
|
* reject truncated payloads or trailing bytes, and
|
||
|
|
* reject any receipt where required references are malformed or invalid.
|
||
|
|
|
||
|
|
No other metadata or policy is embedded in the receipt bytes.
|