From d7b456654b8e9c3c7f715544c4877fe3f967a128 Mon Sep 17 00:00:00 2001 From: Carl Niklas Rydberg Date: Sun, 21 Dec 2025 19:46:56 +0100 Subject: [PATCH] Fix TGK mem multi-encoding handling --- CMakeLists.txt | 5 +- src/adapters/tgk_store_mem/tgk_store_mem.c | 109 ++++++++++++++++----- tests/tgk/test_tgk_store_mem.c | 55 ++++++++++- 3 files changed, 141 insertions(+), 28 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 94b3162..4aa7c53 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -153,7 +153,7 @@ amduat_add_lib(tgk_store_mem SRCS ${AMDUAT_TGK_STORE_MEM_SRCS}) amduat_link(tgk_store_mem amduat_tgk amduat_asl amduat_enc amduat_hash_asl1 amduat_util) amduat_add_lib(tgk_store_fs SRCS ${AMDUAT_TGK_STORE_FS_SRCS}) -amduat_link(tgk_store_fs amduat_tgk amduat_asl_store_fs amduat_asl amduat_enc amduat_hash_asl1 amduat_util) +amduat_link(tgk_store_fs amduat_tgk_store_mem amduat_tgk amduat_asl_store_fs amduat_asl amduat_enc amduat_hash_asl1 amduat_util) add_executable(amduat_asl_cli src/tools/amduat_asl_cli.c) target_include_directories(amduat_asl_cli @@ -256,6 +256,9 @@ target_include_directories(amduat_test_tgk_store_fs PRIVATE ${AMDUAT_INTERNAL_DIR} PRIVATE ${AMDUAT_INCLUDE_DIR} ) +target_compile_definitions(amduat_test_tgk_store_fs + PRIVATE _POSIX_C_SOURCE=200809L +) target_link_libraries(amduat_test_tgk_store_fs PRIVATE amduat_tgk_store_fs ) diff --git a/src/adapters/tgk_store_mem/tgk_store_mem.c b/src/adapters/tgk_store_mem/tgk_store_mem.c index 54dcb23..898e465 100644 --- a/src/adapters/tgk_store_mem/tgk_store_mem.c +++ b/src/adapters/tgk_store_mem/tgk_store_mem.c @@ -53,20 +53,26 @@ static bool amduat_tgk_store_mem_edge_type_supported( return false; } -static bool amduat_tgk_store_mem_encoding_supported( - const amduat_tgk_store_mem_t *mem, +static bool amduat_tgk_store_mem_encoding_impl_supported( amduat_asl_encoding_profile_id_t profile_id) { - size_t i; - - if (mem == NULL) { - return false; - } - for (i = 0; i < mem->config.tgk_profiles.encodings_len; ++i) { - if (mem->config.tgk_profiles.encodings[i] == profile_id) { + switch (profile_id) { + case TGK1_EDGE_ENC_V1: return true; - } + default: + return false; + } +} + +static bool amduat_tgk_store_mem_decode_profile( + amduat_asl_encoding_profile_id_t profile_id, + amduat_octets_t bytes, + amduat_tgk_edge_body_t *out_body) { + switch (profile_id) { + case TGK1_EDGE_ENC_V1: + return amduat_enc_tgk1_edge_decode_v1(bytes, out_body); + default: + return false; } - return false; } static bool amduat_tgk_store_mem_type_filter_match( @@ -272,6 +278,11 @@ static amduat_tgk_graph_error_t amduat_tgk_store_mem_decode_edge( const amduat_tgk_store_mem_t *mem, const amduat_tgk_store_mem_artifact_t *entry, amduat_tgk_edge_body_t *out_body) { + size_t i; + bool saw_supported = false; + bool have_body = false; + amduat_tgk_edge_body_t resolved; + if (out_body != NULL) { memset(out_body, 0, sizeof(*out_body)); } @@ -283,24 +294,61 @@ static amduat_tgk_graph_error_t amduat_tgk_store_mem_decode_edge( mem, entry->artifact.type_tag.tag_id)) { return GS_ERR_NOT_EDGE; } - if (!amduat_tgk_store_mem_encoding_supported(mem, TGK1_EDGE_ENC_V1)) { - return GS_ERR_UNSUPPORTED; - } if (entry->artifact.bytes.len != 0 && entry->artifact.bytes.data == NULL) { - return GS_ERR_INTEGRITY; - } - if (!amduat_enc_tgk1_edge_decode_v1(entry->artifact.bytes, out_body)) { - return GS_ERR_INTEGRITY; - } - if (!amduat_tgk_edge_body_has_endpoints(out_body)) { - amduat_tgk_edge_body_free(out_body); - return GS_ERR_INTEGRITY; - } - if (!amduat_tgk_store_mem_edge_type_supported(mem, out_body->type)) { - amduat_tgk_edge_body_free(out_body); return GS_ERR_NOT_EDGE; } + if (mem->config.tgk_profiles.encodings_len != 0 && + mem->config.tgk_profiles.encodings == NULL) { + return GS_ERR_UNSUPPORTED; + } + + memset(&resolved, 0, sizeof(resolved)); + for (i = 0; i < mem->config.tgk_profiles.encodings_len; ++i) { + amduat_asl_encoding_profile_id_t profile_id = + mem->config.tgk_profiles.encodings[i]; + amduat_tgk_edge_body_t candidate; + + if (!amduat_tgk_store_mem_encoding_impl_supported(profile_id)) { + continue; + } + saw_supported = true; + + if (!amduat_tgk_store_mem_decode_profile(profile_id, + entry->artifact.bytes, + &candidate)) { + continue; + } + if (!amduat_tgk_edge_body_has_endpoints(&candidate)) { + amduat_tgk_edge_body_free(&candidate); + if (have_body) { + amduat_tgk_edge_body_free(&resolved); + } + return GS_ERR_INTEGRITY; + } + if (!amduat_tgk_store_mem_edge_type_supported(mem, candidate.type)) { + amduat_tgk_edge_body_free(&candidate); + continue; + } + if (!have_body) { + resolved = candidate; + have_body = true; + continue; + } + if (!amduat_tgk_edge_body_eq(&resolved, &candidate)) { + amduat_tgk_edge_body_free(&candidate); + amduat_tgk_edge_body_free(&resolved); + return GS_ERR_INTEGRITY; + } + amduat_tgk_edge_body_free(&candidate); + } + if (!saw_supported) { + return GS_ERR_UNSUPPORTED; + } + if (!have_body) { + return GS_ERR_NOT_EDGE; + } + *out_body = resolved; return 0; } @@ -609,6 +657,17 @@ bool amduat_tgk_store_mem_init(amduat_tgk_store_mem_t *mem, mem->edges = NULL; mem->edges_len = 0; + if (config.tgk_profiles.encodings_len != 0 && + config.tgk_profiles.encodings == NULL) { + 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])) { + return false; + } + } + if (artifacts_len == 0) { return true; } diff --git a/tests/tgk/test_tgk_store_mem.c b/tests/tgk/test_tgk_store_mem.c index ed02cf8..8e56555 100644 --- a/tests/tgk/test_tgk_store_mem.c +++ b/tests/tgk/test_tgk_store_mem.c @@ -14,13 +14,14 @@ static const uint8_t k_non_edge_bytes[] = {0xde, 0xad, 0xbe, 0xef}; typedef struct { amduat_tgk_store_t store; amduat_tgk_store_mem_t mem; - amduat_tgk_store_mem_artifact_t artifacts[5]; + amduat_tgk_store_mem_artifact_t artifacts[6]; amduat_octets_t edge_bytes[4]; amduat_reference_t ref_edge1; amduat_reference_t ref_edge2; amduat_reference_t ref_edge3; amduat_reference_t ref_edge_bad; amduat_reference_t ref_non_edge; + amduat_reference_t ref_invalid_tagged; amduat_reference_t ref_missing; amduat_reference_t node_a; amduat_reference_t node_b; @@ -34,6 +35,7 @@ typedef struct { uint8_t digest_edge3[32]; uint8_t digest_edge_bad[32]; uint8_t digest_non_edge[32]; + uint8_t digest_invalid_tagged[32]; uint8_t digest_missing[32]; uint8_t digest_node_a[32]; uint8_t digest_node_b[32]; @@ -59,6 +61,15 @@ static amduat_reference_t make_ref(uint8_t value, uint8_t *storage) { amduat_octets(storage, 32)); } +static void free_ref(amduat_reference_t *ref) { + if (ref == NULL) { + return; + } + free((void *)ref->digest.data); + ref->digest.data = NULL; + ref->digest.len = 0; +} + static void free_edge_bytes(test_env_t *env) { size_t i; @@ -107,6 +118,7 @@ static bool init_env(test_env_t *env) { env->ref_edge3 = make_ref(0x30, env->digest_edge3); env->ref_edge_bad = make_ref(0x40, env->digest_edge_bad); env->ref_non_edge = make_ref(0x50, env->digest_non_edge); + env->ref_invalid_tagged = make_ref(0x55, env->digest_invalid_tagged); env->ref_missing = make_ref(0x60, env->digest_missing); env->node_a = make_ref(0xa1, env->digest_node_a); @@ -185,8 +197,13 @@ static bool init_env(test_env_t *env) { env->artifacts[4].ref = env->ref_non_edge; env->artifacts[4].artifact = amduat_artifact(amduat_octets(k_non_edge_bytes, sizeof(k_non_edge_bytes))); + env->artifacts[5].ref = env->ref_invalid_tagged; + env->artifacts[5].artifact = + amduat_artifact_with_type(amduat_octets(k_non_edge_bytes, + sizeof(k_non_edge_bytes)), + amduat_type_tag(TYPE_TAG_TGK1_EDGE_V1)); - if (!amduat_tgk_store_mem_init(&env->mem, env->config, env->artifacts, 5)) { + if (!amduat_tgk_store_mem_init(&env->mem, env->config, env->artifacts, 6)) { free_edge_bytes(env); return false; } @@ -239,6 +256,19 @@ static int test_resolve_edge_not_edge(const test_env_t *env) { return 0; } +static int test_resolve_edge_invalid_bytes(const test_env_t *env) { + amduat_tgk_edge_body_t body; + amduat_tgk_graph_error_t err; + + err = amduat_tgk_store_resolve_edge((amduat_tgk_store_t *)&env->store, + env->ref_invalid_tagged, &body); + if (err != GS_ERR_NOT_EDGE) { + fprintf(stderr, "resolve_edge invalid bytes mismatch: %d\n", err); + return 1; + } + return 0; +} + static int test_resolve_edge_missing(const test_env_t *env) { amduat_tgk_edge_body_t body; amduat_tgk_graph_error_t err; @@ -274,6 +304,25 @@ static bool make_ref_for_hash(amduat_hash_id_t hash_id, return true; } +static int test_init_rejects_unsupported_encoding(void) { + amduat_tgk_store_mem_t mem; + amduat_tgk_store_config_t config; + amduat_asl_encoding_profile_id_t encodings[1]; + + memset(&mem, 0, sizeof(mem)); + memset(&config, 0, sizeof(config)); + encodings[0] = 0x9999u; + 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 unsupported encoding\n"); + amduat_tgk_store_mem_free(&mem); + return 1; + } + return 0; +} + static int test_resolve_edge_unsupported(const test_env_t *env) { amduat_reference_t ref; amduat_tgk_edge_body_t body; @@ -481,8 +530,10 @@ int main(void) { if (test_resolve_edge_ok(&env) != 0 || test_resolve_edge_not_edge(&env) != 0 || + test_resolve_edge_invalid_bytes(&env) != 0 || test_resolve_edge_missing(&env) != 0 || test_resolve_edge_unsupported(&env) != 0 || + test_init_rejects_unsupported_encoding() != 0 || test_type_filter(&env) != 0 || test_ordering(&env) != 0 || test_adjacency(&env) != 0 ||