Add HASH/ASL1 registry descriptors and stub hook

This commit is contained in:
Carl Niklas Rydberg 2025-12-19 20:55:07 +01:00
parent b47b914224
commit 32e3ca4ade
5 changed files with 273 additions and 1 deletions

View file

@ -10,15 +10,42 @@
extern "C" {
#endif
typedef struct {
bool (*digest)(void *ctx,
amduat_octets_t input,
uint8_t *out,
size_t out_len);
void *ctx;
} amduat_hash_asl1_impl_t;
typedef struct {
amduat_hash_id_t hash_id;
const char *name;
size_t digest_len;
void *impl;
amduat_hash_asl1_impl_t impl;
} amduat_hash_asl1_desc_t;
enum { AMDUAT_HASH_ASL1_ID_SHA256 = 0x0001 };
amduat_octets_t amduat_hash_asl1_key(amduat_hash_id_t hash_id, uint8_t out[2]);
const amduat_hash_asl1_desc_t *amduat_hash_asl1_desc_lookup(
amduat_hash_id_t hash_id);
const amduat_hash_asl1_desc_t *amduat_hash_asl1_descs(size_t *out_len);
bool amduat_hash_asl1_register_impl(amduat_hash_id_t hash_id,
amduat_hash_asl1_impl_t impl);
bool amduat_hash_asl1_digest(amduat_hash_id_t hash_id,
amduat_octets_t input,
uint8_t *out,
size_t out_len);
/* Optional: registers a non-conformant SHA-256 stub for wiring/tests.
* Define AMDUAT_HASH_ASL1_ENABLE_SHA256_STUB to enable. */
bool amduat_hash_asl1_register_sha256_stub(void);
#ifdef __cplusplus
} /* extern "C" */
#endif

89
registry/README.md Normal file
View file

@ -0,0 +1,89 @@
# Registry Model (draft)
This directory documents how Amduat registries are represented in the repo
before the full stack and code generation are available. The goal is to keep
registry entries stable and machine-readable so they can drive docs, code, and
graph mappings later without rewriting identifiers.
## Core idea
- **Registry keys are concepts.** The key itself (for example a `HashId`) has a
stable handle like `amduat.hash.asl1.id.0001@1`.
- **Registry values are data.** Each entry has a descriptor row that is data
(name, digest length, status, notes). Values are not treated as concepts.
This matches MS/1: concept handles are stable identifiers; the descriptor bytes
are data nodes that can be hashed and referenced.
## JSONL manifests
Each registry has a `registry/<name>.jsonl` manifest. Each line is one entry.
The manifest is the source of truth for codegen and documentation tables.
Common fields (registry-specific schemas may add fields):
- `registry`: registry name (e.g. `HASH/ASL1`).
- `hash_id` (or other key field): registry key as hex string.
- `handle`: concept handle for the key.
- `name`, `digest_len`, `status`, `spec_ref`, `notes`: descriptor fields.
- `descriptor_sha256`: digest of the canonical descriptor (see below).
## Handle naming scheme
Handles are opaque identifiers in the `amduat` namespace and do **not** depend
on DNS:
```
amduat.<domain>.<registry>.<kind>.<id>@<version>
```
Example (HASH/ASL1):
```
amduat.hash.asl1.id.0001@1
```
`id` is the canonical key (often lowercase hex, zero-padded). `version` is
incremented only when the meaning of that key changes (rare).
## Descriptor digest rule
`descriptor_sha256` is computed over a canonical JSON object with fields in a
fixed order. Each registry schema defines the exact ordering; for HASH/ASL1
see `registry/hash-asl1.schema.md`.
This digest can be used as a stable Data-node hash to anchor graphs, evidence,
or generated artifacts without requiring a full ASL encoder yet.
## Canonical key encoding
Each registry defines the byte encoding of its key. This is the encoding used
when building an ASL registry artifact:
- HASH/ASL1: `hash_id` is encoded as big-endian `u16` (see
`amduat_hash_asl1_key`).
## Mapping into ASL
When the stack is available:
1. Encode each descriptor row as an ASL Artifact (data bytes).
2. Store it to obtain a `Reference`.
3. Build a registry value where each entry maps:
```
key_bytes -> value_ref
```
This uses the generic registry container in `amduat/asl/registry`.
## Current manifests
- `registry/hash-asl1.jsonl` — ASL1 HashId assignments.
## Design constraints
- Handles MUST be stable and immutable once published.
- Reserved IDs are explicit rows with `status = reserved`.
- The manifest should be sufficient to regenerate code tables and docs without
additional context.

4
registry/hash-asl1.jsonl Normal file
View file

@ -0,0 +1,4 @@
{"registry":"HASH/ASL1","hash_id":"0x0000","handle":"amduat.hash.asl1.id.0000@1","name":null,"digest_len":null,"status":"reserved","spec_ref":"HASH/ASL1 v0.2.4","notes":"Reserved; never a valid algorithm.","descriptor_sha256":"aef821024f5ec2000b3920eaf6ea3a687690df87417a86b372359b064c7d1ac3"}
{"registry":"HASH/ASL1","hash_id":"0x0001","handle":"amduat.hash.asl1.id.0001@1","name":"HASH-ASL1-256","digest_len":32,"status":"mandatory","spec_ref":"HASH/ASL1 v0.2.4","notes":"Bit-for-bit SHA-256.","descriptor_sha256":"5082d8280750dc3cff48b48a7a2eda725a16f2902592f13eaf9b677908d7517e"}
{"registry":"HASH/ASL1","hash_id":"0x0002","handle":"amduat.hash.asl1.id.0002@1","name":"HASH-ASL1-512","digest_len":64,"status":"reserved","spec_ref":"HASH/ASL1 v0.2.4","notes":"Intended classical 512-bit algorithm.","descriptor_sha256":"2063bfe4878add4d2b6c575b95466d433f9c082df5284000ffde972f6a734f6d"}
{"registry":"HASH/ASL1","hash_id":"0x8001","handle":"amduat.hash.asl1.id.8001@1","name":"HASH-ASL1-PQ1","digest_len":null,"status":"reserved","spec_ref":"HASH/ASL1 v0.2.4","notes":"First PQ algorithm placeholder.","descriptor_sha256":"fca3b7afa0c3257cf0bbef7b8b338c76f0b7c3690e60c9a90ae4a1c0b99f25f0"}

View file

@ -0,0 +1,52 @@
# HASH/ASL1 Registry Manifest (draft)
This file documents the JSONL rows in `registry/hash-asl1.jsonl`. Each line is
one entry descriptor for a single `HashId` assignment. The key is the `HashId`
itself (a concept); the descriptor is data.
## Field definitions
- `registry`: string. Constant `"HASH/ASL1"`.
- `hash_id`: string. Hex `u16` formatted as `0x0000`.
- `handle`: string. Stable concept handle for this HashId assignment, e.g.
`amduat.hash.asl1.id.0001@1`.
- `name`: string or null. Algorithm name if assigned (e.g. `HASH-ASL1-256`).
- `digest_len`: integer or null. Digest length in bytes; null if unknown.
- `status`: string. One of: `mandatory`, `reserved`, `deprecated`, `experimental`.
- `spec_ref`: string. Document/version that defines the assignment.
- `notes`: string. Short human-readable note.
- `descriptor_sha256`: string. Lowercase hex SHA-256 digest of the canonical
descriptor (see below).
## Canonical registry key
`hash_id` is the registry key. Its key bytes are the big-endian `u16` encoding
defined in `ENC/ASL1-CORE` (see `amduat_hash_asl1_key`).
## Handle naming scheme
Handles are opaque identifiers in the `amduat` namespace:
```
amduat.hash.asl1.id.<hex4>@1
```
`hex4` is the 4-digit lowercase hex of the `HashId` (zero-padded).
## Descriptor digest rule
`descriptor_sha256` is computed as SHA-256 over the UTF-8 bytes of the
canonical JSON object with these fields **in order**:
```
registry, hash_id, handle, name, digest_len, status, spec_ref, notes
```
The canonical JSON uses no extra whitespace and does **not** include the
`descriptor_sha256` field itself.
## Intended use
- Source of truth for codegen (C tables, enums) and documentation tables.
- `descriptor_sha256` can be treated as the stable digest for mapping entries
into graph references or evidence tables.

View file

@ -1,7 +1,107 @@
#include "amduat/hash/asl1.h"
static amduat_hash_asl1_desc_t g_hash_asl1_descs[] = {
{0x0000, NULL, 0, {NULL, NULL}},
{AMDUAT_HASH_ASL1_ID_SHA256, "HASH-ASL1-256", 32, {NULL, NULL}},
{0x0002, "HASH-ASL1-512", 64, {NULL, NULL}},
{0x8001, "HASH-ASL1-PQ1", 0, {NULL, NULL}}};
#ifdef AMDUAT_HASH_ASL1_ENABLE_SHA256_STUB
static bool amduat_hash_asl1_sha256_stub(void *ctx,
amduat_octets_t input,
uint8_t *out,
size_t out_len) {
size_t i;
(void)ctx;
(void)input;
if (out == NULL || out_len < 32) {
return false;
}
for (i = 0; i < 32; ++i) {
out[i] = 0;
}
return true;
}
#endif
amduat_octets_t amduat_hash_asl1_key(amduat_hash_id_t hash_id, uint8_t out[2]) {
out[0] = (uint8_t)(hash_id >> 8);
out[1] = (uint8_t)(hash_id & 0xff);
return amduat_octets(out, 2);
}
const amduat_hash_asl1_desc_t *amduat_hash_asl1_desc_lookup(
amduat_hash_id_t hash_id) {
size_t i;
for (i = 0; i < sizeof(g_hash_asl1_descs) / sizeof(g_hash_asl1_descs[0]);
++i) {
if (g_hash_asl1_descs[i].hash_id == hash_id) {
return &g_hash_asl1_descs[i];
}
}
return NULL;
}
const amduat_hash_asl1_desc_t *amduat_hash_asl1_descs(size_t *out_len) {
if (out_len != NULL) {
*out_len = sizeof(g_hash_asl1_descs) / sizeof(g_hash_asl1_descs[0]);
}
return g_hash_asl1_descs;
}
bool amduat_hash_asl1_register_impl(amduat_hash_id_t hash_id,
amduat_hash_asl1_impl_t impl) {
size_t i;
for (i = 0; i < sizeof(g_hash_asl1_descs) / sizeof(g_hash_asl1_descs[0]);
++i) {
if (g_hash_asl1_descs[i].hash_id == hash_id) {
g_hash_asl1_descs[i].impl = impl;
return true;
}
}
return false;
}
bool amduat_hash_asl1_digest(amduat_hash_id_t hash_id,
amduat_octets_t input,
uint8_t *out,
size_t out_len) {
const amduat_hash_asl1_desc_t *desc;
if (out == NULL) {
return false;
}
desc = amduat_hash_asl1_desc_lookup(hash_id);
if (desc == NULL || desc->digest_len == 0) {
return false;
}
if (out_len < desc->digest_len) {
return false;
}
if (desc->impl.digest == NULL) {
return false;
}
return desc->impl.digest(desc->impl.ctx, input, out, desc->digest_len);
}
bool amduat_hash_asl1_register_sha256_stub(void) {
#ifdef AMDUAT_HASH_ASL1_ENABLE_SHA256_STUB
amduat_hash_asl1_impl_t impl;
impl.digest = amduat_hash_asl1_sha256_stub;
impl.ctx = NULL;
return amduat_hash_asl1_register_impl(AMDUAT_HASH_ASL1_ID_SHA256, impl);
#else
return false;
#endif
}