* HASH/ASL1 (interpretation and checking of `ReferenceBytes`)
> The Profile ID `ASL_ENC_CORE_V1` and this document’s version are **not** encoded into `ArtifactBytes` or `ReferenceBytes`. Encoding version is selected by context (deployment, profile, or store configuration), not embedded per value.
Except where otherwise noted, this document (text and diagrams) is licensed under
the Creative Commons Attribution 4.0 International License (CC BY 4.0).
The identifier registries and mapping tables (e.g. TypeTag IDs, HashId
assignments, EdgeTypeId tables) are additionally made available under CC0 1.0
Universal (CC0) to enable unrestricted reuse in implementations and derivative
specifications.
Code examples in this document are provided under the Apache License 2.0 unless
explicitly stated otherwise. Test vectors, where present, are dedicated to the
public domain under CC0 1.0.
---
## 0. Overview
`ENC/ASL1-CORE v1` defines the **canonical, streaming-friendly, injective binary encoding** used across the Amduat 2.0 substrate for two core value types from ASL/1-CORE:
1.**ArtifactBytes** — canonical bytes for an ASL/1 `Artifact`
2.**ReferenceBytes** — canonical bytes for an ASL/1 `Reference`
This profile ensures:
* **Injectivity** — each ASL/1 value maps to exactly one byte string.
* **Determinism** — identical values yield identical encodings across implementations.
* **Stability** — bytes never depend on platform, locale, endian, or environment.
* **Streaming-compatibility** — encoders, decoders, and hashers operate in forward-only mode.
`ASL_ENC_CORE_V1` is the **canonical ASL/1 encoding profile** used by the Amduat 2.0 substrate stack for:
* ASL/1 identity model (via canonical encoding + ASL1 hashing),
* the hashing substrate (HASH/ASL1),
* ASL/1-STORE persistence semantics,
* PEL/1 execution input/output artifacts,
* and canonical near-core profiles.
The encodings defined in this profile satisfy all canonical encoding requirements in `ASL/1-CORE §3.2`: injectivity, stability, determinism, explicit structure, type-sensitivity, byte-transparency, and streaming-friendliness.
---
## 1. Scope & Layering
### 1.1 Purpose
This specification defines:
* The **canonical binary layout** for `ArtifactBytes` and `ReferenceBytes`.
* Normative encoding and decoding procedures.
* How these encodings interact with the ASL1 hash family.
* Required consistency checks when HASH/ASL1 is present.
* Streaming and injectivity requirements.
### 1.2 Non-goals
This profile does **not** define:
* Any filesystem, transport, or database representation.
* Chunking or multipart strategies for large artifacts.
* Any alternative encoding families (those are separate profiles).
* Semantics of `TypeTag` values or registry rules.
* Storage layout, replication, or policy.
Those concerns belong to ASL/1-STORE, PEL/1, HASH/ASL1, and higher layers.
### 1.3 Layering constraints
In line with the substrate overview:
*`ENC/ASL1-CORE` is a **near-core substrate profile**, not a kernel primitive.
* It **MUST NOT** re-define `Artifact`, `Reference`, `TypeTag`, or `HashId`; those are defined solely by `ASL/1-CORE`.
* It is **storage-neutral** and **policy-neutral**.
* It defines exactly one canonical encoding profile: `ASL_ENC_CORE_V1`.
---
## 2. Conventions
The key words **MUST**, **SHOULD**, **MAY**, etc. follow RFC 2119.
### 2.1 Integer encodings
All multi-byte integers are encoded as **big-endian**:
*`u8` — 1 byte
*`u16` — 2 bytes
*`u32` — 4 bytes
*`u64` — 8 bytes
Only **fixed-width** integers are used.
### 2.2 Booleans (presence flags)
Booleans used as presence flags are encoded as:
*`false` → `0x00`
*`true` → `0x01`
Booleans are only used for presence flags, never for general logical conditions.
### 2.3 OctetString
Except where explicitly overridden, an `OctetString` is encoded as:
```text
[length (u64)] [raw bytes]
```
*`length` is the number of bytes.
*`length` MAY be zero.
* There is no implicit terminator or padding.
Whenever this profile says an ASL/1 field is an `OctetString`, its canonical encoding is this `u64 + bytes` form **unless explicitly stated otherwise**.
> **Exception:** `Reference.digest` is encoded without an explicit length field; see §4.2.
---
## 3. Artifact Encoding
### 3.1 Logical structure (from ASL/1-CORE)
From `ASL/1-CORE`:
```text
TypeTag {
tag_id: uint32
}
Artifact {
bytes: OctetString
type_tag: optional TypeTag
}
```
`TypeTag` semantics (registries, meaning of tag IDs) are opaque at this layer.
2. If `A.type_tag` is present, emit `A.type_tag.tag_id` as `u32`.
3. Let `bytes_len = len(A.bytes)`; emit `bytes_len` as `u64`.
4. Emit the raw bytes of `A.bytes`.
The result is the canonical `ArtifactBytes`.
This encoding satisfies the `ASL/1-CORE §3.2` requirements: injective, stable, deterministic, explicit in structure, type-sensitive, byte-transparent, and streaming-friendly.
### 3.4 Decoding (normative)
Given a byte slice known to contain exactly one `ArtifactBytes` value, the canonical decoding function:
* If the value is neither `0x00` nor `0x01`, fail with an encoding error.
2. If `has_type_tag == 0x01`, read `tag_id (u32)` and construct `TypeTag{ tag_id }`.
3. Read `bytes_len (u64)`.
4. Read exactly `bytes_len` bytes; this is `bytes`.
5. Construct `Artifact{ bytes, type_tag }` where `type_tag` is either `None` or `Some(TypeTag{ tag_id })` per steps above.
Decoders MUST reject:
* Invalid presence flags (`has_type_tag` not in `{0x00, 0x01}`).
* Truncated sequences (insufficient bytes for declared lengths).
* Over-long sequences where `bytes_len` cannot be represented or allocated safely in the implementation’s execution model (encoding error).
* Trailing bytes if the decoding context expects an isolated `ArtifactBytes` value.
### 3.5 Injectivity
The mapping:
```text
Artifact → ArtifactBytes
```
defined by `encode_artifact_core_v1` is **injective**:
* Each `Artifact` value has exactly one canonical byte string.
* Decoding the canonical bytes via `decode_artifact_core_v1` yields exactly that `Artifact`.
### 3.6 Streaming properties
Encoders and decoders MUST NOT require backtracking:
* The header (`has_type_tag`, optional `type_tag`, `bytes_len`) is computed and emitted/read once, in order.
*`bytes` MAY be streamed directly:
* Encoders MAY produce the payload incrementally after emitting `bytes_len`.
* Decoders MAY pass the payload through to a consumer or hasher as it is read.
Incremental hashing (e.g., computing digests over `ArtifactBytes`) MUST be possible with a single forward pass over the byte stream.
---
## 4. Reference Encoding
### 4.1 Logical structure (from ASL/1-CORE)
From `ASL/1-CORE`:
```text
Reference {
hash_id: HashId // uint16
digest: OctetString
}
HashId = uint16
```
For encoding purposes, `Reference.digest` is treated as a raw digest byte string, not as a generic encoded `u64 + bytes` OctetString.
### 4.2 Canonical layout: ReferenceBytes
The canonical binary layout for a `Reference` is:
```text
+----------------+---------------------------+
| hash_id (u16) | digest (b[?]) ...
+----------------+---------------------------+
```
Fields:
1.**hash_id (u16)**
* Encodes `Reference.hash_id`.
* Semantically, an element of the `HashId` space defined by ASL/1-CORE (and populated by HASH/ASL1 when present).
2.**digest**
* Raw digest bytes.
* The length of `digest` is **not encoded** explicitly in this profile.
* Digest length is determined by the decoding context:
* by the **frame boundary** of the `ReferenceBytes` value (e.g. “this message consists of exactly one `ReferenceBytes`”), or
* by an outer length-prefix in a higher-level enclosing structure.
> This layout is an explicit exception to the general `OctetString = u64 + bytes` rule. It keeps `ReferenceBytes` compact and relies on framing + the hash registry for length.
### 4.3 Encoding (normative)
Let `R` be a `Reference`. The canonical encoding function:
2. Treat **all remaining bytes in the slice** as the digest `digest`.
3. Construct `Reference{ hash_id, digest }`.
**Boundary requirement:**
Decoding contexts MUST provide explicit boundaries for `ReferenceBytes` values (e.g., via an external length-prefix or by framing the entire message as a single `ReferenceBytes` value). A decoder MUST NOT read beyond the slice that defines the `ReferenceBytes` frame.
**Cross-profile consistency with HASH/ASL1 (when present):**
If the implementation also implements `HASH/ASL1` and recognizes this `hash_id`, then:
* Let `expected_len = expected_digest_length(hash_id)` from the ASL1 registry.
* The implementation **MUST** enforce:
```text
len(digest) == expected_len
```
* Any mismatch MUST result in an encoding/integrity error.
If the implementation does **not** implement HASH/ASL1 or does not recognize the `hash_id`:
* It MAY accept the value as a structurally well-formed `Reference`.
* It MUST treat the algorithm as **unsupported** for digest recomputation or verification.
### 4.5 Injectivity
The mapping:
```text
Reference → ReferenceBytes
```
defined by `encode_reference_core_v1` is **injective**:
* Each `Reference` value has exactly one canonical byte string.
* Equality of `ReferenceBytes` implies equality of the underlying `Reference` (same `hash_id`, same digest bytes).
No additional normalization is performed.
---
## 5. Hash Interactions & Canonicality
### 5.1 Canonical hashing rule
For encoding profile `ASL_ENC_CORE_V1`, the canonical rule for constructing `Reference` values from `Artifact` values is:
* Uses the ASL/1-CORE domain separator (`"AMDUAT:ASL1:ART\0"`) plus `ArtifactBytes` from `encode_artifact_core_v1` as the **only** input to ASL1 hash functions when deriving `Reference`s under this profile.