tgk1-edge: accept unknown hash ids and add regression test

This commit is contained in:
Carl Niklas Rydberg 2025-12-22 11:42:41 +01:00
parent 5b7d07e033
commit 222fe2f84e
5 changed files with 268 additions and 9 deletions

View file

@ -38,8 +38,8 @@ Status legend: ✅ completed, ⬜ pending.
10. ✅ `tier1/enc-pel1-result-1.md`
11. ✅ `tier1/pel-trace-dag-1.md`
12. ✅ `tier1/enc-pel-trace-dag-1.md`
13. `tier1/tgk-1-core.md`
14. `tier1/enc-tgk1-edge-1.md`
13. `tier1/tgk-1-core.md`
14. `tier1/enc-tgk1-edge-1.md`
15. ⬜ `tier1/tgk-store-1.md`
16. ⬜ `tier1/tgk-prov-1.md`
17. ⬜ `tier1/opreg-pel1-kernel.md`
@ -185,3 +185,32 @@ Status legend: ✅ completed, ⬜ pending.
but permit unknown IDs and digest lengths, matching ENC/ASL1-CORE v1 behavior.
- Tests: command not provided — pass (user reported “100% tests passed, 0 tests
failed out of 14”).
## 2025-12-22 — TGK/1-CORE (`tier1/tgk-1-core.md`)
- Scope: TGK/1-CORE EdgeArtifact recognition, EdgeBody invariants, profile
configuration, and deterministic graph projection behavior in TGK stores.
- Findings: `amduat_tgk_store_mem_init` does not validate
`config.tgk_profiles.edge_tags`/`edge_tags_len` or
`config.tgk_profiles.edge_types`/`edge_types_len`, so null pointers with
non-zero lengths can lead to undefined behavior and prevent the required
`EDGE_TAG_SET`/edge-type catalogs from being well-defined; no consistency
checks ensure edge tags correspond to active edge encodings.
- Resolution: added validation for edge tag/type list pointers and duplicates;
enforced `TYPE_TAG_TGK1_EDGE_V1` presence when `TGK1_EDGE_ENC_V1` is active,
and rejection when the encoding is inactive.
- Tests: command not provided — pass (user reported “100% tests passed, 0 tests
failed out of 14”).
## 2025-12-22 — ENC/TGK1-EDGE/1 (`tier1/enc-tgk1-edge-1.md`)
- Scope: TGK1 EdgeBody encoding/decoding, EncodedRef framing, and profile
invariants for `TGK1_EDGE_ENC_V1`.
- Findings: `amduat_enc_tgk1_edge_encode_v1` rejects edges whose references use
unknown (non-registry) `hash_id` values because it requires a
registry-backed digest length when calculating `EncodedRef` sizes, which
contradicts `ENC/ASL1-CORE v1.x` and §2.4s requirement to accept unknown hash
IDs with only reserved-ID rejection and length checks when known.
- Resolution: updated `amduat_enc_tgk1_edge_encode_v1` sizing to allow unknown
hash IDs per `ENC/ASL1-CORE`; added regression test for unknown `hash_id`
edge references.
- Tests: command not provided — pass (user reported “100% tests passed, 0 tests
failed out of 14”).

View file

@ -98,6 +98,46 @@ static bool amduat_tgk_store_mem_encoding_impl_supported(
}
}
static bool amduat_tgk_store_mem_u32_list_has(const uint32_t *values,
size_t len,
uint32_t value) {
size_t i;
if (len == 0) {
return false;
}
if (values == NULL) {
return false;
}
for (i = 0; i < len; ++i) {
if (values[i] == value) {
return true;
}
}
return false;
}
static bool amduat_tgk_store_mem_u32_list_unique(const uint32_t *values,
size_t len) {
size_t i;
size_t j;
if (len == 0) {
return true;
}
if (values == NULL) {
return false;
}
for (i = 0; i < len; ++i) {
for (j = i + 1; j < len; ++j) {
if (values[i] == values[j]) {
return false;
}
}
}
return true;
}
static bool amduat_tgk_store_mem_decode_profile(
amduat_asl_encoding_profile_id_t profile_id,
amduat_octets_t bytes,
@ -1189,6 +1229,7 @@ bool amduat_tgk_store_mem_init(amduat_tgk_store_mem_t *mem,
size_t stored = 0;
amduat_tgk_graph_edge_view_t *edges = NULL;
size_t edges_len = 0;
bool has_tgk1_encoding = false;
if (mem == NULL) {
return false;
@ -1208,9 +1249,46 @@ bool amduat_tgk_store_mem_init(amduat_tgk_store_mem_t *mem,
config.tgk_profiles.encodings == NULL) {
return false;
}
if (config.tgk_profiles.edge_tags_len != 0 &&
config.tgk_profiles.edge_tags == NULL) {
return false;
}
if (config.tgk_profiles.edge_types_len != 0 &&
config.tgk_profiles.edge_types == NULL) {
return false;
}
if (!amduat_tgk_store_mem_u32_list_unique(
config.tgk_profiles.edge_tags,
config.tgk_profiles.edge_tags_len)) {
return false;
}
if (!amduat_tgk_store_mem_u32_list_unique(
config.tgk_profiles.edge_types,
config.tgk_profiles.edge_types_len)) {
return false;
}
for (i = 0; i < config.tgk_profiles.encodings_len; ++i) {
if (!amduat_tgk_store_mem_encoding_impl_supported(
config.tgk_profiles.encodings[i])) {
amduat_asl_encoding_profile_id_t profile_id =
config.tgk_profiles.encodings[i];
if (!amduat_tgk_store_mem_encoding_impl_supported(profile_id)) {
return false;
}
if (profile_id == TGK1_EDGE_ENC_V1) {
has_tgk1_encoding = true;
}
}
if (has_tgk1_encoding) {
if (!amduat_tgk_store_mem_u32_list_has(
config.tgk_profiles.edge_tags,
config.tgk_profiles.edge_tags_len,
TYPE_TAG_TGK1_EDGE_V1)) {
return false;
}
} else {
if (amduat_tgk_store_mem_u32_list_has(
config.tgk_profiles.edge_tags,
config.tgk_profiles.edge_tags_len,
TYPE_TAG_TGK1_EDGE_V1)) {
return false;
}
}

View file

@ -63,16 +63,17 @@ static bool amduat_reference_bytes_len(amduat_reference_t ref, size_t *out_len)
if (ref.digest.len != 0 && ref.digest.data == NULL) {
return false;
}
if (amduat_hash_asl1_is_reserved(ref.hash_id)) {
return false;
}
desc = amduat_hash_asl1_desc_lookup(ref.hash_id);
if (desc == NULL || desc->digest_len == 0) {
return false;
}
if (ref.digest.len != desc->digest_len) {
if (desc != NULL && desc->digest_len != 0 &&
ref.digest.len != desc->digest_len) {
return false;
}
*out_len = 2 + desc->digest_len;
*out_len = 2 + ref.digest.len;
return true;
}

View file

@ -35,11 +35,23 @@ static void fill_digest(uint8_t *out, uint8_t value) {
memset(out, value, 32);
}
static void fill_digest_len(uint8_t *out, size_t len, uint8_t value) {
memset(out, value, len);
}
static amduat_reference_t make_ref(uint8_t value, uint8_t *storage) {
fill_digest(storage, value);
return amduat_reference(0x0001, amduat_octets(storage, 32));
}
static amduat_reference_t make_ref_len(uint16_t hash_id,
uint8_t value,
uint8_t *storage,
size_t len) {
fill_digest_len(storage, len, value);
return amduat_reference(hash_id, amduat_octets(storage, len));
}
static bool bytes_equal(amduat_octets_t bytes,
const uint8_t *expected,
size_t expected_len) {
@ -132,6 +144,55 @@ static int test_invalid_edge_version(void) {
return 0;
}
static int test_unknown_hash_id_round_trip(void) {
amduat_tgk_edge_body_t edge;
amduat_reference_t from_refs[1];
amduat_octets_t encoded;
amduat_tgk_edge_body_t decoded;
uint8_t f0[5];
uint8_t p0[7];
int exit_code = 1;
memset(&edge, 0, sizeof(edge));
edge.type = 0x2b;
from_refs[0] = make_ref_len(0x1234, 0x44, f0, sizeof(f0));
edge.from = from_refs;
edge.from_len = 1;
edge.payload = make_ref_len(0x2345, 0x55, p0, sizeof(p0));
if (!amduat_enc_tgk1_edge_encode_v1(&edge, &encoded)) {
fprintf(stderr, "encode failed for unknown hash_id\n");
return exit_code;
}
if (!amduat_enc_tgk1_edge_decode_v1(encoded, &decoded)) {
fprintf(stderr, "decode failed for unknown hash_id\n");
goto cleanup;
}
if (decoded.type != edge.type || decoded.from_len != 1 ||
decoded.to_len != 0) {
fprintf(stderr, "decoded field mismatch for unknown hash_id\n");
goto cleanup_decoded;
}
if (!amduat_reference_eq(decoded.from[0], edge.from[0]) ||
!amduat_reference_eq(decoded.payload, edge.payload)) {
fprintf(stderr, "decoded refs mismatch for unknown hash_id\n");
goto cleanup_decoded;
}
exit_code = 0;
cleanup_decoded:
amduat_enc_tgk1_edge_free(&decoded);
cleanup:
free((void *)encoded.data);
return exit_code;
}
static int test_empty_endpoints(void) {
amduat_tgk_edge_body_t edge;
amduat_octets_t encoded;
@ -184,6 +245,9 @@ int main(void) {
if (test_invalid_edge_version() != 0) {
return 1;
}
if (test_unknown_hash_id_round_trip() != 0) {
return 1;
}
if (test_empty_endpoints() != 0) {
return 1;
}

View file

@ -346,6 +346,92 @@ static int test_init_rejects_duplicate_hash_id(void) {
return 0;
}
static int test_init_rejects_invalid_profile_config(void) {
amduat_tgk_store_mem_t mem;
amduat_tgk_store_config_t config;
amduat_asl_encoding_profile_id_t encodings[1];
uint32_t edge_tags[2];
amduat_tgk_edge_type_id_t edge_types[2];
encodings[0] = TGK1_EDGE_ENC_V1;
edge_tags[0] = TYPE_TAG_TGK1_EDGE_V1;
edge_tags[1] = TYPE_TAG_TGK1_EDGE_V1;
edge_types[0] = 0x10;
edge_types[1] = 0x10;
memset(&mem, 0, sizeof(mem));
memset(&config, 0, sizeof(config));
config.tgk_profiles.encodings = encodings;
config.tgk_profiles.encodings_len = 1;
config.tgk_profiles.edge_tags_len = 1;
config.tgk_profiles.edge_tags = NULL;
if (amduat_tgk_store_mem_init(&mem, config, NULL, 0)) {
fprintf(stderr, "init accepted null edge_tags\n");
amduat_tgk_store_mem_free(&mem);
return 1;
}
memset(&mem, 0, sizeof(mem));
memset(&config, 0, sizeof(config));
config.tgk_profiles.encodings = encodings;
config.tgk_profiles.encodings_len = 1;
config.tgk_profiles.edge_types_len = 1;
config.tgk_profiles.edge_types = NULL;
if (amduat_tgk_store_mem_init(&mem, config, NULL, 0)) {
fprintf(stderr, "init accepted null edge_types\n");
amduat_tgk_store_mem_free(&mem);
return 1;
}
memset(&mem, 0, sizeof(mem));
memset(&config, 0, sizeof(config));
config.tgk_profiles.encodings = encodings;
config.tgk_profiles.encodings_len = 1;
if (amduat_tgk_store_mem_init(&mem, config, NULL, 0)) {
fprintf(stderr, "init accepted encoding without edge tags\n");
amduat_tgk_store_mem_free(&mem);
return 1;
}
memset(&mem, 0, sizeof(mem));
memset(&config, 0, sizeof(config));
config.tgk_profiles.edge_tags = edge_tags;
config.tgk_profiles.edge_tags_len = 1;
if (amduat_tgk_store_mem_init(&mem, config, NULL, 0)) {
fprintf(stderr, "init accepted edge tag without encoding\n");
amduat_tgk_store_mem_free(&mem);
return 1;
}
memset(&mem, 0, sizeof(mem));
memset(&config, 0, sizeof(config));
config.tgk_profiles.edge_tags = edge_tags;
config.tgk_profiles.edge_tags_len = 2;
if (amduat_tgk_store_mem_init(&mem, config, NULL, 0)) {
fprintf(stderr, "init accepted duplicate edge tags\n");
amduat_tgk_store_mem_free(&mem);
return 1;
}
memset(&mem, 0, sizeof(mem));
memset(&config, 0, sizeof(config));
config.tgk_profiles.edge_types = edge_types;
config.tgk_profiles.edge_types_len = 2;
if (amduat_tgk_store_mem_init(&mem, config, NULL, 0)) {
fprintf(stderr, "init accepted duplicate edge types\n");
amduat_tgk_store_mem_free(&mem);
return 1;
}
return 0;
}
static int test_duplicate_edge_ref_same_artifact(void) {
amduat_tgk_store_mem_t mem;
amduat_tgk_store_t store;
@ -1348,6 +1434,7 @@ int main(void) {
test_resolve_edge_unsupported(&env) != 0 ||
test_init_rejects_unsupported_encoding() != 0 ||
test_init_rejects_duplicate_hash_id() != 0 ||
test_init_rejects_invalid_profile_config() != 0 ||
test_duplicate_edge_ref_same_artifact() != 0 ||
test_duplicate_edge_ref_conflict() != 0 ||
test_scan_edges_pagination() != 0 ||