From 5b7d07e033f81a4131aeb096ab20dc6fa332e4bf Mon Sep 17 00:00:00 2001 From: Carl Niklas Rydberg Date: Mon, 22 Dec 2025 11:24:43 +0100 Subject: [PATCH] Fix trace DAG EncodedRef validation and test unknown hash ids --- AUDITS.md | 14 ++++- src/near_core/enc/pel_trace_dag.c | 18 ++++--- tests/enc/test_pel_trace_dag.c | 86 ++++++++++++++++++++++++++++++- 3 files changed, 109 insertions(+), 9 deletions(-) diff --git a/AUDITS.md b/AUDITS.md index 0d6533f..83c41a6 100644 --- a/AUDITS.md +++ b/AUDITS.md @@ -37,7 +37,7 @@ Status legend: ✅ completed, ⬜ pending. 9. ✅ `tier1/enc-pel-program-dag-1.md` 10. ✅ `tier1/enc-pel1-result-1.md` 11. ✅ `tier1/pel-trace-dag-1.md` -12. ⬜ `tier1/enc-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` 15. ⬜ `tier1/tgk-store-1.md` @@ -173,3 +173,15 @@ Status legend: ✅ completed, ⬜ pending. for failed nodes. - Tests: command not provided — pass (user reported “100% tests passed, 0 tests failed out of 14”). + +## 2025-12-22 — ENC/PEL-TRACE-DAG/1 (`tier1/enc-pel-trace-dag-1.md`) +- Scope: canonical TraceDAGBytes encoding, EncodedRef framing, and validation + rules for trace payloads. +- Findings: EncodedRef encoding rejected unknown `hash_id` values by requiring a + registry-backed digest length, contradicting ENC/ASL1-CORE’s ReferenceBytes + rules (which allow unknown hash IDs and variable digest lengths as long as + they are not reserved). +- Resolution: relaxed EncodedRef length validation to reject reserved hash IDs + 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”). diff --git a/src/near_core/enc/pel_trace_dag.c b/src/near_core/enc/pel_trace_dag.c index 92eab7a..2402c62 100644 --- a/src/near_core/enc/pel_trace_dag.c +++ b/src/near_core/enc/pel_trace_dag.c @@ -134,20 +134,26 @@ static bool amduat_utf8_is_valid(amduat_octets_t value) { static bool amduat_reference_bytes_len(amduat_reference_t ref, size_t *out_len) { const amduat_hash_asl1_desc_t *desc; + size_t digest_len; if (ref.digest.len != 0 && ref.digest.data == NULL) { 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 (amduat_hash_asl1_is_reserved(ref.hash_id)) { return false; } - *out_len = 2 + desc->digest_len; + desc = amduat_hash_asl1_desc_lookup(ref.hash_id); + digest_len = ref.digest.len; + if (desc != NULL && desc->digest_len != 0 && digest_len != desc->digest_len) { + return false; + } + + if (digest_len > SIZE_MAX - 2) { + return false; + } + *out_len = 2 + digest_len; return true; } diff --git a/tests/enc/test_pel_trace_dag.c b/tests/enc/test_pel_trace_dag.c index 61aee1e..5351eec 100644 --- a/tests/enc/test_pel_trace_dag.c +++ b/tests/enc/test_pel_trace_dag.c @@ -50,6 +50,14 @@ static amduat_reference_t make_ref(uint8_t value, uint8_t *storage) { return amduat_reference(0x0001, amduat_octets(storage, 32)); } +static amduat_reference_t make_ref_custom(amduat_hash_id_t hash_id, + uint8_t *storage, + size_t len, + uint8_t value) { + memset(storage, value, len); + 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) { @@ -150,6 +158,80 @@ cleanup: return exit_code; } -int main(void) { - return test_trace_encoding(); +static int test_trace_unknown_hash_id(void) { + amduat_pel_trace_dag_value_t trace; + amduat_pel_node_trace_dag_t node; + amduat_reference_t input_refs[1]; + amduat_octets_t encoded; + amduat_pel_trace_dag_value_t decoded; + uint8_t s[32], p[32], r[32], i0[5]; + const char op_name[] = "noop"; + int exit_code = 1; + + memset(&trace, 0, sizeof(trace)); + memset(&node, 0, sizeof(node)); + + trace.pel1_version = 1; + trace.scheme_ref = make_ref(0x01, s); + trace.program_ref = make_ref(0x02, p); + trace.status = AMDUAT_PEL_EXEC_STATUS_OK; + trace.summary.kind = AMDUAT_PEL_EXEC_ERROR_NONE; + trace.summary.status_code = 0; + trace.has_exec_result_ref = true; + trace.exec_result_ref = make_ref(0x03, r); + + input_refs[0] = make_ref_custom(0x1234, i0, sizeof(i0), 0x5a); + trace.input_refs = input_refs; + trace.input_refs_len = 1; + trace.has_params_ref = false; + + node.node_id = 0; + node.op_name = amduat_octets(op_name, strlen(op_name)); + node.op_version = 1; + node.status = AMDUAT_PEL_NODE_TRACE_OK; + node.status_code = 0; + node.output_refs = NULL; + node.output_refs_len = 0; + node.diagnostics = NULL; + node.diagnostics_len = 0; + + trace.node_traces = &node; + trace.node_traces_len = 1; + + if (!amduat_enc_pel_trace_dag_encode_v1(&trace, &encoded)) { + fprintf(stderr, "encode failed (unknown hash)\n"); + return exit_code; + } + + if (!amduat_enc_pel_trace_dag_decode_v1(encoded, &decoded)) { + fprintf(stderr, "decode failed (unknown hash)\n"); + goto cleanup; + } + + if (decoded.input_refs_len != 1) { + fprintf(stderr, "decoded input count mismatch\n"); + goto cleanup_decoded; + } + + if (decoded.input_refs[0].hash_id != 0x1234 || + decoded.input_refs[0].digest.len != sizeof(i0) || + memcmp(decoded.input_refs[0].digest.data, i0, sizeof(i0)) != 0) { + fprintf(stderr, "decoded unknown hash mismatch\n"); + goto cleanup_decoded; + } + + exit_code = 0; + +cleanup_decoded: + amduat_enc_pel_trace_dag_free(&decoded); +cleanup: + free((void *)encoded.data); + return exit_code; +} + +int main(void) { + if (test_trace_encoding() != 0) { + return 1; + } + return test_trace_unknown_hash_id(); }