Fix trace DAG EncodedRef validation and test unknown hash ids

This commit is contained in:
Carl Niklas Rydberg 2025-12-22 11:24:43 +01:00
parent a4932b1217
commit 5b7d07e033
3 changed files with 109 additions and 9 deletions

View file

@ -37,7 +37,7 @@ Status legend: ✅ completed, ⬜ pending.
9. ✅ `tier1/enc-pel-program-dag-1.md` 9. ✅ `tier1/enc-pel-program-dag-1.md`
10. ✅ `tier1/enc-pel1-result-1.md` 10. ✅ `tier1/enc-pel1-result-1.md`
11. ✅ `tier1/pel-trace-dag-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` 13. ⬜ `tier1/tgk-1-core.md`
14. ⬜ `tier1/enc-tgk1-edge-1.md` 14. ⬜ `tier1/enc-tgk1-edge-1.md`
15. ⬜ `tier1/tgk-store-1.md` 15. ⬜ `tier1/tgk-store-1.md`
@ -173,3 +173,15 @@ Status legend: ✅ completed, ⬜ pending.
for failed nodes. for failed nodes.
- Tests: command not provided — pass (user reported “100% tests passed, 0 tests - Tests: command not provided — pass (user reported “100% tests passed, 0 tests
failed out of 14”). 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-COREs 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”).

View file

@ -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) { static bool amduat_reference_bytes_len(amduat_reference_t ref, size_t *out_len) {
const amduat_hash_asl1_desc_t *desc; const amduat_hash_asl1_desc_t *desc;
size_t digest_len;
if (ref.digest.len != 0 && ref.digest.data == NULL) { if (ref.digest.len != 0 && ref.digest.data == NULL) {
return false; return false;
} }
desc = amduat_hash_asl1_desc_lookup(ref.hash_id); if (amduat_hash_asl1_is_reserved(ref.hash_id)) {
if (desc == NULL || desc->digest_len == 0) {
return false;
}
if (ref.digest.len != desc->digest_len) {
return false; 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; return true;
} }

View file

@ -50,6 +50,14 @@ static amduat_reference_t make_ref(uint8_t value, uint8_t *storage) {
return amduat_reference(0x0001, amduat_octets(storage, 32)); 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, static bool bytes_equal(amduat_octets_t bytes,
const uint8_t *expected, const uint8_t *expected,
size_t expected_len) { size_t expected_len) {
@ -150,6 +158,80 @@ cleanup:
return exit_code; return exit_code;
} }
int main(void) { static int test_trace_unknown_hash_id(void) {
return test_trace_encoding(); 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();
} }