From 585844a6fc9c50156616c9cac6e6f64f16c3d8d9 Mon Sep 17 00:00:00 2001 From: Carl Niklas Rydberg Date: Sat, 20 Dec 2025 13:54:18 +0100 Subject: [PATCH] Implement PEL encodings and tests --- CMakeLists.txt | 33 ++ include/amduat/enc/pel1_result.h | 14 + include/amduat/enc/pel_program_dag.h | 14 + include/amduat/enc/pel_trace_dag.h | 14 + include/amduat/pel/core.h | 56 ++ include/amduat/pel/program_dag.h | 67 +++ include/amduat/pel/surf.h | 55 ++ include/amduat/pel/trace_dag.h | 54 ++ src/near_core/enc/pel1_result.c | 734 +++++++++++++++++++++++++ src/near_core/enc/pel_program_dag.c | 666 +++++++++++++++++++++++ src/near_core/enc/pel_trace_dag.c | 775 +++++++++++++++++++++++++++ tests/enc/test_pel1_result.c | 126 +++++ tests/enc/test_pel_program_dag.c | 113 ++++ tests/enc/test_pel_trace_dag.c | 155 ++++++ 14 files changed, 2876 insertions(+) create mode 100644 src/near_core/enc/pel1_result.c create mode 100644 tests/enc/test_pel1_result.c create mode 100644 tests/enc/test_pel_program_dag.c create mode 100644 tests/enc/test_pel_trace_dag.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 60dbcd2..fa081b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -78,6 +78,7 @@ set(AMDUAT_ENC_SRCS src/near_core/enc/asl1_core_codec.c src/near_core/enc/pel_program_dag.c src/near_core/enc/pel_trace_dag.c + src/near_core/enc/pel1_result.c src/near_core/enc/tgk1_edge.c ) @@ -147,3 +148,35 @@ target_link_libraries(amduat_asl_cli PRIVATE amduat_asl_store_fs amduat_asl amduat_enc amduat_hash_asl1 amduat_util ) set_target_properties(amduat_asl_cli PROPERTIES OUTPUT_NAME amduat-asl) + +enable_testing() + +add_executable(amduat_test_pel_program_dag tests/enc/test_pel_program_dag.c) +target_include_directories(amduat_test_pel_program_dag + PRIVATE ${AMDUAT_INTERNAL_DIR} + PRIVATE ${AMDUAT_INCLUDE_DIR} +) +target_link_libraries(amduat_test_pel_program_dag + PRIVATE amduat_enc amduat_hash_asl1 amduat_asl amduat_util +) +add_test(NAME pel_program_dag COMMAND amduat_test_pel_program_dag) + +add_executable(amduat_test_pel_trace_dag tests/enc/test_pel_trace_dag.c) +target_include_directories(amduat_test_pel_trace_dag + PRIVATE ${AMDUAT_INTERNAL_DIR} + PRIVATE ${AMDUAT_INCLUDE_DIR} +) +target_link_libraries(amduat_test_pel_trace_dag + PRIVATE amduat_enc amduat_hash_asl1 amduat_asl amduat_util +) +add_test(NAME pel_trace_dag COMMAND amduat_test_pel_trace_dag) + +add_executable(amduat_test_pel1_result tests/enc/test_pel1_result.c) +target_include_directories(amduat_test_pel1_result + PRIVATE ${AMDUAT_INTERNAL_DIR} + PRIVATE ${AMDUAT_INCLUDE_DIR} +) +target_link_libraries(amduat_test_pel1_result + PRIVATE amduat_enc amduat_hash_asl1 amduat_asl amduat_util +) +add_test(NAME pel1_result COMMAND amduat_test_pel1_result) diff --git a/include/amduat/enc/pel1_result.h b/include/amduat/enc/pel1_result.h index cf87590..3bd32a4 100644 --- a/include/amduat/enc/pel1_result.h +++ b/include/amduat/enc/pel1_result.h @@ -1,6 +1,9 @@ #ifndef AMDUAT_ENC_PEL1_RESULT_H #define AMDUAT_ENC_PEL1_RESULT_H +#include "amduat/asl/core.h" +#include "amduat/pel/surf.h" + #ifdef __cplusplus extern "C" { #endif @@ -8,6 +11,17 @@ extern "C" { enum { PEL_ENC_EXECUTION_RESULT_V1 = 0x0103u }; enum { AMDUAT_PEL_ENC_EXECUTION_RESULT_V1 = PEL_ENC_EXECUTION_RESULT_V1 }; +/* Caller owns any heap allocations returned in out_bytes/out_result. */ +bool amduat_enc_pel1_result_encode_v1( + const amduat_pel_surface_execution_result_t *result, + amduat_octets_t *out_bytes); + +bool amduat_enc_pel1_result_decode_v1( + amduat_octets_t bytes, + amduat_pel_surface_execution_result_t *out_result); + +void amduat_enc_pel1_result_free(amduat_pel_surface_execution_result_t *result); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/include/amduat/enc/pel_program_dag.h b/include/amduat/enc/pel_program_dag.h index 2e577a1..de1c1e8 100644 --- a/include/amduat/enc/pel_program_dag.h +++ b/include/amduat/enc/pel_program_dag.h @@ -1,6 +1,9 @@ #ifndef AMDUAT_ENC_PEL_PROGRAM_DAG_H #define AMDUAT_ENC_PEL_PROGRAM_DAG_H +#include "amduat/asl/core.h" +#include "amduat/pel/program_dag.h" + #ifdef __cplusplus extern "C" { #endif @@ -8,6 +11,17 @@ extern "C" { enum { PEL_ENC_PROGRAM_DAG_V1 = 0x0101u }; enum { AMDUAT_PEL_ENC_PROGRAM_DAG_V1 = PEL_ENC_PROGRAM_DAG_V1 }; +/* Caller owns any heap allocations returned in out_bytes/out_program. */ +bool amduat_enc_pel_program_dag_encode_v1( + const amduat_pel_program_t *program, + amduat_octets_t *out_bytes); + +bool amduat_enc_pel_program_dag_decode_v1( + amduat_octets_t bytes, + amduat_pel_program_t *out_program); + +void amduat_enc_pel_program_dag_free(amduat_pel_program_t *program); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/include/amduat/enc/pel_trace_dag.h b/include/amduat/enc/pel_trace_dag.h index 91694cc..417691f 100644 --- a/include/amduat/enc/pel_trace_dag.h +++ b/include/amduat/enc/pel_trace_dag.h @@ -1,6 +1,9 @@ #ifndef AMDUAT_ENC_PEL_TRACE_DAG_H #define AMDUAT_ENC_PEL_TRACE_DAG_H +#include "amduat/asl/core.h" +#include "amduat/pel/trace_dag.h" + #ifdef __cplusplus extern "C" { #endif @@ -8,6 +11,17 @@ extern "C" { enum { PEL_ENC_TRACE_DAG_V1 = 0x0102u }; enum { AMDUAT_PEL_ENC_TRACE_DAG_V1 = PEL_ENC_TRACE_DAG_V1 }; +/* Caller owns any heap allocations returned in out_bytes/out_trace. */ +bool amduat_enc_pel_trace_dag_encode_v1( + const amduat_pel_trace_dag_value_t *trace, + amduat_octets_t *out_bytes); + +bool amduat_enc_pel_trace_dag_decode_v1( + amduat_octets_t bytes, + amduat_pel_trace_dag_value_t *out_trace); + +void amduat_enc_pel_trace_dag_free(amduat_pel_trace_dag_value_t *trace); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/include/amduat/pel/core.h b/include/amduat/pel/core.h index e69de29..27577f5 100644 --- a/include/amduat/pel/core.h +++ b/include/amduat/pel/core.h @@ -0,0 +1,56 @@ +#ifndef AMDUAT_PEL_CORE_H +#define AMDUAT_PEL_CORE_H + +#include "amduat/asl/core.h" + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint8_t amduat_pel_execution_status_t; +typedef uint8_t amduat_pel_execution_error_kind_t; + +enum { + AMDUAT_PEL_EXEC_STATUS_OK = 0, + AMDUAT_PEL_EXEC_STATUS_SCHEME_UNSUPPORTED = 1, + AMDUAT_PEL_EXEC_STATUS_INVALID_PROGRAM = 2, + AMDUAT_PEL_EXEC_STATUS_INVALID_INPUTS = 3, + AMDUAT_PEL_EXEC_STATUS_RUNTIME_FAILED = 4 +}; + +enum { + AMDUAT_PEL_EXEC_ERROR_NONE = 0, + AMDUAT_PEL_EXEC_ERROR_SCHEME = 1, + AMDUAT_PEL_EXEC_ERROR_PROGRAM = 2, + AMDUAT_PEL_EXEC_ERROR_INPUTS = 3, + AMDUAT_PEL_EXEC_ERROR_RUNTIME = 4 +}; + +typedef struct { + amduat_pel_execution_error_kind_t kind; + uint32_t status_code; +} amduat_pel_execution_error_summary_t; + +typedef struct { + uint32_t code; + amduat_octets_t message; +} amduat_pel_diagnostic_entry_t; + +typedef struct { + uint16_t pel1_version; + amduat_pel_execution_status_t status; + amduat_reference_t scheme_ref; + amduat_pel_execution_error_summary_t summary; + amduat_pel_diagnostic_entry_t *diagnostics; + size_t diagnostics_len; +} amduat_pel_execution_result_value_t; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* AMDUAT_PEL_CORE_H */ diff --git a/include/amduat/pel/program_dag.h b/include/amduat/pel/program_dag.h index e69de29..a7177b9 100644 --- a/include/amduat/pel/program_dag.h +++ b/include/amduat/pel/program_dag.h @@ -0,0 +1,67 @@ +#ifndef AMDUAT_PEL_PROGRAM_DAG_H +#define AMDUAT_PEL_PROGRAM_DAG_H + +#include "amduat/asl/core.h" + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint32_t amduat_pel_node_id_t; + +typedef struct { + amduat_octets_t name; + uint32_t version; +} amduat_pel_operation_id_t; + +typedef enum { + AMDUAT_PEL_DAG_INPUT_EXTERNAL = 0, + AMDUAT_PEL_DAG_INPUT_NODE = 1 +} amduat_pel_dag_input_kind_t; + +typedef struct { + uint32_t input_index; +} amduat_pel_dag_input_external_t; + +typedef struct { + amduat_pel_node_id_t node_id; + uint32_t output_index; +} amduat_pel_dag_input_node_t; + +typedef struct { + amduat_pel_dag_input_kind_t kind; + union { + amduat_pel_dag_input_external_t external; + amduat_pel_dag_input_node_t node; + } value; +} amduat_pel_dag_input_t; + +typedef struct { + amduat_pel_node_id_t id; + amduat_pel_operation_id_t op; + amduat_pel_dag_input_t *inputs; + size_t inputs_len; + amduat_octets_t params; +} amduat_pel_node_t; + +typedef struct { + amduat_pel_node_id_t node_id; + uint32_t output_index; +} amduat_pel_root_ref_t; + +typedef struct { + amduat_pel_node_t *nodes; + size_t nodes_len; + amduat_pel_root_ref_t *roots; + size_t roots_len; +} amduat_pel_program_t; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* AMDUAT_PEL_PROGRAM_DAG_H */ diff --git a/include/amduat/pel/surf.h b/include/amduat/pel/surf.h index e69de29..36c9ac4 100644 --- a/include/amduat/pel/surf.h +++ b/include/amduat/pel/surf.h @@ -0,0 +1,55 @@ +#ifndef AMDUAT_PEL_SURF_H +#define AMDUAT_PEL_SURF_H + +#include "amduat/pel/core.h" + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint8_t amduat_pel_store_failure_phase_t; +typedef uint8_t amduat_pel_store_error_code_t; + +enum { + AMDUAT_PEL_STORE_FAILURE_PROGRAM = 1, + AMDUAT_PEL_STORE_FAILURE_INPUT = 2 +}; + +enum { + AMDUAT_PEL_STORE_ERROR_NOT_FOUND = 1, + AMDUAT_PEL_STORE_ERROR_INTEGRITY = 2, + AMDUAT_PEL_STORE_ERROR_UNSUPPORTED = 3 +}; + +typedef struct { + amduat_pel_store_failure_phase_t phase; + amduat_pel_store_error_code_t error_code; + amduat_reference_t failing_ref; +} amduat_pel_store_failure_t; + +typedef struct { + uint16_t pel1_version; + amduat_pel_execution_result_value_t core_result; + amduat_reference_t scheme_ref; + amduat_reference_t program_ref; + amduat_reference_t *input_refs; + size_t input_refs_len; + amduat_reference_t *output_refs; + size_t output_refs_len; + bool has_params_ref; + amduat_reference_t params_ref; + bool has_store_failure; + amduat_pel_store_failure_t store_failure; + bool has_trace_ref; + amduat_reference_t trace_ref; +} amduat_pel_surface_execution_result_t; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* AMDUAT_PEL_SURF_H */ diff --git a/include/amduat/pel/trace_dag.h b/include/amduat/pel/trace_dag.h index e69de29..aa78d88 100644 --- a/include/amduat/pel/trace_dag.h +++ b/include/amduat/pel/trace_dag.h @@ -0,0 +1,54 @@ +#ifndef AMDUAT_PEL_TRACE_DAG_H +#define AMDUAT_PEL_TRACE_DAG_H + +#include "amduat/pel/core.h" + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef uint8_t amduat_pel_node_trace_status_t; + +enum { + AMDUAT_PEL_NODE_TRACE_OK = 0, + AMDUAT_PEL_NODE_TRACE_FAILED = 1, + AMDUAT_PEL_NODE_TRACE_SKIPPED = 2 +}; + +typedef struct { + uint32_t node_id; + amduat_octets_t op_name; + uint32_t op_version; + amduat_pel_node_trace_status_t status; + uint32_t status_code; + amduat_reference_t *output_refs; + size_t output_refs_len; + amduat_pel_diagnostic_entry_t *diagnostics; + size_t diagnostics_len; +} amduat_pel_node_trace_dag_t; + +typedef struct { + uint16_t pel1_version; + amduat_reference_t scheme_ref; + amduat_reference_t program_ref; + amduat_pel_execution_status_t status; + amduat_pel_execution_error_summary_t summary; + bool has_exec_result_ref; + amduat_reference_t exec_result_ref; + amduat_reference_t *input_refs; + size_t input_refs_len; + bool has_params_ref; + amduat_reference_t params_ref; + amduat_pel_node_trace_dag_t *node_traces; + size_t node_traces_len; +} amduat_pel_trace_dag_value_t; + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* AMDUAT_PEL_TRACE_DAG_H */ diff --git a/src/near_core/enc/pel1_result.c b/src/near_core/enc/pel1_result.c new file mode 100644 index 0000000..aacbbb6 --- /dev/null +++ b/src/near_core/enc/pel1_result.c @@ -0,0 +1,734 @@ +#include "amduat/enc/pel1_result.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_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; +} + +static void amduat_reference_free(amduat_reference_t *ref) { + if (ref == NULL) { + return; + } + free((void *)ref->digest.data); + ref->digest.data = NULL; + ref->digest.len = 0; +} + +static void amduat_diagnostic_list_free(amduat_pel_diagnostic_entry_t *entries, + size_t count) { + size_t i; + + if (entries == NULL) { + return; + } + for (i = 0; i < count; ++i) { + free((void *)entries[i].message.data); + entries[i].message.data = NULL; + entries[i].message.len = 0; + } + free(entries); +} + +static bool amduat_execution_result_value_size( + const amduat_pel_execution_result_value_t *value, + size_t *out_len) { + size_t total = 0; + size_t enc_len; + size_t i; + + if (value->pel1_version != 1) { + return false; + } + if (value->diagnostics_len > UINT32_MAX) { + return false; + } + if (value->diagnostics_len > 0 && value->diagnostics == NULL) { + return false; + } + if (!amduat_encoded_ref_len(value->scheme_ref, &enc_len)) { + return false; + } + + if (!amduat_add_size(&total, 2 + 1 + enc_len + 1 + 4 + 4)) { + return false; + } + + for (i = 0; i < value->diagnostics_len; ++i) { + const amduat_pel_diagnostic_entry_t *diag = &value->diagnostics[i]; + if (diag->message.len > UINT32_MAX) { + return false; + } + if (diag->message.len != 0 && diag->message.data == NULL) { + return false; + } + if (!amduat_add_size(&total, 4 + 4 + diag->message.len)) { + return false; + } + } + + *out_len = total; + return true; +} + +static bool amduat_write_execution_result_value( + uint8_t *buffer, + size_t buffer_len, + size_t *offset, + const amduat_pel_execution_result_value_t *value) { + size_t i; + + if (value->pel1_version != 1) { + return false; + } + + amduat_store_u16_be(buffer + *offset, value->pel1_version); + *offset += 2; + buffer[(*offset)++] = value->status; + if (!amduat_write_encoded_ref(buffer, buffer_len, offset, value->scheme_ref)) { + return false; + } + buffer[(*offset)++] = value->summary.kind; + amduat_store_u32_be(buffer + *offset, value->summary.status_code); + *offset += 4; + amduat_store_u32_be(buffer + *offset, (uint32_t)value->diagnostics_len); + *offset += 4; + + for (i = 0; i < value->diagnostics_len; ++i) { + const amduat_pel_diagnostic_entry_t *diag = &value->diagnostics[i]; + amduat_store_u32_be(buffer + *offset, diag->code); + *offset += 4; + amduat_store_u32_be(buffer + *offset, (uint32_t)diag->message.len); + *offset += 4; + if (diag->message.len != 0) { + memcpy(buffer + *offset, diag->message.data, diag->message.len); + *offset += diag->message.len; + } + } + + return true; +} + +static bool amduat_read_execution_result_value( + amduat_cursor_t *cur, + amduat_pel_execution_result_value_t *out_value) { + uint16_t pel1_version; + uint32_t diag_count; + size_t i; + + if (!amduat_read_u16(cur, &pel1_version)) { + return false; + } + if (pel1_version != 1) { + return false; + } + out_value->pel1_version = pel1_version; + if (!amduat_read_u8(cur, &out_value->status)) { + return false; + } + if (!amduat_read_encoded_ref(cur, &out_value->scheme_ref)) { + return false; + } + if (!amduat_read_u8(cur, &out_value->summary.kind) || + !amduat_read_u32(cur, &out_value->summary.status_code)) { + return false; + } + if (!amduat_read_u32(cur, &diag_count)) { + return false; + } + out_value->diagnostics_len = diag_count; + if (diag_count != 0) { + if (diag_count > SIZE_MAX / sizeof(amduat_pel_diagnostic_entry_t)) { + return false; + } + out_value->diagnostics = (amduat_pel_diagnostic_entry_t *)calloc( + diag_count, sizeof(amduat_pel_diagnostic_entry_t)); + if (out_value->diagnostics == NULL) { + return false; + } + } + for (i = 0; i < out_value->diagnostics_len; ++i) { + amduat_pel_diagnostic_entry_t *diag = &out_value->diagnostics[i]; + uint32_t msg_len; + if (!amduat_read_u32(cur, &diag->code) || + !amduat_read_u32(cur, &msg_len)) { + return false; + } + if (cur->len - cur->offset < msg_len) { + return false; + } + if (msg_len != 0) { + uint8_t *msg = (uint8_t *)malloc(msg_len); + if (msg == NULL) { + return false; + } + memcpy(msg, cur->data + cur->offset, msg_len); + diag->message = amduat_octets(msg, msg_len); + } + cur->offset += msg_len; + } + + return true; +} + +void amduat_enc_pel1_result_free(amduat_pel_surface_execution_result_t *result) { + size_t i; + + if (result == NULL) { + return; + } + + amduat_reference_free(&result->scheme_ref); + amduat_reference_free(&result->program_ref); + if (result->input_refs != NULL) { + for (i = 0; i < result->input_refs_len; ++i) { + amduat_reference_free(&result->input_refs[i]); + } + free(result->input_refs); + } + if (result->output_refs != NULL) { + for (i = 0; i < result->output_refs_len; ++i) { + amduat_reference_free(&result->output_refs[i]); + } + free(result->output_refs); + } + if (result->has_params_ref) { + amduat_reference_free(&result->params_ref); + } + if (result->has_store_failure) { + amduat_reference_free(&result->store_failure.failing_ref); + } + if (result->has_trace_ref) { + amduat_reference_free(&result->trace_ref); + } + + amduat_reference_free(&result->core_result.scheme_ref); + amduat_diagnostic_list_free(result->core_result.diagnostics, + result->core_result.diagnostics_len); + result->core_result.diagnostics = NULL; + result->core_result.diagnostics_len = 0; + + result->input_refs = NULL; + result->input_refs_len = 0; + result->output_refs = NULL; + result->output_refs_len = 0; +} + +bool amduat_enc_pel1_result_encode_v1( + const amduat_pel_surface_execution_result_t *result, + amduat_octets_t *out_bytes) { + size_t total_len = 0; + size_t offset = 0; + uint8_t *buffer; + size_t i; + size_t exec_result_len = 0; + + if (result == NULL || out_bytes == NULL) { + return false; + } + out_bytes->data = NULL; + out_bytes->len = 0; + + if (result->pel1_version != 1 || result->core_result.pel1_version != 1) { + return false; + } + if (!amduat_reference_eq(result->scheme_ref, + result->core_result.scheme_ref)) { + return false; + } + if (result->input_refs_len > UINT32_MAX || + result->output_refs_len > UINT32_MAX) { + return false; + } + + if (!amduat_execution_result_value_size(&result->core_result, + &exec_result_len)) { + return false; + } + + if (!amduat_add_size(&total_len, 2)) { + return false; + } + { + size_t enc_len; + if (!amduat_encoded_ref_len(result->scheme_ref, &enc_len) || + !amduat_add_size(&total_len, enc_len)) { + return false; + } + if (!amduat_encoded_ref_len(result->program_ref, &enc_len) || + !amduat_add_size(&total_len, enc_len)) { + return false; + } + } + if (!amduat_add_size(&total_len, 4)) { + return false; + } + if (result->input_refs_len > 0 && result->input_refs == NULL) { + return false; + } + for (i = 0; i < result->input_refs_len; ++i) { + size_t enc_len; + if (!amduat_encoded_ref_len(result->input_refs[i], &enc_len) || + !amduat_add_size(&total_len, enc_len)) { + return false; + } + } + if (!amduat_add_size(&total_len, 4)) { + return false; + } + if (result->output_refs_len > 0 && result->output_refs == NULL) { + return false; + } + for (i = 0; i < result->output_refs_len; ++i) { + size_t enc_len; + if (!amduat_encoded_ref_len(result->output_refs[i], &enc_len) || + !amduat_add_size(&total_len, enc_len)) { + return false; + } + } + if (!amduat_add_size(&total_len, 1)) { + return false; + } + if (result->has_params_ref) { + size_t enc_len; + if (!amduat_encoded_ref_len(result->params_ref, &enc_len) || + !amduat_add_size(&total_len, enc_len)) { + return false; + } + } + if (!amduat_add_size(&total_len, 1)) { + return false; + } + if (result->has_store_failure) { + size_t enc_len; + if (!amduat_encoded_ref_len(result->store_failure.failing_ref, &enc_len)) { + return false; + } + if (!amduat_add_size(&total_len, 1 + 1 + enc_len)) { + return false; + } + } + if (!amduat_add_size(&total_len, 1)) { + return false; + } + if (result->has_trace_ref) { + size_t enc_len; + if (!amduat_encoded_ref_len(result->trace_ref, &enc_len) || + !amduat_add_size(&total_len, enc_len)) { + return false; + } + } + if (!amduat_add_size(&total_len, exec_result_len)) { + return false; + } + + buffer = (uint8_t *)malloc(total_len); + if (buffer == NULL) { + return false; + } + + amduat_store_u16_be(buffer + offset, result->pel1_version); + offset += 2; + + if (!amduat_write_encoded_ref(buffer, total_len, &offset, + result->scheme_ref) || + !amduat_write_encoded_ref(buffer, total_len, &offset, + result->program_ref)) { + free(buffer); + return false; + } + + amduat_store_u32_be(buffer + offset, (uint32_t)result->input_refs_len); + offset += 4; + for (i = 0; i < result->input_refs_len; ++i) { + if (!amduat_write_encoded_ref(buffer, total_len, &offset, + result->input_refs[i])) { + free(buffer); + return false; + } + } + + amduat_store_u32_be(buffer + offset, (uint32_t)result->output_refs_len); + offset += 4; + for (i = 0; i < result->output_refs_len; ++i) { + if (!amduat_write_encoded_ref(buffer, total_len, &offset, + result->output_refs[i])) { + free(buffer); + return false; + } + } + + buffer[offset++] = result->has_params_ref ? 0x01u : 0x00u; + if (result->has_params_ref) { + if (!amduat_write_encoded_ref(buffer, total_len, &offset, + result->params_ref)) { + free(buffer); + return false; + } + } + + buffer[offset++] = result->has_store_failure ? 0x01u : 0x00u; + if (result->has_store_failure) { + if (result->store_failure.phase != AMDUAT_PEL_STORE_FAILURE_PROGRAM && + result->store_failure.phase != AMDUAT_PEL_STORE_FAILURE_INPUT) { + free(buffer); + return false; + } + if (result->store_failure.error_code != AMDUAT_PEL_STORE_ERROR_NOT_FOUND && + result->store_failure.error_code != AMDUAT_PEL_STORE_ERROR_INTEGRITY && + result->store_failure.error_code != AMDUAT_PEL_STORE_ERROR_UNSUPPORTED) { + free(buffer); + return false; + } + buffer[offset++] = result->store_failure.phase; + buffer[offset++] = result->store_failure.error_code; + if (!amduat_write_encoded_ref(buffer, total_len, &offset, + result->store_failure.failing_ref)) { + free(buffer); + return false; + } + } + + buffer[offset++] = result->has_trace_ref ? 0x01u : 0x00u; + if (result->has_trace_ref) { + if (!amduat_write_encoded_ref(buffer, total_len, &offset, + result->trace_ref)) { + free(buffer); + return false; + } + } + + if (!amduat_write_execution_result_value(buffer, + total_len, + &offset, + &result->core_result)) { + free(buffer); + return false; + } + + out_bytes->data = buffer; + out_bytes->len = total_len; + return true; +} + +bool amduat_enc_pel1_result_decode_v1( + amduat_octets_t bytes, + amduat_pel_surface_execution_result_t *out_result) { + amduat_cursor_t cur; + uint16_t pel1_version; + uint32_t input_count; + uint32_t output_count; + size_t i; + + if (out_result == NULL) { + return false; + } + if (bytes.len != 0 && bytes.data == NULL) { + return false; + } + + memset(out_result, 0, sizeof(*out_result)); + 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; + } + out_result->pel1_version = pel1_version; + + if (!amduat_read_encoded_ref(&cur, &out_result->scheme_ref) || + !amduat_read_encoded_ref(&cur, &out_result->program_ref)) { + amduat_enc_pel1_result_free(out_result); + return false; + } + + if (!amduat_read_u32(&cur, &input_count)) { + amduat_enc_pel1_result_free(out_result); + return false; + } + out_result->input_refs_len = input_count; + if (input_count != 0) { + if (input_count > SIZE_MAX / sizeof(amduat_reference_t)) { + amduat_enc_pel1_result_free(out_result); + return false; + } + out_result->input_refs = (amduat_reference_t *)calloc( + input_count, sizeof(amduat_reference_t)); + if (out_result->input_refs == NULL) { + amduat_enc_pel1_result_free(out_result); + return false; + } + } + for (i = 0; i < out_result->input_refs_len; ++i) { + if (!amduat_read_encoded_ref(&cur, &out_result->input_refs[i])) { + amduat_enc_pel1_result_free(out_result); + return false; + } + } + + if (!amduat_read_u32(&cur, &output_count)) { + amduat_enc_pel1_result_free(out_result); + return false; + } + out_result->output_refs_len = output_count; + if (output_count != 0) { + if (output_count > SIZE_MAX / sizeof(amduat_reference_t)) { + amduat_enc_pel1_result_free(out_result); + return false; + } + out_result->output_refs = (amduat_reference_t *)calloc( + output_count, sizeof(amduat_reference_t)); + if (out_result->output_refs == NULL) { + amduat_enc_pel1_result_free(out_result); + return false; + } + } + for (i = 0; i < out_result->output_refs_len; ++i) { + if (!amduat_read_encoded_ref(&cur, &out_result->output_refs[i])) { + amduat_enc_pel1_result_free(out_result); + return false; + } + } + + { + uint8_t has_params_ref; + if (!amduat_read_u8(&cur, &has_params_ref)) { + amduat_enc_pel1_result_free(out_result); + return false; + } + if (has_params_ref != 0x00u && has_params_ref != 0x01u) { + amduat_enc_pel1_result_free(out_result); + return false; + } + out_result->has_params_ref = (has_params_ref == 0x01u); + if (out_result->has_params_ref) { + if (!amduat_read_encoded_ref(&cur, &out_result->params_ref)) { + amduat_enc_pel1_result_free(out_result); + return false; + } + } + } + + { + uint8_t has_store_failure; + if (!amduat_read_u8(&cur, &has_store_failure)) { + amduat_enc_pel1_result_free(out_result); + return false; + } + if (has_store_failure != 0x00u && has_store_failure != 0x01u) { + amduat_enc_pel1_result_free(out_result); + return false; + } + out_result->has_store_failure = (has_store_failure == 0x01u); + if (out_result->has_store_failure) { + if (!amduat_read_u8(&cur, &out_result->store_failure.phase) || + !amduat_read_u8(&cur, &out_result->store_failure.error_code)) { + amduat_enc_pel1_result_free(out_result); + return false; + } + if (out_result->store_failure.phase != + AMDUAT_PEL_STORE_FAILURE_PROGRAM && + out_result->store_failure.phase != AMDUAT_PEL_STORE_FAILURE_INPUT) { + amduat_enc_pel1_result_free(out_result); + return false; + } + if (out_result->store_failure.error_code != + AMDUAT_PEL_STORE_ERROR_NOT_FOUND && + out_result->store_failure.error_code != + AMDUAT_PEL_STORE_ERROR_INTEGRITY && + out_result->store_failure.error_code != + AMDUAT_PEL_STORE_ERROR_UNSUPPORTED) { + amduat_enc_pel1_result_free(out_result); + return false; + } + if (!amduat_read_encoded_ref(&cur, + &out_result->store_failure.failing_ref)) { + amduat_enc_pel1_result_free(out_result); + return false; + } + } + } + + { + uint8_t has_trace_ref; + if (!amduat_read_u8(&cur, &has_trace_ref)) { + amduat_enc_pel1_result_free(out_result); + return false; + } + if (has_trace_ref != 0x00u && has_trace_ref != 0x01u) { + amduat_enc_pel1_result_free(out_result); + return false; + } + out_result->has_trace_ref = (has_trace_ref == 0x01u); + if (out_result->has_trace_ref) { + if (!amduat_read_encoded_ref(&cur, &out_result->trace_ref)) { + amduat_enc_pel1_result_free(out_result); + return false; + } + } + } + + if (!amduat_read_execution_result_value(&cur, &out_result->core_result)) { + amduat_enc_pel1_result_free(out_result); + return false; + } + + if (!amduat_reference_eq(out_result->scheme_ref, + out_result->core_result.scheme_ref)) { + amduat_enc_pel1_result_free(out_result); + return false; + } + + if (cur.offset != cur.len) { + amduat_enc_pel1_result_free(out_result); + return false; + } + + return true; +} diff --git a/src/near_core/enc/pel_program_dag.c b/src/near_core/enc/pel_program_dag.c index e69de29..23c5afe 100644 --- a/src/near_core/enc/pel_program_dag.c +++ b/src/near_core/enc/pel_program_dag.c @@ -0,0 +1,666 @@ +#include "amduat/enc/pel_program_dag.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 int amduat_find_node_index(const amduat_pel_program_t *program, + amduat_pel_node_id_t node_id) { + size_t i; + + for (i = 0; i < program->nodes_len; ++i) { + if (program->nodes[i].id == node_id) { + return (int)i; + } + } + + return -1; +} + +static bool amduat_build_node_order(const amduat_pel_program_t *program, + size_t *out_order) { + size_t n; + size_t *deps; + bool *placed; + size_t i; + + n = program->nodes_len; + deps = NULL; + placed = NULL; + + if (n == 0) { + return true; + } + + deps = (size_t *)calloc(n, sizeof(*deps)); + placed = (bool *)calloc(n, sizeof(*placed)); + if (deps == NULL || placed == NULL) { + free(deps); + free(placed); + return false; + } + + for (i = 0; i < n; ++i) { + size_t j; + for (j = i + 1; j < n; ++j) { + if (program->nodes[i].id == program->nodes[j].id) { + free(deps); + free(placed); + return false; + } + } + } + + for (i = 0; i < n; ++i) { + size_t j; + const amduat_pel_node_t *node; + + node = &program->nodes[i]; + for (j = 0; j < node->inputs_len; ++j) { + const amduat_pel_dag_input_t *input = &node->inputs[j]; + if (input->kind == AMDUAT_PEL_DAG_INPUT_NODE) { + if (amduat_find_node_index(program, input->value.node.node_id) < 0) { + free(deps); + free(placed); + return false; + } + deps[i] += 1; + } + } + } + + for (i = 0; i < n; ++i) { + size_t best = SIZE_MAX; + size_t j; + amduat_pel_node_id_t best_id = 0; + + for (j = 0; j < n; ++j) { + if (placed[j] || deps[j] != 0) { + continue; + } + if (best == SIZE_MAX || program->nodes[j].id < best_id) { + best = j; + best_id = program->nodes[j].id; + } + } + + if (best == SIZE_MAX) { + free(deps); + free(placed); + return false; + } + + out_order[i] = best; + placed[best] = true; + + for (j = 0; j < n; ++j) { + size_t k; + const amduat_pel_node_t *node; + + if (placed[j]) { + continue; + } + node = &program->nodes[j]; + for (k = 0; k < node->inputs_len; ++k) { + const amduat_pel_dag_input_t *input = &node->inputs[k]; + if (input->kind == AMDUAT_PEL_DAG_INPUT_NODE && + input->value.node.node_id == program->nodes[best].id) { + if (deps[j] == 0) { + free(deps); + free(placed); + return false; + } + deps[j] -= 1; + } + } + } + } + + free(deps); + free(placed); + return true; +} + +void amduat_enc_pel_program_dag_free(amduat_pel_program_t *program) { + size_t i; + + if (program == NULL) { + return; + } + + for (i = 0; i < program->nodes_len; ++i) { + amduat_pel_node_t *node = &program->nodes[i]; + free((void *)node->op.name.data); + free(node->inputs); + free((void *)node->params.data); + node->op.name.data = NULL; + node->op.name.len = 0; + node->inputs = NULL; + node->inputs_len = 0; + node->params.data = NULL; + node->params.len = 0; + } + + free(program->nodes); + free(program->roots); + program->nodes = NULL; + program->nodes_len = 0; + program->roots = NULL; + program->roots_len = 0; +} + +bool amduat_enc_pel_program_dag_encode_v1( + const amduat_pel_program_t *program, + amduat_octets_t *out_bytes) { + size_t total_len = 0; + size_t offset = 0; + uint8_t *buffer; + size_t *order; + size_t i; + + if (out_bytes == NULL || program == NULL) { + return false; + } + out_bytes->data = NULL; + out_bytes->len = 0; + + if (program->nodes_len > 0 && program->nodes == NULL) { + return false; + } + if (program->roots_len > 0 && program->roots == NULL) { + return false; + } + + order = NULL; + if (program->nodes_len > 0) { + order = (size_t *)malloc(program->nodes_len * sizeof(*order)); + if (order == NULL) { + return false; + } + if (!amduat_build_node_order(program, order)) { + free(order); + return false; + } + } + + if (!amduat_add_size(&total_len, 2)) { + free(order); + return false; + } + if (program->nodes_len > UINT32_MAX || program->roots_len > UINT32_MAX) { + free(order); + return false; + } + if (!amduat_add_size(&total_len, 4)) { + free(order); + return false; + } + + for (i = 0; i < program->nodes_len; ++i) { + const amduat_pel_node_t *node = &program->nodes[order ? order[i] : i]; + size_t j; + + if (node->op.name.len > UINT32_MAX) { + free(order); + return false; + } + if (node->op.name.len > 0 && node->op.name.data == NULL) { + free(order); + return false; + } + if (!amduat_utf8_is_valid(node->op.name)) { + free(order); + return false; + } + if (node->inputs_len > 0 && node->inputs == NULL) { + free(order); + return false; + } + if (node->inputs_len > UINT32_MAX) { + free(order); + return false; + } + if (node->params.len > UINT32_MAX) { + free(order); + return false; + } + if (node->params.len > 0 && node->params.data == NULL) { + free(order); + return false; + } + + if (!amduat_add_size(&total_len, 4)) { + free(order); + return false; + } + if (!amduat_add_size(&total_len, 4 + node->op.name.len)) { + free(order); + return false; + } + if (!amduat_add_size(&total_len, 4)) { + free(order); + return false; + } + if (!amduat_add_size(&total_len, 4)) { + free(order); + return false; + } + + for (j = 0; j < node->inputs_len; ++j) { + const amduat_pel_dag_input_t *input = &node->inputs[j]; + if (!amduat_add_size(&total_len, 1)) { + free(order); + return false; + } + if (input->kind == AMDUAT_PEL_DAG_INPUT_EXTERNAL) { + if (!amduat_add_size(&total_len, 4)) { + free(order); + return false; + } + } else if (input->kind == AMDUAT_PEL_DAG_INPUT_NODE) { + if (!amduat_add_size(&total_len, 8)) { + free(order); + return false; + } + } else { + free(order); + return false; + } + } + + if (!amduat_add_size(&total_len, 4 + node->params.len)) { + free(order); + return false; + } + } + + if (!amduat_add_size(&total_len, 4)) { + free(order); + return false; + } + if (!amduat_add_size(&total_len, program->roots_len * 8)) { + free(order); + return false; + } + + buffer = (uint8_t *)malloc(total_len); + if (buffer == NULL) { + free(order); + return false; + } + + amduat_store_u16_be(buffer + offset, 1); + offset += 2; + amduat_store_u32_be(buffer + offset, (uint32_t)program->nodes_len); + offset += 4; + + for (i = 0; i < program->nodes_len; ++i) { + const amduat_pel_node_t *node = &program->nodes[order ? order[i] : i]; + size_t j; + + amduat_store_u32_be(buffer + offset, node->id); + offset += 4; + amduat_store_u32_be(buffer + offset, (uint32_t)node->op.name.len); + offset += 4; + if (node->op.name.len != 0) { + memcpy(buffer + offset, node->op.name.data, node->op.name.len); + offset += node->op.name.len; + } + amduat_store_u32_be(buffer + offset, node->op.version); + offset += 4; + amduat_store_u32_be(buffer + offset, (uint32_t)node->inputs_len); + offset += 4; + + for (j = 0; j < node->inputs_len; ++j) { + const amduat_pel_dag_input_t *input = &node->inputs[j]; + buffer[offset++] = (uint8_t)input->kind; + if (input->kind == AMDUAT_PEL_DAG_INPUT_EXTERNAL) { + amduat_store_u32_be(buffer + offset, input->value.external.input_index); + offset += 4; + } else { + amduat_store_u32_be(buffer + offset, input->value.node.node_id); + offset += 4; + amduat_store_u32_be(buffer + offset, input->value.node.output_index); + offset += 4; + } + } + + amduat_store_u32_be(buffer + offset, (uint32_t)node->params.len); + offset += 4; + if (node->params.len != 0) { + memcpy(buffer + offset, node->params.data, node->params.len); + offset += node->params.len; + } + } + + amduat_store_u32_be(buffer + offset, (uint32_t)program->roots_len); + offset += 4; + for (i = 0; i < program->roots_len; ++i) { + amduat_store_u32_be(buffer + offset, program->roots[i].node_id); + offset += 4; + amduat_store_u32_be(buffer + offset, program->roots[i].output_index); + offset += 4; + } + + free(order); + out_bytes->data = buffer; + out_bytes->len = total_len; + return true; +} + +bool amduat_enc_pel_program_dag_decode_v1( + amduat_octets_t bytes, + amduat_pel_program_t *out_program) { + amduat_cursor_t cur; + uint16_t version; + uint32_t node_count; + uint32_t root_count; + size_t i; + + if (out_program == NULL) { + return false; + } + + if (bytes.len != 0 && bytes.data == NULL) { + return false; + } + + memset(out_program, 0, sizeof(*out_program)); + + cur.data = bytes.data; + cur.len = bytes.len; + cur.offset = 0; + + if (!amduat_read_u16(&cur, &version)) { + return false; + } + if (version != 1) { + return false; + } + if (!amduat_read_u32(&cur, &node_count)) { + return false; + } + + if (node_count != 0) { + if (node_count > SIZE_MAX / sizeof(amduat_pel_node_t)) { + return false; + } + out_program->nodes = (amduat_pel_node_t *)calloc( + node_count, sizeof(amduat_pel_node_t)); + if (out_program->nodes == NULL) { + return false; + } + } + out_program->nodes_len = node_count; + + for (i = 0; i < out_program->nodes_len; ++i) { + amduat_pel_node_t *node = &out_program->nodes[i]; + uint32_t name_len; + uint32_t input_count; + uint32_t params_len; + size_t j; + + if (!amduat_read_u32(&cur, &node->id)) { + amduat_enc_pel_program_dag_free(out_program); + return false; + } + if (!amduat_read_u32(&cur, &name_len)) { + amduat_enc_pel_program_dag_free(out_program); + return false; + } + if (cur.len - cur.offset < name_len) { + amduat_enc_pel_program_dag_free(out_program); + return false; + } + if (name_len != 0) { + uint8_t *name = (uint8_t *)malloc(name_len); + if (name == NULL) { + amduat_enc_pel_program_dag_free(out_program); + return false; + } + memcpy(name, cur.data + cur.offset, name_len); + node->op.name = amduat_octets(name, name_len); + if (!amduat_utf8_is_valid(node->op.name)) { + amduat_enc_pel_program_dag_free(out_program); + return false; + } + } + cur.offset += name_len; + + if (!amduat_read_u32(&cur, &node->op.version)) { + amduat_enc_pel_program_dag_free(out_program); + return false; + } + if (!amduat_read_u32(&cur, &input_count)) { + amduat_enc_pel_program_dag_free(out_program); + return false; + } + if (input_count > SIZE_MAX / sizeof(amduat_pel_dag_input_t)) { + amduat_enc_pel_program_dag_free(out_program); + return false; + } + node->inputs_len = input_count; + if (input_count != 0) { + node->inputs = (amduat_pel_dag_input_t *)calloc( + input_count, sizeof(amduat_pel_dag_input_t)); + if (node->inputs == NULL) { + amduat_enc_pel_program_dag_free(out_program); + return false; + } + } + + for (j = 0; j < node->inputs_len; ++j) { + uint8_t kind; + amduat_pel_dag_input_t *input = &node->inputs[j]; + if (!amduat_read_u8(&cur, &kind)) { + amduat_enc_pel_program_dag_free(out_program); + return false; + } + if (kind == AMDUAT_PEL_DAG_INPUT_EXTERNAL) { + uint32_t input_index; + if (!amduat_read_u32(&cur, &input_index)) { + amduat_enc_pel_program_dag_free(out_program); + return false; + } + input->kind = AMDUAT_PEL_DAG_INPUT_EXTERNAL; + input->value.external.input_index = input_index; + } else if (kind == AMDUAT_PEL_DAG_INPUT_NODE) { + uint32_t node_id; + uint32_t output_index; + if (!amduat_read_u32(&cur, &node_id) || + !amduat_read_u32(&cur, &output_index)) { + amduat_enc_pel_program_dag_free(out_program); + return false; + } + input->kind = AMDUAT_PEL_DAG_INPUT_NODE; + input->value.node.node_id = node_id; + input->value.node.output_index = output_index; + } else { + amduat_enc_pel_program_dag_free(out_program); + return false; + } + } + + if (!amduat_read_u32(&cur, ¶ms_len)) { + amduat_enc_pel_program_dag_free(out_program); + return false; + } + if (cur.len - cur.offset < params_len) { + amduat_enc_pel_program_dag_free(out_program); + return false; + } + if (params_len != 0) { + uint8_t *params = (uint8_t *)malloc(params_len); + if (params == NULL) { + amduat_enc_pel_program_dag_free(out_program); + return false; + } + memcpy(params, cur.data + cur.offset, params_len); + node->params = amduat_octets(params, params_len); + } + cur.offset += params_len; + } + + if (!amduat_read_u32(&cur, &root_count)) { + amduat_enc_pel_program_dag_free(out_program); + return false; + } + out_program->roots_len = root_count; + if (root_count != 0) { + if (root_count > SIZE_MAX / sizeof(amduat_pel_root_ref_t)) { + amduat_enc_pel_program_dag_free(out_program); + return false; + } + out_program->roots = + (amduat_pel_root_ref_t *)calloc(root_count, + sizeof(amduat_pel_root_ref_t)); + if (out_program->roots == NULL) { + amduat_enc_pel_program_dag_free(out_program); + return false; + } + } + + for (i = 0; i < out_program->roots_len; ++i) { + uint32_t node_id; + uint32_t output_index; + if (!amduat_read_u32(&cur, &node_id) || + !amduat_read_u32(&cur, &output_index)) { + amduat_enc_pel_program_dag_free(out_program); + return false; + } + out_program->roots[i].node_id = node_id; + out_program->roots[i].output_index = output_index; + } + + if (cur.offset != cur.len) { + amduat_enc_pel_program_dag_free(out_program); + return false; + } + + return true; +} diff --git a/src/near_core/enc/pel_trace_dag.c b/src/near_core/enc/pel_trace_dag.c index e69de29..03c5f6d 100644 --- a/src/near_core/enc/pel_trace_dag.c +++ b/src/near_core/enc/pel_trace_dag.c @@ -0,0 +1,775 @@ +#include "amduat/enc/pel_trace_dag.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; +} + +static void amduat_reference_free(amduat_reference_t *ref) { + if (ref == NULL) { + return; + } + free((void *)ref->digest.data); + ref->digest.data = NULL; + ref->digest.len = 0; +} + +static void amduat_diagnostic_list_free(amduat_pel_diagnostic_entry_t *entries, + size_t count) { + size_t i; + + if (entries == NULL) { + return; + } + for (i = 0; i < count; ++i) { + free((void *)entries[i].message.data); + entries[i].message.data = NULL; + entries[i].message.len = 0; + } + free(entries); +} + +void amduat_enc_pel_trace_dag_free(amduat_pel_trace_dag_value_t *trace) { + size_t i; + + if (trace == NULL) { + return; + } + + amduat_reference_free(&trace->scheme_ref); + amduat_reference_free(&trace->program_ref); + if (trace->has_exec_result_ref) { + amduat_reference_free(&trace->exec_result_ref); + } + if (trace->input_refs != NULL) { + for (i = 0; i < trace->input_refs_len; ++i) { + amduat_reference_free(&trace->input_refs[i]); + } + free(trace->input_refs); + } + if (trace->has_params_ref) { + amduat_reference_free(&trace->params_ref); + } + + if (trace->node_traces != NULL) { + for (i = 0; i < trace->node_traces_len; ++i) { + amduat_pel_node_trace_dag_t *node = &trace->node_traces[i]; + free((void *)node->op_name.data); + if (node->output_refs != NULL) { + size_t j; + for (j = 0; j < node->output_refs_len; ++j) { + amduat_reference_free(&node->output_refs[j]); + } + free(node->output_refs); + } + amduat_diagnostic_list_free(node->diagnostics, node->diagnostics_len); + node->op_name.data = NULL; + node->op_name.len = 0; + node->output_refs = NULL; + node->output_refs_len = 0; + node->diagnostics = NULL; + node->diagnostics_len = 0; + } + free(trace->node_traces); + } + + trace->input_refs = NULL; + trace->input_refs_len = 0; + trace->node_traces = NULL; + trace->node_traces_len = 0; +} + +bool amduat_enc_pel_trace_dag_encode_v1( + const amduat_pel_trace_dag_value_t *trace, + amduat_octets_t *out_bytes) { + size_t total_len = 0; + size_t offset = 0; + uint8_t *buffer; + size_t i; + + if (trace == NULL || out_bytes == NULL) { + return false; + } + + out_bytes->data = NULL; + out_bytes->len = 0; + + if (trace->pel1_version != 1) { + return false; + } + if (!amduat_add_size(&total_len, 2)) { + return false; + } + if (trace->input_refs_len > UINT32_MAX || + trace->node_traces_len > UINT32_MAX) { + return false; + } + { + size_t enc_len; + if (!amduat_encoded_ref_len(trace->scheme_ref, &enc_len) || + !amduat_add_size(&total_len, enc_len)) { + return false; + } + if (!amduat_encoded_ref_len(trace->program_ref, &enc_len) || + !amduat_add_size(&total_len, enc_len)) { + return false; + } + } + if (!amduat_add_size(&total_len, 1 + 1 + 4)) { + return false; + } + if (!amduat_add_size(&total_len, 1)) { + return false; + } + if (trace->has_exec_result_ref) { + size_t enc_len; + if (!amduat_encoded_ref_len(trace->exec_result_ref, &enc_len) || + !amduat_add_size(&total_len, enc_len)) { + return false; + } + } + if (!amduat_add_size(&total_len, 4)) { + return false; + } + if (trace->input_refs_len > 0 && trace->input_refs == NULL) { + return false; + } + for (i = 0; i < trace->input_refs_len; ++i) { + size_t enc_len; + if (!amduat_encoded_ref_len(trace->input_refs[i], &enc_len) || + !amduat_add_size(&total_len, enc_len)) { + return false; + } + } + if (!amduat_add_size(&total_len, 1)) { + return false; + } + if (trace->has_params_ref) { + size_t enc_len; + if (!amduat_encoded_ref_len(trace->params_ref, &enc_len) || + !amduat_add_size(&total_len, enc_len)) { + return false; + } + } + + if (!amduat_add_size(&total_len, 4)) { + return false; + } + if (trace->node_traces_len > 0 && trace->node_traces == NULL) { + return false; + } + for (i = 0; i < trace->node_traces_len; ++i) { + const amduat_pel_node_trace_dag_t *node = &trace->node_traces[i]; + size_t j; + + if (node->output_refs_len > UINT32_MAX || + node->diagnostics_len > UINT32_MAX) { + return false; + } + if (node->op_name.len > UINT32_MAX) { + return false; + } + if (node->op_name.len != 0 && node->op_name.data == NULL) { + return false; + } + if (!amduat_utf8_is_valid(node->op_name)) { + return false; + } + if (node->status != AMDUAT_PEL_NODE_TRACE_OK && + node->status != AMDUAT_PEL_NODE_TRACE_FAILED && + node->status != AMDUAT_PEL_NODE_TRACE_SKIPPED) { + return false; + } + if (!amduat_add_size(&total_len, 4 + 4 + node->op_name.len + 4)) { + return false; + } + if (!amduat_add_size(&total_len, 1 + 4)) { + return false; + } + if (!amduat_add_size(&total_len, 4)) { + return false; + } + if (node->output_refs_len > 0 && node->output_refs == NULL) { + return false; + } + for (j = 0; j < node->output_refs_len; ++j) { + size_t enc_len; + if (!amduat_encoded_ref_len(node->output_refs[j], &enc_len) || + !amduat_add_size(&total_len, enc_len)) { + return false; + } + } + if (!amduat_add_size(&total_len, 4)) { + return false; + } + if (node->diagnostics_len > 0 && node->diagnostics == NULL) { + return false; + } + for (j = 0; j < node->diagnostics_len; ++j) { + const amduat_pel_diagnostic_entry_t *diag = &node->diagnostics[j]; + if (diag->message.len > UINT32_MAX) { + return false; + } + if (diag->message.len != 0 && diag->message.data == NULL) { + return false; + } + if (!amduat_add_size(&total_len, 4 + 4 + diag->message.len)) { + return false; + } + } + } + + buffer = (uint8_t *)malloc(total_len); + if (buffer == NULL) { + return false; + } + + amduat_store_u16_be(buffer + offset, trace->pel1_version); + offset += 2; + if (!amduat_write_encoded_ref(buffer, total_len, &offset, + trace->scheme_ref) || + !amduat_write_encoded_ref(buffer, total_len, &offset, + trace->program_ref)) { + free(buffer); + return false; + } + + buffer[offset++] = trace->status; + buffer[offset++] = trace->summary.kind; + amduat_store_u32_be(buffer + offset, trace->summary.status_code); + offset += 4; + + buffer[offset++] = trace->has_exec_result_ref ? 0x01u : 0x00u; + if (trace->has_exec_result_ref) { + if (!amduat_write_encoded_ref(buffer, total_len, &offset, + trace->exec_result_ref)) { + free(buffer); + return false; + } + } + + amduat_store_u32_be(buffer + offset, (uint32_t)trace->input_refs_len); + offset += 4; + for (i = 0; i < trace->input_refs_len; ++i) { + if (!amduat_write_encoded_ref(buffer, total_len, &offset, + trace->input_refs[i])) { + free(buffer); + return false; + } + } + + buffer[offset++] = trace->has_params_ref ? 0x01u : 0x00u; + if (trace->has_params_ref) { + if (!amduat_write_encoded_ref(buffer, total_len, &offset, + trace->params_ref)) { + free(buffer); + return false; + } + } + + amduat_store_u32_be(buffer + offset, (uint32_t)trace->node_traces_len); + offset += 4; + for (i = 0; i < trace->node_traces_len; ++i) { + const amduat_pel_node_trace_dag_t *node = &trace->node_traces[i]; + size_t j; + + amduat_store_u32_be(buffer + offset, node->node_id); + offset += 4; + amduat_store_u32_be(buffer + offset, (uint32_t)node->op_name.len); + offset += 4; + if (node->op_name.len != 0) { + memcpy(buffer + offset, node->op_name.data, node->op_name.len); + offset += node->op_name.len; + } + amduat_store_u32_be(buffer + offset, node->op_version); + offset += 4; + + buffer[offset++] = node->status; + amduat_store_u32_be(buffer + offset, node->status_code); + offset += 4; + + amduat_store_u32_be(buffer + offset, (uint32_t)node->output_refs_len); + offset += 4; + for (j = 0; j < node->output_refs_len; ++j) { + if (!amduat_write_encoded_ref(buffer, total_len, &offset, + node->output_refs[j])) { + free(buffer); + return false; + } + } + + amduat_store_u32_be(buffer + offset, (uint32_t)node->diagnostics_len); + offset += 4; + for (j = 0; j < node->diagnostics_len; ++j) { + const amduat_pel_diagnostic_entry_t *diag = &node->diagnostics[j]; + amduat_store_u32_be(buffer + offset, diag->code); + offset += 4; + amduat_store_u32_be(buffer + offset, (uint32_t)diag->message.len); + offset += 4; + if (diag->message.len != 0) { + memcpy(buffer + offset, diag->message.data, diag->message.len); + offset += diag->message.len; + } + } + } + + out_bytes->data = buffer; + out_bytes->len = total_len; + return true; +} + +bool amduat_enc_pel_trace_dag_decode_v1( + amduat_octets_t bytes, + amduat_pel_trace_dag_value_t *out_trace) { + amduat_cursor_t cur; + uint16_t pel1_version; + uint32_t input_count; + uint32_t node_trace_count; + size_t i; + + if (out_trace == NULL) { + return false; + } + + if (bytes.len != 0 && bytes.data == NULL) { + return false; + } + + memset(out_trace, 0, sizeof(*out_trace)); + 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; + } + out_trace->pel1_version = pel1_version; + + if (!amduat_read_encoded_ref(&cur, &out_trace->scheme_ref) || + !amduat_read_encoded_ref(&cur, &out_trace->program_ref)) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + + if (!amduat_read_u8(&cur, &out_trace->status) || + !amduat_read_u8(&cur, &out_trace->summary.kind) || + !amduat_read_u32(&cur, &out_trace->summary.status_code)) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + + { + uint8_t has_exec_result; + if (!amduat_read_u8(&cur, &has_exec_result)) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + if (has_exec_result != 0x00u && has_exec_result != 0x01u) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + out_trace->has_exec_result_ref = (has_exec_result == 0x01u); + if (out_trace->has_exec_result_ref) { + if (!amduat_read_encoded_ref(&cur, &out_trace->exec_result_ref)) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + } + } + + if (!amduat_read_u32(&cur, &input_count)) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + out_trace->input_refs_len = input_count; + if (input_count != 0) { + if (input_count > SIZE_MAX / sizeof(amduat_reference_t)) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + out_trace->input_refs = + (amduat_reference_t *)calloc(input_count, sizeof(amduat_reference_t)); + if (out_trace->input_refs == NULL) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + } + for (i = 0; i < out_trace->input_refs_len; ++i) { + if (!amduat_read_encoded_ref(&cur, &out_trace->input_refs[i])) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + } + + { + uint8_t has_params_ref; + if (!amduat_read_u8(&cur, &has_params_ref)) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + if (has_params_ref != 0x00u && has_params_ref != 0x01u) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + out_trace->has_params_ref = (has_params_ref == 0x01u); + if (out_trace->has_params_ref) { + if (!amduat_read_encoded_ref(&cur, &out_trace->params_ref)) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + } + } + + if (!amduat_read_u32(&cur, &node_trace_count)) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + out_trace->node_traces_len = node_trace_count; + if (node_trace_count != 0) { + if (node_trace_count > SIZE_MAX / sizeof(amduat_pel_node_trace_dag_t)) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + out_trace->node_traces = (amduat_pel_node_trace_dag_t *)calloc( + node_trace_count, sizeof(amduat_pel_node_trace_dag_t)); + if (out_trace->node_traces == NULL) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + } + + for (i = 0; i < out_trace->node_traces_len; ++i) { + amduat_pel_node_trace_dag_t *node = &out_trace->node_traces[i]; + uint32_t name_len; + uint32_t output_ref_count; + uint32_t diag_count; + size_t j; + + if (!amduat_read_u32(&cur, &node->node_id)) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + if (!amduat_read_u32(&cur, &name_len)) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + if (cur.len - cur.offset < name_len) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + if (name_len != 0) { + uint8_t *name = (uint8_t *)malloc(name_len); + if (name == NULL) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + memcpy(name, cur.data + cur.offset, name_len); + node->op_name = amduat_octets(name, name_len); + if (!amduat_utf8_is_valid(node->op_name)) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + } + cur.offset += name_len; + + if (!amduat_read_u32(&cur, &node->op_version)) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + if (!amduat_read_u8(&cur, &node->status) || + !amduat_read_u32(&cur, &node->status_code)) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + if (node->status != AMDUAT_PEL_NODE_TRACE_OK && + node->status != AMDUAT_PEL_NODE_TRACE_FAILED && + node->status != AMDUAT_PEL_NODE_TRACE_SKIPPED) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + + if (!amduat_read_u32(&cur, &output_ref_count)) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + node->output_refs_len = output_ref_count; + if (output_ref_count != 0) { + if (output_ref_count > SIZE_MAX / sizeof(amduat_reference_t)) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + node->output_refs = (amduat_reference_t *)calloc( + output_ref_count, sizeof(amduat_reference_t)); + if (node->output_refs == NULL) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + } + for (j = 0; j < node->output_refs_len; ++j) { + if (!amduat_read_encoded_ref(&cur, &node->output_refs[j])) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + } + + if (!amduat_read_u32(&cur, &diag_count)) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + node->diagnostics_len = diag_count; + if (diag_count != 0) { + if (diag_count > SIZE_MAX / sizeof(amduat_pel_diagnostic_entry_t)) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + node->diagnostics = (amduat_pel_diagnostic_entry_t *)calloc( + diag_count, sizeof(amduat_pel_diagnostic_entry_t)); + if (node->diagnostics == NULL) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + } + for (j = 0; j < node->diagnostics_len; ++j) { + amduat_pel_diagnostic_entry_t *diag = &node->diagnostics[j]; + uint32_t msg_len; + if (!amduat_read_u32(&cur, &diag->code) || + !amduat_read_u32(&cur, &msg_len)) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + if (cur.len - cur.offset < msg_len) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + if (msg_len != 0) { + uint8_t *msg = (uint8_t *)malloc(msg_len); + if (msg == NULL) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + memcpy(msg, cur.data + cur.offset, msg_len); + diag->message = amduat_octets(msg, msg_len); + } + cur.offset += msg_len; + } + } + + if (cur.offset != cur.len) { + amduat_enc_pel_trace_dag_free(out_trace); + return false; + } + + return true; +} diff --git a/tests/enc/test_pel1_result.c b/tests/enc/test_pel1_result.c new file mode 100644 index 0000000..6a60852 --- /dev/null +++ b/tests/enc/test_pel1_result.c @@ -0,0 +1,126 @@ +#include "amduat/enc/pel1_result.h" + +#include +#include +#include +#include +#include + +static const uint8_t k_expected_result_bytes[] = { + 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x01, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x22, 0x00, 0x01, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x00, 0x00, 0x00, 0x22, 0x00, 0x01, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x01, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x22, 0x00, 0x01, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, +}; + +static void fill_digest(uint8_t *out, uint8_t value) { + memset(out, value, 32); +} + +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 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_result_encoding(void) { + amduat_pel_surface_execution_result_t result; + amduat_reference_t input_refs[2]; + amduat_reference_t output_refs[1]; + amduat_octets_t encoded; + amduat_pel_surface_execution_result_t decoded; + uint8_t s[32], p[32], i0[32], i1[32], o0[32], t[32]; + int exit_code = 1; + + memset(&result, 0, sizeof(result)); + result.pel1_version = 1; + result.scheme_ref = make_ref(0x01, s); + result.program_ref = make_ref(0x02, p); + + input_refs[0] = make_ref(0x10, i0); + input_refs[1] = make_ref(0x11, i1); + result.input_refs = input_refs; + result.input_refs_len = 2; + + output_refs[0] = make_ref(0x20, o0); + result.output_refs = output_refs; + result.output_refs_len = 1; + + result.has_params_ref = false; + result.has_store_failure = false; + result.has_trace_ref = true; + result.trace_ref = make_ref(0x30, t); + + result.core_result.pel1_version = 1; + result.core_result.status = AMDUAT_PEL_EXEC_STATUS_OK; + result.core_result.scheme_ref = result.scheme_ref; + result.core_result.summary.kind = AMDUAT_PEL_EXEC_ERROR_NONE; + result.core_result.summary.status_code = 0; + result.core_result.diagnostics = NULL; + result.core_result.diagnostics_len = 0; + + if (!amduat_enc_pel1_result_encode_v1(&result, &encoded)) { + fprintf(stderr, "encode failed\n"); + return exit_code; + } + + if (!bytes_equal(encoded, k_expected_result_bytes, + sizeof(k_expected_result_bytes))) { + fprintf(stderr, "encoded bytes mismatch\n"); + goto cleanup; + } + + if (!amduat_enc_pel1_result_decode_v1(encoded, &decoded)) { + fprintf(stderr, "decode failed\n"); + goto cleanup; + } + + if (decoded.input_refs_len != 2 || decoded.output_refs_len != 1) { + fprintf(stderr, "decoded lengths mismatch\n"); + goto cleanup_decoded; + } + + exit_code = 0; + +cleanup_decoded: + amduat_enc_pel1_result_free(&decoded); +cleanup: + free((void *)encoded.data); + return exit_code; +} + +int main(void) { + return test_result_encoding(); +} diff --git a/tests/enc/test_pel_program_dag.c b/tests/enc/test_pel_program_dag.c new file mode 100644 index 0000000..feba6e3 --- /dev/null +++ b/tests/enc/test_pel_program_dag.c @@ -0,0 +1,113 @@ +#include "amduat/enc/pel_program_dag.h" + +#include +#include +#include +#include +#include + +static const uint8_t k_expected_program_bytes[] = { + 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x05, 0x61, 0x64, 0x64, 0x36, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x05, 0x6d, 0x75, 0x6c, 0x36, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, +}; + +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_program_encoding(void) { + amduat_pel_dag_input_t node1_inputs[2]; + amduat_pel_dag_input_t node2_inputs[2]; + amduat_pel_node_t nodes[2]; + amduat_pel_root_ref_t roots[1]; + amduat_pel_program_t program; + amduat_octets_t encoded; + amduat_pel_program_t decoded; + const char add_name[] = "add64"; + const char mul_name[] = "mul64"; + int exit_code = 1; + + node1_inputs[0].kind = AMDUAT_PEL_DAG_INPUT_EXTERNAL; + node1_inputs[0].value.external.input_index = 0; + node1_inputs[1].kind = AMDUAT_PEL_DAG_INPUT_EXTERNAL; + node1_inputs[1].value.external.input_index = 1; + + node2_inputs[0].kind = AMDUAT_PEL_DAG_INPUT_NODE; + node2_inputs[0].value.node.node_id = 1; + node2_inputs[0].value.node.output_index = 0; + node2_inputs[1].kind = AMDUAT_PEL_DAG_INPUT_EXTERNAL; + node2_inputs[1].value.external.input_index = 2; + + nodes[0].id = 2; + nodes[0].op.name = amduat_octets(mul_name, strlen(mul_name)); + nodes[0].op.version = 1; + nodes[0].inputs = node2_inputs; + nodes[0].inputs_len = 2; + nodes[0].params = amduat_octets(NULL, 0); + + nodes[1].id = 1; + nodes[1].op.name = amduat_octets(add_name, strlen(add_name)); + nodes[1].op.version = 1; + nodes[1].inputs = node1_inputs; + nodes[1].inputs_len = 2; + nodes[1].params = amduat_octets(NULL, 0); + + roots[0].node_id = 2; + roots[0].output_index = 0; + + program.nodes = nodes; + program.nodes_len = 2; + program.roots = roots; + program.roots_len = 1; + + if (!amduat_enc_pel_program_dag_encode_v1(&program, &encoded)) { + fprintf(stderr, "encode failed\n"); + return exit_code; + } + + if (!bytes_equal(encoded, k_expected_program_bytes, + sizeof(k_expected_program_bytes))) { + fprintf(stderr, "encoded bytes mismatch\n"); + goto cleanup; + } + + if (!amduat_enc_pel_program_dag_decode_v1(encoded, &decoded)) { + fprintf(stderr, "decode failed\n"); + goto cleanup; + } + + if (decoded.nodes_len != 2 || decoded.roots_len != 1) { + fprintf(stderr, "decoded lengths mismatch\n"); + goto cleanup_decoded; + } + if (decoded.nodes[0].id != 1 || decoded.nodes[1].id != 2) { + fprintf(stderr, "decoded node order mismatch\n"); + goto cleanup_decoded; + } + + exit_code = 0; + +cleanup_decoded: + amduat_enc_pel_program_dag_free(&decoded); +cleanup: + free((void *)encoded.data); + return exit_code; +} + +int main(void) { + return test_program_encoding(); +} diff --git a/tests/enc/test_pel_trace_dag.c b/tests/enc/test_pel_trace_dag.c new file mode 100644 index 0000000..61aee1e --- /dev/null +++ b/tests/enc/test_pel_trace_dag.c @@ -0,0 +1,155 @@ +#include "amduat/enc/pel_trace_dag.h" + +#include +#include +#include +#include +#include + +static const uint8_t k_expected_trace_bytes[] = { + 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x01, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x01, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x22, 0x00, + 0x01, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, + 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x00, 0x00, 0x00, + 0x22, 0x00, 0x01, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, + 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00, + 0x00, 0x00, 0x22, 0x00, 0x01, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, 0x12, + 0x12, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x05, 0x61, 0x64, 0x64, 0x36, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, + 0x00, 0x01, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, + 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x05, 0x6d, 0x75, + 0x6c, 0x36, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x22, 0x00, 0x01, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, + 0x21, 0x21, 0x21, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00, +}; + +static void fill_digest(uint8_t *out, uint8_t value) { + memset(out, value, 32); +} + +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 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_trace_encoding(void) { + amduat_pel_trace_dag_value_t trace; + amduat_pel_node_trace_dag_t nodes[2]; + amduat_reference_t input_refs[3]; + amduat_reference_t output_refs0[1]; + amduat_reference_t output_refs1[1]; + amduat_octets_t encoded; + amduat_pel_trace_dag_value_t decoded; + uint8_t s[32], p[32], r[32], i0[32], i1[32], i2[32], o0[32], o1[32]; + const char add_name[] = "add64"; + const char mul_name[] = "mul64"; + int exit_code = 1; + + memset(&trace, 0, sizeof(trace)); + + 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(0x10, i0); + input_refs[1] = make_ref(0x11, i1); + input_refs[2] = make_ref(0x12, i2); + trace.input_refs = input_refs; + trace.input_refs_len = 3; + + trace.has_params_ref = false; + + output_refs0[0] = make_ref(0x20, o0); + output_refs1[0] = make_ref(0x21, o1); + + nodes[0].node_id = 1; + nodes[0].op_name = amduat_octets(add_name, strlen(add_name)); + nodes[0].op_version = 1; + nodes[0].status = AMDUAT_PEL_NODE_TRACE_OK; + nodes[0].status_code = 0; + nodes[0].output_refs = output_refs0; + nodes[0].output_refs_len = 1; + nodes[0].diagnostics = NULL; + nodes[0].diagnostics_len = 0; + + nodes[1].node_id = 2; + nodes[1].op_name = amduat_octets(mul_name, strlen(mul_name)); + nodes[1].op_version = 1; + nodes[1].status = AMDUAT_PEL_NODE_TRACE_OK; + nodes[1].status_code = 0; + nodes[1].output_refs = output_refs1; + nodes[1].output_refs_len = 1; + nodes[1].diagnostics = NULL; + nodes[1].diagnostics_len = 0; + + trace.node_traces = nodes; + trace.node_traces_len = 2; + + if (!amduat_enc_pel_trace_dag_encode_v1(&trace, &encoded)) { + fprintf(stderr, "encode failed\n"); + return exit_code; + } + + if (!bytes_equal(encoded, k_expected_trace_bytes, + sizeof(k_expected_trace_bytes))) { + fprintf(stderr, "encoded bytes mismatch\n"); + goto cleanup; + } + + if (!amduat_enc_pel_trace_dag_decode_v1(encoded, &decoded)) { + fprintf(stderr, "decode failed\n"); + goto cleanup; + } + + if (decoded.node_traces_len != 2 || decoded.input_refs_len != 3) { + fprintf(stderr, "decoded lengths 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) { + return test_trace_encoding(); +}