From f5e1ab8801fb06c6199445c1aeb16b7bab4ab484 Mon Sep 17 00:00:00 2001 From: Carl Niklas Rydberg Date: Mon, 22 Dec 2025 08:16:58 +0100 Subject: [PATCH] Add PEL DAG scheme descriptor codec and validation If you want a longer one: Add codec + tests for PEL DAG scheme descriptor --- CMakeLists.txt | 12 + include/amduat/enc/pel_program_dag_desc.h | 40 ++ include/amduat/pel/decode.h | 5 + src/near_core/enc/pel_program_dag_desc.c | 440 ++++++++++++++++++++++ src/pel_stack/decode.c | 15 + src/tools/amduat_pel_cli.c | 43 ++- tests/pel/test_pel_program_dag_desc.c | 92 +++++ 7 files changed, 636 insertions(+), 11 deletions(-) create mode 100644 include/amduat/enc/pel_program_dag_desc.h create mode 100644 src/near_core/enc/pel_program_dag_desc.c create mode 100644 tests/pel/test_pel_program_dag_desc.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 661f7d9..f74b5a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -80,6 +80,7 @@ set(AMDUAT_ENC_SRCS src/near_core/enc/asl1_core_codec.c src/near_core/asl/ref_derive.c src/near_core/enc/pel_program_dag.c + src/near_core/enc/pel_program_dag_desc.c src/near_core/enc/pel_trace_dag.c src/near_core/enc/pel1_result.c src/near_core/enc/tgk1_edge.c @@ -296,6 +297,17 @@ target_link_libraries(amduat_test_pel_program_dag_exec ) add_test(NAME pel_program_dag_exec COMMAND amduat_test_pel_program_dag_exec) +add_executable(amduat_test_pel_program_dag_desc + tests/pel/test_pel_program_dag_desc.c) +target_include_directories(amduat_test_pel_program_dag_desc + PRIVATE ${AMDUAT_INTERNAL_DIR} + PRIVATE ${AMDUAT_INCLUDE_DIR} +) +target_link_libraries(amduat_test_pel_program_dag_desc + PRIVATE amduat_enc +) +add_test(NAME pel_program_dag_desc COMMAND amduat_test_pel_program_dag_desc) + add_executable(amduat_test_pel_surf_run tests/pel/test_pel_surf_run.c) target_include_directories(amduat_test_pel_surf_run PRIVATE ${AMDUAT_INTERNAL_DIR} diff --git a/include/amduat/enc/pel_program_dag_desc.h b/include/amduat/enc/pel_program_dag_desc.h new file mode 100644 index 0000000..1b26455 --- /dev/null +++ b/include/amduat/enc/pel_program_dag_desc.h @@ -0,0 +1,40 @@ +#ifndef AMDUAT_ENC_PEL_PROGRAM_DAG_DESC_H +#define AMDUAT_ENC_PEL_PROGRAM_DAG_DESC_H + +#include "amduat/asl/core.h" + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + uint16_t pel1_version; + amduat_octets_t scheme_name; + amduat_type_tag_t program_type_tag; + uint16_t program_enc_profile; + bool has_trace_profile_ref; + amduat_reference_t trace_profile_ref; + bool has_opreg_ref; + amduat_reference_t opreg_ref; +} amduat_pel_dag_scheme_descriptor_t; + +/* Caller owns any heap allocations returned in out_bytes/out_desc. */ +bool amduat_enc_pel_program_dag_desc_encode_v1( + const amduat_pel_dag_scheme_descriptor_t *desc, + amduat_octets_t *out_bytes); + +bool amduat_enc_pel_program_dag_desc_decode_v1( + amduat_octets_t bytes, + amduat_pel_dag_scheme_descriptor_t *out_desc); + +void amduat_enc_pel_program_dag_desc_free( + amduat_pel_dag_scheme_descriptor_t *desc); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* AMDUAT_ENC_PEL_PROGRAM_DAG_DESC_H */ diff --git a/include/amduat/pel/decode.h b/include/amduat/pel/decode.h index 003ab29..95b1b47 100644 --- a/include/amduat/pel/decode.h +++ b/include/amduat/pel/decode.h @@ -3,6 +3,7 @@ #include "amduat/asl/core.h" #include "amduat/pel/program_dag.h" +#include "amduat/enc/pel_program_dag_desc.h" #include "amduat/pel/surf.h" #include "amduat/pel/trace_dag.h" @@ -15,6 +16,10 @@ extern "C" { bool amduat_pel_program_decode_artifact(const amduat_artifact_t *artifact, amduat_pel_program_t *out_program); +bool amduat_pel_program_dag_desc_decode_artifact( + const amduat_artifact_t *artifact, + amduat_pel_dag_scheme_descriptor_t *out_desc); + bool amduat_pel_trace_decode_artifact(const amduat_artifact_t *artifact, amduat_pel_trace_dag_value_t *out_trace); diff --git a/src/near_core/enc/pel_program_dag_desc.c b/src/near_core/enc/pel_program_dag_desc.c new file mode 100644 index 0000000..c0c3242 --- /dev/null +++ b/src/near_core/enc/pel_program_dag_desc.c @@ -0,0 +1,440 @@ +#include "amduat/enc/pel_program_dag_desc.h" + +#include "amduat/enc/asl1_core_codec.h" +#include "amduat/hash/asl1.h" + +#include +#include +#include +#include + +typedef struct { + const uint8_t *data; + size_t len; + size_t offset; +} amduat_cursor_t; + +static void amduat_store_u16_be(uint8_t *out, uint16_t value) { + out[0] = (uint8_t)((value >> 8) & 0xffu); + out[1] = (uint8_t)(value & 0xffu); +} + +static void amduat_store_u32_be(uint8_t *out, uint32_t value) { + out[0] = (uint8_t)((value >> 24) & 0xffu); + out[1] = (uint8_t)((value >> 16) & 0xffu); + out[2] = (uint8_t)((value >> 8) & 0xffu); + out[3] = (uint8_t)(value & 0xffu); +} + +static bool amduat_read_u8(amduat_cursor_t *cur, uint8_t *out) { + if (cur->len - cur->offset < 1) { + return false; + } + *out = cur->data[cur->offset]; + cur->offset += 1; + return true; +} + +static bool amduat_read_u16(amduat_cursor_t *cur, uint16_t *out) { + const uint8_t *data; + if (cur->len - cur->offset < 2) { + return false; + } + data = cur->data + cur->offset; + *out = (uint16_t)((data[0] << 8) | data[1]); + cur->offset += 2; + return true; +} + +static bool amduat_read_u32(amduat_cursor_t *cur, uint32_t *out) { + const uint8_t *data; + if (cur->len - cur->offset < 4) { + return false; + } + data = cur->data + cur->offset; + *out = ((uint32_t)data[0] << 24) | ((uint32_t)data[1] << 16) | + ((uint32_t)data[2] << 8) | (uint32_t)data[3]; + cur->offset += 4; + return true; +} + +static bool amduat_add_size(size_t *acc, size_t add) { + if (*acc > SIZE_MAX - add) { + return false; + } + *acc += add; + return true; +} + +static bool amduat_utf8_is_valid(amduat_octets_t value) { + size_t i = 0; + + while (i < value.len) { + uint8_t c = value.data[i]; + if (c <= 0x7f) { + i += 1; + continue; + } + if ((c & 0xe0u) == 0xc0u) { + if (i + 1 >= value.len) { + return false; + } + if ((value.data[i + 1] & 0xc0u) != 0x80u) { + return false; + } + if (c < 0xc2u) { + return false; + } + i += 2; + continue; + } + if ((c & 0xf0u) == 0xe0u) { + if (i + 2 >= value.len) { + return false; + } + if ((value.data[i + 1] & 0xc0u) != 0x80u || + (value.data[i + 2] & 0xc0u) != 0x80u) { + return false; + } + if (c == 0xe0u && value.data[i + 1] < 0xa0u) { + return false; + } + if (c == 0xedu && value.data[i + 1] >= 0xa0u) { + return false; + } + i += 3; + continue; + } + if ((c & 0xf8u) == 0xf0u) { + if (i + 3 >= value.len) { + return false; + } + if ((value.data[i + 1] & 0xc0u) != 0x80u || + (value.data[i + 2] & 0xc0u) != 0x80u || + (value.data[i + 3] & 0xc0u) != 0x80u) { + return false; + } + if (c == 0xf0u && value.data[i + 1] < 0x90u) { + return false; + } + if (c == 0xf4u && value.data[i + 1] >= 0x90u) { + return false; + } + if (c > 0xf4u) { + return false; + } + i += 4; + continue; + } + return false; + } + + return true; +} + +static bool amduat_reference_bytes_len(amduat_reference_t ref, size_t *out_len) { + const amduat_hash_asl1_desc_t *desc; + + 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) { + return false; + } + + *out_len = 2 + desc->digest_len; + return true; +} + +static bool amduat_encoded_ref_len(amduat_reference_t ref, size_t *out_len) { + size_t ref_len; + + if (!amduat_reference_bytes_len(ref, &ref_len)) { + return false; + } + if (ref_len > UINT32_MAX) { + return false; + } + *out_len = 4 + ref_len; + return true; +} + +static bool amduat_write_encoded_ref(uint8_t *buffer, + size_t buffer_len, + size_t *offset, + amduat_reference_t ref) { + size_t ref_len; + + if (!amduat_reference_bytes_len(ref, &ref_len)) { + return false; + } + if (ref_len > UINT32_MAX) { + return false; + } + if (buffer_len - *offset < 4 + ref_len) { + return false; + } + + amduat_store_u32_be(buffer + *offset, (uint32_t)ref_len); + *offset += 4; + amduat_store_u16_be(buffer + *offset, ref.hash_id); + *offset += 2; + if (ref.digest.len != 0) { + memcpy(buffer + *offset, ref.digest.data, ref.digest.len); + *offset += ref.digest.len; + } + + return true; +} + +static bool amduat_read_encoded_ref(amduat_cursor_t *cur, + amduat_reference_t *out_ref) { + uint32_t ref_len_u32; + amduat_octets_t ref_bytes; + + if (!amduat_read_u32(cur, &ref_len_u32)) { + return false; + } + if (ref_len_u32 < 2) { + return false; + } + if (cur->len - cur->offset < ref_len_u32) { + return false; + } + ref_bytes = amduat_octets(cur->data + cur->offset, ref_len_u32); + if (!amduat_enc_asl1_core_decode_reference_v1(ref_bytes, out_ref)) { + return false; + } + cur->offset += ref_len_u32; + return true; +} + +void amduat_enc_pel_program_dag_desc_free( + amduat_pel_dag_scheme_descriptor_t *desc) { + if (desc == NULL) { + return; + } + + amduat_octets_free(&desc->scheme_name); + if (desc->has_trace_profile_ref) { + amduat_reference_free(&desc->trace_profile_ref); + } + if (desc->has_opreg_ref) { + amduat_reference_free(&desc->opreg_ref); + } + desc->has_trace_profile_ref = false; + desc->has_opreg_ref = false; +} + +bool amduat_enc_pel_program_dag_desc_encode_v1( + const amduat_pel_dag_scheme_descriptor_t *desc, + amduat_octets_t *out_bytes) { + size_t total_len = 0; + size_t offset = 0; + uint8_t *buffer; + + if (desc == NULL || out_bytes == NULL) { + return false; + } + + out_bytes->data = NULL; + out_bytes->len = 0; + + if (desc->pel1_version != 1) { + return false; + } + if (desc->scheme_name.len != 0 && desc->scheme_name.data == NULL) { + return false; + } + if (desc->scheme_name.len > UINT32_MAX) { + return false; + } + if (!amduat_utf8_is_valid(desc->scheme_name)) { + return false; + } + + if (!amduat_add_size(&total_len, 2 + 4 + desc->scheme_name.len + 4 + 2)) { + return false; + } + if (!amduat_add_size(&total_len, 1)) { + return false; + } + if (desc->has_trace_profile_ref) { + size_t enc_len; + if (!amduat_encoded_ref_len(desc->trace_profile_ref, &enc_len) || + !amduat_add_size(&total_len, enc_len)) { + return false; + } + } + if (!amduat_add_size(&total_len, 1)) { + return false; + } + if (desc->has_opreg_ref) { + size_t enc_len; + if (!amduat_encoded_ref_len(desc->opreg_ref, &enc_len) || + !amduat_add_size(&total_len, enc_len)) { + return false; + } + } + + buffer = (uint8_t *)malloc(total_len); + if (buffer == NULL) { + return false; + } + + amduat_store_u16_be(buffer + offset, desc->pel1_version); + offset += 2; + amduat_store_u32_be(buffer + offset, (uint32_t)desc->scheme_name.len); + offset += 4; + if (desc->scheme_name.len != 0) { + memcpy(buffer + offset, desc->scheme_name.data, desc->scheme_name.len); + offset += desc->scheme_name.len; + } + amduat_store_u32_be(buffer + offset, desc->program_type_tag.tag_id); + offset += 4; + amduat_store_u16_be(buffer + offset, desc->program_enc_profile); + offset += 2; + + buffer[offset] = desc->has_trace_profile_ref ? 0x01u : 0x00u; + offset += 1; + if (desc->has_trace_profile_ref) { + if (!amduat_write_encoded_ref(buffer, total_len, &offset, + desc->trace_profile_ref)) { + free(buffer); + return false; + } + } + + buffer[offset] = desc->has_opreg_ref ? 0x01u : 0x00u; + offset += 1; + if (desc->has_opreg_ref) { + if (!amduat_write_encoded_ref(buffer, total_len, &offset, + desc->opreg_ref)) { + free(buffer); + return false; + } + } + + out_bytes->data = buffer; + out_bytes->len = total_len; + return true; +} + +bool amduat_enc_pel_program_dag_desc_decode_v1( + amduat_octets_t bytes, + amduat_pel_dag_scheme_descriptor_t *out_desc) { + amduat_cursor_t cur; + uint16_t pel1_version; + uint32_t scheme_name_len; + uint32_t program_type_tag_id; + uint16_t program_enc_profile; + uint8_t has_trace_profile; + uint8_t has_opreg_ref; + uint8_t *scheme_name_copy = NULL; + + if (out_desc == NULL) { + return false; + } + if (bytes.len != 0 && bytes.data == NULL) { + return false; + } + + memset(out_desc, 0, sizeof(*out_desc)); + + cur.data = bytes.data; + cur.len = bytes.len; + cur.offset = 0; + + if (!amduat_read_u16(&cur, &pel1_version)) { + return false; + } + if (pel1_version != 1) { + return false; + } + + if (!amduat_read_u32(&cur, &scheme_name_len)) { + return false; + } + if (cur.len - cur.offset < scheme_name_len) { + return false; + } + if (scheme_name_len != 0) { + scheme_name_copy = (uint8_t *)malloc(scheme_name_len); + if (scheme_name_copy == NULL) { + return false; + } + memcpy(scheme_name_copy, cur.data + cur.offset, scheme_name_len); + } + cur.offset += scheme_name_len; + if (!amduat_utf8_is_valid( + amduat_octets(scheme_name_copy, scheme_name_len))) { + free(scheme_name_copy); + return false; + } + + if (!amduat_read_u32(&cur, &program_type_tag_id)) { + free(scheme_name_copy); + return false; + } + if (!amduat_read_u16(&cur, &program_enc_profile)) { + free(scheme_name_copy); + return false; + } + + if (!amduat_read_u8(&cur, &has_trace_profile)) { + free(scheme_name_copy); + return false; + } + if (has_trace_profile != 0x00u && has_trace_profile != 0x01u) { + free(scheme_name_copy); + return false; + } + if (has_trace_profile == 0x01u) { + if (!amduat_read_encoded_ref(&cur, &out_desc->trace_profile_ref)) { + free(scheme_name_copy); + return false; + } + out_desc->has_trace_profile_ref = true; + } + + if (!amduat_read_u8(&cur, &has_opreg_ref)) { + amduat_reference_free(&out_desc->trace_profile_ref); + free(scheme_name_copy); + return false; + } + if (has_opreg_ref != 0x00u && has_opreg_ref != 0x01u) { + if (out_desc->has_trace_profile_ref) { + amduat_reference_free(&out_desc->trace_profile_ref); + } + free(scheme_name_copy); + return false; + } + if (has_opreg_ref == 0x01u) { + if (!amduat_read_encoded_ref(&cur, &out_desc->opreg_ref)) { + if (out_desc->has_trace_profile_ref) { + amduat_reference_free(&out_desc->trace_profile_ref); + } + free(scheme_name_copy); + return false; + } + out_desc->has_opreg_ref = true; + } + + if (cur.offset != cur.len) { + amduat_enc_pel_program_dag_desc_free(out_desc); + free(scheme_name_copy); + return false; + } + + out_desc->pel1_version = pel1_version; + out_desc->scheme_name = amduat_octets(scheme_name_copy, scheme_name_len); + out_desc->program_type_tag = amduat_type_tag(program_type_tag_id); + out_desc->program_enc_profile = program_enc_profile; + + return true; +} diff --git a/src/pel_stack/decode.c b/src/pel_stack/decode.c index 567dc3c..d7b05f5 100644 --- a/src/pel_stack/decode.c +++ b/src/pel_stack/decode.c @@ -2,6 +2,7 @@ #include "amduat/enc/pel1_result.h" #include "amduat/enc/pel_program_dag.h" +#include "amduat/enc/pel_program_dag_desc.h" #include "amduat/enc/pel_trace_dag.h" #include "amduat/pel/program_dag_desc.h" @@ -20,6 +21,20 @@ bool amduat_pel_program_decode_artifact(const amduat_artifact_t *artifact, return amduat_enc_pel_program_dag_decode_v1(artifact->bytes, out_program); } +bool amduat_pel_program_dag_desc_decode_artifact( + const amduat_artifact_t *artifact, + amduat_pel_dag_scheme_descriptor_t *out_desc) { + if (artifact == NULL || out_desc == NULL) { + return false; + } + if (artifact->has_type_tag && + artifact->type_tag.tag_id != AMDUAT_PEL_TYPE_TAG_SCHEME_DESC_1) { + return false; + } + memset(out_desc, 0, sizeof(*out_desc)); + return amduat_enc_pel_program_dag_desc_decode_v1(artifact->bytes, out_desc); +} + bool amduat_pel_trace_decode_artifact(const amduat_artifact_t *artifact, amduat_pel_trace_dag_value_t *out_trace) { if (artifact == NULL || out_trace == NULL) { diff --git a/src/tools/amduat_pel_cli.c b/src/tools/amduat_pel_cli.c index b0e0129..0f50517 100644 --- a/src/tools/amduat_pel_cli.c +++ b/src/tools/amduat_pel_cli.c @@ -60,7 +60,7 @@ static void amduat_pel_cli_print_usage(FILE *stream) { "commands:\n" " run Execute a PEL/PROGRAM-DAG/1 program via PEL/1-SURF (store-backed).\n" " exec Execute a PEL/PROGRAM-DAG/1 program in-memory (no store writes).\n" - " validate Validate a Program artifact (decode + DAG checks + params).\n" + " validate Validate a Program or Scheme Descriptor artifact.\n" " program Program DAG tools (decode, normalize).\n" " trace Trace DAG tools (decode, from-result).\n" " result Surface result tools (decode).\n" @@ -1155,17 +1155,38 @@ static int amduat_pel_cli_cmd_validate( return AMDUAT_PEL_CLI_EXIT_UNSUPPORTED; } } - if (artifact.has_type_tag && - artifact.type_tag.tag_id != AMDUAT_PEL_TYPE_TAG_PROGRAM_DAG_1) { - fprintf(stderr, "error: type-tag mismatch\n"); - amduat_asl_artifact_free(&artifact); - return AMDUAT_PEL_CLI_EXIT_UNSUPPORTED; - } + { + bool expect_desc = has_expect_type_tag && + expect_type_tag.tag_id == + AMDUAT_PEL_TYPE_TAG_SCHEME_DESC_1; + bool is_desc = (artifact.has_type_tag && + artifact.type_tag.tag_id == + AMDUAT_PEL_TYPE_TAG_SCHEME_DESC_1) || + expect_desc; - if (!amduat_pel_program_validate_artifact(&artifact, &valid)) { - fprintf(stderr, "error: invalid program encoding\n"); - amduat_asl_artifact_free(&artifact); - return AMDUAT_PEL_CLI_EXIT_CODEC; + if (is_desc) { + amduat_pel_dag_scheme_descriptor_t desc; + if (!amduat_pel_program_dag_desc_decode_artifact(&artifact, &desc)) { + fprintf(stderr, "error: invalid scheme descriptor encoding\n"); + amduat_asl_artifact_free(&artifact); + return AMDUAT_PEL_CLI_EXIT_CODEC; + } + amduat_enc_pel_program_dag_desc_free(&desc); + valid = true; + } else { + if (artifact.has_type_tag && + artifact.type_tag.tag_id != AMDUAT_PEL_TYPE_TAG_PROGRAM_DAG_1) { + fprintf(stderr, "error: type-tag mismatch\n"); + amduat_asl_artifact_free(&artifact); + return AMDUAT_PEL_CLI_EXIT_UNSUPPORTED; + } + + if (!amduat_pel_program_validate_artifact(&artifact, &valid)) { + fprintf(stderr, "error: invalid program encoding\n"); + amduat_asl_artifact_free(&artifact); + return AMDUAT_PEL_CLI_EXIT_CODEC; + } + } } amduat_asl_artifact_free(&artifact); diff --git a/tests/pel/test_pel_program_dag_desc.c b/tests/pel/test_pel_program_dag_desc.c new file mode 100644 index 0000000..704c347 --- /dev/null +++ b/tests/pel/test_pel_program_dag_desc.c @@ -0,0 +1,92 @@ +#include "amduat/enc/pel_program_dag_desc.h" +#include "amduat/enc/pel_program_dag.h" +#include "amduat/pel/program_dag_desc.h" + +#include +#include + +static bool bytes_equal(amduat_octets_t bytes, + const uint8_t *expected, + size_t expected_len) { + if (bytes.len != expected_len) { + return false; + } + if (bytes.len == 0) { + return true; + } + return memcmp(bytes.data, expected, expected_len) == 0; +} + +static int test_descriptor_round_trip(void) { + static const uint8_t k_desc_bytes[] = { + 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x50, 0x45, + 0x4c, 0x2f, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x41, + 0x4d, 0x2d, 0x44, 0x41, 0x47, 0x2f, 0x31, 0x00, + 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00 + }; + const char k_scheme_name[] = "PEL/PROGRAM-DAG/1"; + amduat_pel_dag_scheme_descriptor_t desc; + amduat_pel_dag_scheme_descriptor_t decoded; + amduat_octets_t encoded = amduat_octets(NULL, 0); + amduat_octets_t encoded_roundtrip = amduat_octets(NULL, 0); + int exit_code = 1; + + memset(&desc, 0, sizeof(desc)); + desc.pel1_version = 1; + desc.scheme_name = amduat_octets(k_scheme_name, strlen(k_scheme_name)); + desc.program_type_tag = amduat_type_tag(AMDUAT_PEL_TYPE_TAG_PROGRAM_DAG_1); + desc.program_enc_profile = AMDUAT_PEL_ENC_PROGRAM_DAG_V1; + desc.has_trace_profile_ref = false; + desc.has_opreg_ref = false; + + if (!amduat_enc_pel_program_dag_desc_encode_v1(&desc, &encoded)) { + fprintf(stderr, "encode failed\n"); + goto cleanup; + } + if (!bytes_equal(encoded, k_desc_bytes, sizeof(k_desc_bytes))) { + fprintf(stderr, "encoded bytes mismatch\n"); + goto cleanup; + } + + memset(&decoded, 0, sizeof(decoded)); + if (!amduat_enc_pel_program_dag_desc_decode_v1( + amduat_octets(k_desc_bytes, sizeof(k_desc_bytes)), &decoded)) { + fprintf(stderr, "decode failed\n"); + goto cleanup; + } + if (decoded.pel1_version != 1 || + decoded.program_type_tag.tag_id != AMDUAT_PEL_TYPE_TAG_PROGRAM_DAG_1 || + decoded.program_enc_profile != AMDUAT_PEL_ENC_PROGRAM_DAG_V1 || + decoded.has_trace_profile_ref || decoded.has_opreg_ref) { + fprintf(stderr, "decoded fields mismatch\n"); + goto cleanup; + } + if (!bytes_equal(decoded.scheme_name, + (const uint8_t *)k_scheme_name, + strlen(k_scheme_name))) { + fprintf(stderr, "decoded scheme name mismatch\n"); + goto cleanup; + } + + if (!amduat_enc_pel_program_dag_desc_encode_v1(&decoded, + &encoded_roundtrip)) { + fprintf(stderr, "roundtrip encode failed\n"); + goto cleanup; + } + if (!bytes_equal(encoded_roundtrip, k_desc_bytes, sizeof(k_desc_bytes))) { + fprintf(stderr, "roundtrip bytes mismatch\n"); + goto cleanup; + } + + exit_code = 0; + +cleanup: + amduat_octets_free(&encoded); + amduat_octets_free(&encoded_roundtrip); + amduat_enc_pel_program_dag_desc_free(&decoded); + return exit_code; +} + +int main(void) { + return test_descriptor_round_trip(); +}