From a7ff4ec25a5e0391f28c873ba3f74270a2aaeb30 Mon Sep 17 00:00:00 2001 From: Carl Niklas Rydberg Date: Sat, 20 Dec 2025 15:16:07 +0100 Subject: [PATCH] Implement PEL/1-SURF run with trace artifacts and stub store test --- CMakeLists.txt | 10 + include/amduat/enc/pel1_result.h | 2 + include/amduat/enc/pel_trace_dag.h | 2 + include/amduat/pel/program_dag.h | 26 + include/amduat/pel/surf.h | 16 + src/pel_stack/program_dag/program_dag.c | 153 ++++-- src/pel_stack/surf/surf.c | 516 ++++++++++++++++++ tests/pel/test_pel_surf_run.c | 677 ++++++++++++++++++++++++ 8 files changed, 1357 insertions(+), 45 deletions(-) create mode 100644 tests/pel/test_pel_surf_run.c diff --git a/CMakeLists.txt b/CMakeLists.txt index de712c5..76f733a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -191,3 +191,13 @@ target_link_libraries(amduat_test_pel_program_dag_exec PRIVATE amduat_pel ) add_test(NAME pel_program_dag_exec COMMAND amduat_test_pel_program_dag_exec) + +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} + PRIVATE ${AMDUAT_INCLUDE_DIR} +) +target_link_libraries(amduat_test_pel_surf_run + PRIVATE amduat_pel +) +add_test(NAME pel_surf_run COMMAND amduat_test_pel_surf_run) diff --git a/include/amduat/enc/pel1_result.h b/include/amduat/enc/pel1_result.h index 3bd32a4..274530a 100644 --- a/include/amduat/enc/pel1_result.h +++ b/include/amduat/enc/pel1_result.h @@ -10,6 +10,8 @@ extern "C" { enum { PEL_ENC_EXECUTION_RESULT_V1 = 0x0103u }; enum { AMDUAT_PEL_ENC_EXECUTION_RESULT_V1 = PEL_ENC_EXECUTION_RESULT_V1 }; +enum { TYPE_TAG_PEL1_RESULT_1 = 0x00000103u }; +enum { AMDUAT_TYPE_TAG_PEL1_RESULT_1 = TYPE_TAG_PEL1_RESULT_1 }; /* Caller owns any heap allocations returned in out_bytes/out_result. */ bool amduat_enc_pel1_result_encode_v1( diff --git a/include/amduat/enc/pel_trace_dag.h b/include/amduat/enc/pel_trace_dag.h index 417691f..385e422 100644 --- a/include/amduat/enc/pel_trace_dag.h +++ b/include/amduat/enc/pel_trace_dag.h @@ -10,6 +10,8 @@ extern "C" { enum { PEL_ENC_TRACE_DAG_V1 = 0x0102u }; enum { AMDUAT_PEL_ENC_TRACE_DAG_V1 = PEL_ENC_TRACE_DAG_V1 }; +enum { TYPE_TAG_PEL_TRACE_DAG_1 = 0x00000102u }; +enum { AMDUAT_TYPE_TAG_PEL_TRACE_DAG_1 = TYPE_TAG_PEL_TRACE_DAG_1 }; /* Caller owns any heap allocations returned in out_bytes/out_trace. */ bool amduat_enc_pel_trace_dag_encode_v1( diff --git a/include/amduat/pel/program_dag.h b/include/amduat/pel/program_dag.h index 5373751..616f342 100644 --- a/include/amduat/pel/program_dag.h +++ b/include/amduat/pel/program_dag.h @@ -3,6 +3,7 @@ #include "amduat/asl/core.h" #include "amduat/pel/core.h" +#include "amduat/pel/trace_dag.h" #include #include @@ -61,6 +62,20 @@ typedef struct { size_t roots_len; } amduat_pel_program_t; +typedef struct { + amduat_pel_node_trace_status_t status; + uint32_t status_code; + amduat_artifact_t *outputs; + size_t outputs_len; +} amduat_pel_program_dag_node_result_t; + +typedef struct { + amduat_pel_program_dag_node_result_t *nodes; + size_t nodes_len; + size_t *order; + bool any_node_executed; +} amduat_pel_program_dag_trace_t; + bool amduat_pel_program_dag_validate(const amduat_pel_program_t *program); bool amduat_pel_program_dag_exec( @@ -71,9 +86,20 @@ bool amduat_pel_program_dag_exec( size_t *out_outputs_len, amduat_pel_execution_result_value_t *out_result); +bool amduat_pel_program_dag_exec_trace( + const amduat_pel_program_t *program, + const amduat_artifact_t *inputs, + size_t inputs_len, + amduat_artifact_t **out_outputs, + size_t *out_outputs_len, + amduat_pel_execution_result_value_t *out_result, + amduat_pel_program_dag_trace_t *out_trace); + void amduat_pel_program_dag_free_outputs(amduat_artifact_t *outputs, size_t outputs_len); +void amduat_pel_program_dag_trace_free(amduat_pel_program_dag_trace_t *trace); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/include/amduat/pel/surf.h b/include/amduat/pel/surf.h index 36c9ac4..b83011b 100644 --- a/include/amduat/pel/surf.h +++ b/include/amduat/pel/surf.h @@ -1,6 +1,7 @@ #ifndef AMDUAT_PEL_SURF_H #define AMDUAT_PEL_SURF_H +#include "amduat/asl/store.h" #include "amduat/pel/core.h" #include @@ -48,6 +49,21 @@ typedef struct { amduat_reference_t trace_ref; } amduat_pel_surface_execution_result_t; +bool amduat_pel_surf_run(amduat_asl_store_t *store, + amduat_reference_t scheme_ref, + amduat_reference_t program_ref, + const amduat_reference_t *input_refs, + size_t input_refs_len, + bool has_params_ref, + amduat_reference_t params_ref, + amduat_reference_t **out_output_refs, + size_t *out_output_refs_len, + amduat_reference_t *out_result_ref); + +void amduat_pel_surf_free_refs(amduat_reference_t *refs, size_t refs_len); + +void amduat_pel_surf_free_ref(amduat_reference_t *ref); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/src/pel_stack/program_dag/program_dag.c b/src/pel_stack/program_dag/program_dag.c index c7774b3..3153f2e 100644 --- a/src/pel_stack/program_dag/program_dag.c +++ b/src/pel_stack/program_dag/program_dag.c @@ -10,11 +10,6 @@ #include #include -typedef struct { - amduat_artifact_t *outputs; - size_t outputs_len; -} amduat_pel_node_outputs_t; - typedef struct { size_t *order; const amduat_pel_kernel_op_desc_t **ops; @@ -245,16 +240,17 @@ static bool amduat_build_node_order(const amduat_pel_program_t *program, return true; } -static void amduat_free_node_outputs(amduat_pel_node_outputs_t *node_outputs, - size_t len) { +static void amduat_node_results_free( + amduat_pel_program_dag_node_result_t *node_results, + size_t len) { size_t i; - if (node_outputs == NULL) { + if (node_results == NULL) { return; } for (i = 0; i < len; ++i) { - amduat_pel_node_outputs_t *entry = &node_outputs[i]; + amduat_pel_program_dag_node_result_t *entry = &node_results[i]; size_t j; for (j = 0; j < entry->outputs_len; ++j) { free((void *)entry->outputs[j].bytes.data); @@ -265,7 +261,26 @@ static void amduat_free_node_outputs(amduat_pel_node_outputs_t *node_outputs, entry->outputs = NULL; entry->outputs_len = 0; } - free(node_outputs); + free(node_results); +} + +static void amduat_trace_reset(amduat_pel_program_dag_trace_t *trace) { + if (trace == NULL) { + return; + } + trace->nodes = NULL; + trace->nodes_len = 0; + trace->order = NULL; + trace->any_node_executed = false; +} + +void amduat_pel_program_dag_trace_free(amduat_pel_program_dag_trace_t *trace) { + if (trace == NULL) { + return; + } + amduat_node_results_free(trace->nodes, trace->nodes_len); + free(trace->order); + amduat_trace_reset(trace); } static bool amduat_copy_artifact(amduat_artifact_t *out, @@ -424,18 +439,21 @@ bool amduat_pel_program_dag_validate(const amduat_pel_program_t *program) { return ok; } -bool amduat_pel_program_dag_exec( +static bool amduat_pel_program_dag_exec_internal( const amduat_pel_program_t *program, const amduat_artifact_t *inputs, size_t inputs_len, amduat_artifact_t **out_outputs, size_t *out_outputs_len, - amduat_pel_execution_result_value_t *out_result) { + amduat_pel_execution_result_value_t *out_result, + amduat_pel_program_dag_trace_t *out_trace) { amduat_pel_program_dag_prepared_t prepared; - amduat_pel_node_outputs_t *node_outputs; + amduat_pel_program_dag_node_result_t *node_results; amduat_artifact_t *resolved_inputs; size_t max_inputs; size_t i; + bool any_node_executed = false; + bool wants_trace = out_trace != NULL; if (out_outputs == NULL || out_outputs_len == NULL || out_result == NULL) { return false; @@ -444,10 +462,15 @@ bool amduat_pel_program_dag_exec( *out_outputs = NULL; *out_outputs_len = 0; + if (wants_trace) { + amduat_trace_reset(out_trace); + } + amduat_prepared_reset(&prepared); if (!amduat_program_prepare(program, &prepared)) { amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_INVALID_PROGRAM, AMDUAT_PEL_EXEC_ERROR_PROGRAM, 2); + amduat_prepared_free(&prepared); return true; } @@ -481,14 +504,18 @@ bool amduat_pel_program_dag_exec( return true; } - node_outputs = (amduat_pel_node_outputs_t *)calloc( - program->nodes_len, sizeof(*node_outputs)); - if (node_outputs == NULL) { + node_results = (amduat_pel_program_dag_node_result_t *)calloc( + program->nodes_len, sizeof(*node_results)); + if (node_results == NULL) { amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_RUNTIME_FAILED, AMDUAT_PEL_EXEC_ERROR_RUNTIME, 1); amduat_prepared_free(&prepared); return true; } + for (i = 0; i < program->nodes_len; ++i) { + node_results[i].status = AMDUAT_PEL_NODE_TRACE_SKIPPED; + node_results[i].status_code = 0; + } max_inputs = 0; for (i = 0; i < program->nodes_len; ++i) { @@ -504,7 +531,7 @@ bool amduat_pel_program_dag_exec( if (resolved_inputs == NULL) { amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_RUNTIME_FAILED, AMDUAT_PEL_EXEC_ERROR_RUNTIME, 1); - amduat_free_node_outputs(node_outputs, program->nodes_len); + amduat_node_results_free(node_results, program->nodes_len); amduat_prepared_free(&prepared); return true; } @@ -523,9 +550,7 @@ bool amduat_pel_program_dag_exec( amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_INVALID_INPUTS, AMDUAT_PEL_EXEC_ERROR_INPUTS, 3); free(resolved_inputs); - amduat_free_node_outputs(node_outputs, program->nodes_len); - amduat_prepared_free(&prepared); - return true; + goto finish; } resolved_inputs[j] = inputs[input->value.external.input_index]; } else if (input->kind == AMDUAT_PEL_DAG_INPUT_NODE) { @@ -533,40 +558,40 @@ bool amduat_pel_program_dag_exec( input->value.node.node_id); if (dep_index < 0 || input->value.node.output_index >= - node_outputs[dep_index].outputs_len) { + node_results[dep_index].outputs_len) { amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_INVALID_PROGRAM, AMDUAT_PEL_EXEC_ERROR_PROGRAM, 2); free(resolved_inputs); - amduat_free_node_outputs(node_outputs, program->nodes_len); - amduat_prepared_free(&prepared); - return true; + goto finish; } resolved_inputs[j] = - node_outputs[dep_index].outputs[input->value.node.output_index]; + node_results[dep_index].outputs[input->value.node.output_index]; } else { amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_INVALID_PROGRAM, AMDUAT_PEL_EXEC_ERROR_PROGRAM, 2); free(resolved_inputs); - amduat_free_node_outputs(node_outputs, program->nodes_len); - amduat_prepared_free(&prepared); - return true; + goto finish; } } if (!amduat_pel_kernel_op_eval( prepared.ops[node_index], resolved_inputs, node->inputs_len, - &prepared.params[node_index], &node_outputs[node_index].outputs, - &node_outputs[node_index].outputs_len, &status_code)) { + &prepared.params[node_index], &node_results[node_index].outputs, + &node_results[node_index].outputs_len, &status_code)) { if (status_code == 2 || status_code == 3 || status_code == 0) { status_code = 1; } + node_results[node_index].status = AMDUAT_PEL_NODE_TRACE_FAILED; + node_results[node_index].status_code = status_code; + any_node_executed = true; amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_RUNTIME_FAILED, AMDUAT_PEL_EXEC_ERROR_RUNTIME, status_code); free(resolved_inputs); - amduat_free_node_outputs(node_outputs, program->nodes_len); - amduat_prepared_free(&prepared); - return true; + goto finish; } + node_results[node_index].status = AMDUAT_PEL_NODE_TRACE_OK; + node_results[node_index].status_code = 0; + any_node_executed = true; } if (program->roots_len != 0) { @@ -576,9 +601,7 @@ bool amduat_pel_program_dag_exec( amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_RUNTIME_FAILED, AMDUAT_PEL_EXEC_ERROR_RUNTIME, 1); free(resolved_inputs); - amduat_free_node_outputs(node_outputs, program->nodes_len); - amduat_prepared_free(&prepared); - return true; + goto finish; } } @@ -586,7 +609,7 @@ bool amduat_pel_program_dag_exec( int root_index = amduat_find_node_index(program, program->roots[i].node_id); if (root_index < 0 || program->roots[i].output_index >= - node_outputs[root_index].outputs_len) { + node_results[root_index].outputs_len) { amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_INVALID_PROGRAM, AMDUAT_PEL_EXEC_ERROR_PROGRAM, 2); amduat_pel_program_dag_free_outputs(*out_outputs, @@ -594,13 +617,11 @@ bool amduat_pel_program_dag_exec( *out_outputs = NULL; *out_outputs_len = 0; free(resolved_inputs); - amduat_free_node_outputs(node_outputs, program->nodes_len); - amduat_prepared_free(&prepared); - return true; + goto finish; } if (!amduat_copy_artifact( &(*out_outputs)[i], - &node_outputs[root_index] + &node_results[root_index] .outputs[program->roots[i].output_index])) { amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_RUNTIME_FAILED, AMDUAT_PEL_EXEC_ERROR_RUNTIME, 1); @@ -609,9 +630,7 @@ bool amduat_pel_program_dag_exec( *out_outputs = NULL; *out_outputs_len = 0; free(resolved_inputs); - amduat_free_node_outputs(node_outputs, program->nodes_len); - amduat_prepared_free(&prepared); - return true; + goto finish; } } @@ -620,11 +639,55 @@ bool amduat_pel_program_dag_exec( AMDUAT_PEL_EXEC_ERROR_NONE, 0); free(resolved_inputs); - amduat_free_node_outputs(node_outputs, program->nodes_len); + +finish: + if (wants_trace) { + out_trace->any_node_executed = any_node_executed; + if (any_node_executed) { + out_trace->nodes = node_results; + out_trace->nodes_len = program->nodes_len; + out_trace->order = prepared.order; + prepared.order = NULL; + } else { + amduat_node_results_free(node_results, program->nodes_len); + node_results = NULL; + } + } else { + amduat_node_results_free(node_results, program->nodes_len); + node_results = NULL; + } amduat_prepared_free(&prepared); return true; } +bool amduat_pel_program_dag_exec( + const amduat_pel_program_t *program, + const amduat_artifact_t *inputs, + size_t inputs_len, + amduat_artifact_t **out_outputs, + size_t *out_outputs_len, + amduat_pel_execution_result_value_t *out_result) { + return amduat_pel_program_dag_exec_internal( + program, inputs, inputs_len, out_outputs, out_outputs_len, out_result, + NULL); +} + +bool amduat_pel_program_dag_exec_trace( + const amduat_pel_program_t *program, + const amduat_artifact_t *inputs, + size_t inputs_len, + amduat_artifact_t **out_outputs, + size_t *out_outputs_len, + amduat_pel_execution_result_value_t *out_result, + amduat_pel_program_dag_trace_t *out_trace) { + if (out_trace == NULL) { + return false; + } + return amduat_pel_program_dag_exec_internal( + program, inputs, inputs_len, out_outputs, out_outputs_len, out_result, + out_trace); +} + void amduat_pel_program_dag_free_outputs(amduat_artifact_t *outputs, size_t outputs_len) { size_t i; diff --git a/src/pel_stack/surf/surf.c b/src/pel_stack/surf/surf.c index e69de29..98df43f 100644 --- a/src/pel_stack/surf/surf.c +++ b/src/pel_stack/surf/surf.c @@ -0,0 +1,516 @@ +#include "amduat/pel/surf.h" + +#include "amduat/enc/pel1_result.h" +#include "amduat/enc/pel_program_dag.h" +#include "amduat/enc/pel_trace_dag.h" +#include "amduat/pel/program_dag.h" +#include "amduat/pel/program_dag_desc.h" + +#include +#include +#include +#include +#include + +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; +} + +void amduat_pel_surf_free_refs(amduat_reference_t *refs, size_t refs_len) { + size_t i; + + if (refs == NULL) { + return; + } + for (i = 0; i < refs_len; ++i) { + amduat_reference_free(&refs[i]); + } + free(refs); +} + +void amduat_pel_surf_free_ref(amduat_reference_t *ref) { + amduat_reference_free(ref); +} + +static void amduat_artifact_free(amduat_artifact_t *artifact) { + if (artifact == NULL) { + return; + } + free((void *)artifact->bytes.data); + artifact->bytes.data = NULL; + artifact->bytes.len = 0; +} + +static void amduat_init_core_result(amduat_pel_execution_result_value_t *result, + amduat_reference_t scheme_ref, + amduat_pel_execution_status_t status, + amduat_pel_execution_error_kind_t kind, + uint32_t status_code) { + if (result == NULL) { + return; + } + result->pel1_version = 1; + result->status = status; + result->scheme_ref = scheme_ref; + result->summary.kind = kind; + result->summary.status_code = status_code; + result->diagnostics = NULL; + result->diagnostics_len = 0; +} + +static bool amduat_store_error_map(amduat_asl_store_error_t err, + amduat_pel_store_error_code_t *out_code) { + if (out_code == NULL) { + return false; + } + switch (err) { + case AMDUAT_ASL_STORE_ERR_NOT_FOUND: + *out_code = AMDUAT_PEL_STORE_ERROR_NOT_FOUND; + return true; + case AMDUAT_ASL_STORE_ERR_INTEGRITY: + *out_code = AMDUAT_PEL_STORE_ERROR_INTEGRITY; + return true; + case AMDUAT_ASL_STORE_ERR_UNSUPPORTED: + *out_code = AMDUAT_PEL_STORE_ERROR_UNSUPPORTED; + return true; + default: + return false; + } +} + +static bool amduat_store_surface_result( + amduat_asl_store_t *store, + const amduat_pel_execution_result_value_t *core_result, + amduat_reference_t scheme_ref, + amduat_reference_t program_ref, + const amduat_reference_t *input_refs, + size_t input_refs_len, + const amduat_reference_t *output_refs, + size_t output_refs_len, + bool has_params_ref, + amduat_reference_t params_ref, + bool has_store_failure, + const amduat_pel_store_failure_t *store_failure, + bool has_trace_ref, + amduat_reference_t trace_ref, + amduat_reference_t *out_result_ref) { + amduat_pel_surface_execution_result_t result; + amduat_octets_t encoded; + amduat_artifact_t artifact; + amduat_asl_store_error_t store_err; + + if (store == NULL || core_result == NULL || out_result_ref == NULL) { + return false; + } + + memset(&result, 0, sizeof(result)); + result.pel1_version = 1; + result.core_result = *core_result; + result.scheme_ref = scheme_ref; + result.program_ref = program_ref; + result.input_refs = (amduat_reference_t *)input_refs; + result.input_refs_len = input_refs_len; + result.output_refs = (amduat_reference_t *)output_refs; + result.output_refs_len = output_refs_len; + result.has_params_ref = has_params_ref; + if (has_params_ref) { + result.params_ref = params_ref; + } + result.has_store_failure = has_store_failure; + if (has_store_failure && store_failure != NULL) { + result.store_failure = *store_failure; + } + result.has_trace_ref = has_trace_ref; + if (has_trace_ref) { + result.trace_ref = trace_ref; + } + + encoded = amduat_octets(NULL, 0); + if (!amduat_enc_pel1_result_encode_v1(&result, &encoded)) { + return false; + } + + artifact = amduat_artifact_with_type( + encoded, amduat_type_tag(AMDUAT_TYPE_TAG_PEL1_RESULT_1)); + store_err = amduat_asl_store_put(store, artifact, out_result_ref); + free((void *)encoded.data); + return store_err == AMDUAT_ASL_STORE_OK; +} + +static void amduat_trace_nodes_free(amduat_pel_node_trace_dag_t *nodes, + size_t nodes_len) { + size_t i; + + if (nodes == NULL) { + return; + } + for (i = 0; i < nodes_len; ++i) { + amduat_pel_node_trace_dag_t *node = &nodes[i]; + 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); + node->output_refs = NULL; + node->output_refs_len = 0; + } + } + free(nodes); +} + +static bool amduat_store_trace( + amduat_asl_store_t *store, + amduat_reference_t scheme_ref, + amduat_reference_t program_ref, + const amduat_reference_t *input_refs, + size_t input_refs_len, + bool has_params_ref, + amduat_reference_t params_ref, + const amduat_pel_execution_result_value_t *core_result, + const amduat_pel_program_t *program, + const amduat_pel_program_dag_trace_t *trace_eval, + amduat_reference_t *out_trace_ref) { + amduat_pel_trace_dag_value_t trace; + amduat_pel_node_trace_dag_t *node_traces; + amduat_octets_t encoded; + amduat_artifact_t artifact; + amduat_asl_store_error_t store_err; + size_t node_count; + size_t i; + + if (store == NULL || core_result == NULL || out_trace_ref == NULL) { + return false; + } + + node_traces = NULL; + node_count = 0; + if (program != NULL && trace_eval != NULL && trace_eval->any_node_executed) { + node_count = program->nodes_len; + if (node_count != 0) { + node_traces = (amduat_pel_node_trace_dag_t *)calloc( + node_count, sizeof(*node_traces)); + if (node_traces == NULL) { + return false; + } + } + + for (i = 0; i < node_count; ++i) { + size_t node_index = trace_eval->order[i]; + const amduat_pel_node_t *node = &program->nodes[node_index]; + amduat_pel_program_dag_node_result_t *state = + &trace_eval->nodes[node_index]; + amduat_pel_node_trace_dag_t *trace_node = &node_traces[i]; + + trace_node->node_id = node->id; + trace_node->op_name = node->op.name; + trace_node->op_version = node->op.version; + trace_node->status = state->status; + trace_node->status_code = state->status_code; + trace_node->diagnostics = NULL; + trace_node->diagnostics_len = 0; + + if (state->status == AMDUAT_PEL_NODE_TRACE_OK && + state->outputs_len != 0) { + size_t j; + trace_node->output_refs = (amduat_reference_t *)calloc( + state->outputs_len, sizeof(*trace_node->output_refs)); + if (trace_node->output_refs == NULL) { + amduat_trace_nodes_free(node_traces, node_count); + return false; + } + trace_node->output_refs_len = state->outputs_len; + for (j = 0; j < state->outputs_len; ++j) { + store_err = amduat_asl_store_put(store, state->outputs[j], + &trace_node->output_refs[j]); + if (store_err != AMDUAT_ASL_STORE_OK) { + amduat_trace_nodes_free(node_traces, node_count); + return false; + } + } + } + } + } + + memset(&trace, 0, sizeof(trace)); + trace.pel1_version = 1; + trace.scheme_ref = scheme_ref; + trace.program_ref = program_ref; + trace.status = core_result->status; + trace.summary = core_result->summary; + trace.has_exec_result_ref = false; + trace.input_refs = (amduat_reference_t *)input_refs; + trace.input_refs_len = input_refs_len; + trace.has_params_ref = has_params_ref; + if (has_params_ref) { + trace.params_ref = params_ref; + } + trace.node_traces = node_traces; + trace.node_traces_len = node_count; + + encoded = amduat_octets(NULL, 0); + if (!amduat_enc_pel_trace_dag_encode_v1(&trace, &encoded)) { + amduat_trace_nodes_free(node_traces, node_count); + return false; + } + + artifact = amduat_artifact_with_type( + encoded, amduat_type_tag(AMDUAT_TYPE_TAG_PEL_TRACE_DAG_1)); + store_err = amduat_asl_store_put(store, artifact, out_trace_ref); + free((void *)encoded.data); + amduat_trace_nodes_free(node_traces, node_count); + return store_err == AMDUAT_ASL_STORE_OK; +} + +bool amduat_pel_surf_run(amduat_asl_store_t *store, + amduat_reference_t scheme_ref, + amduat_reference_t program_ref, + const amduat_reference_t *input_refs, + size_t input_refs_len, + bool has_params_ref, + amduat_reference_t params_ref, + amduat_reference_t **out_output_refs, + size_t *out_output_refs_len, + amduat_reference_t *out_result_ref) { + amduat_pel_execution_result_value_t core_result; + amduat_pel_store_failure_t store_failure; + amduat_pel_store_error_code_t store_error_code; + amduat_asl_store_error_t store_err; + amduat_artifact_t program_artifact; + amduat_artifact_t *input_artifacts; + amduat_artifact_t params_artifact; + amduat_pel_program_t program; + amduat_pel_program_dag_trace_t trace_eval; + amduat_artifact_t *outputs; + size_t outputs_len; + amduat_reference_t *output_refs; + size_t output_refs_len; + amduat_reference_t trace_ref; + size_t i; + bool program_decoded = false; + bool has_params_artifact = false; + bool exec_invoked = false; + bool trace_ok = false; + + if (store == NULL || out_output_refs == NULL || + out_output_refs_len == NULL || out_result_ref == NULL) { + return false; + } + if (input_refs_len != 0 && input_refs == NULL) { + return false; + } + + *out_output_refs = NULL; + *out_output_refs_len = 0; + out_result_ref->hash_id = 0; + out_result_ref->digest = amduat_octets(NULL, 0); + trace_ref.hash_id = 0; + trace_ref.digest = amduat_octets(NULL, 0); + + if (!amduat_reference_eq(scheme_ref, + amduat_pel_program_dag_scheme_ref())) { + amduat_init_core_result(&core_result, scheme_ref, + AMDUAT_PEL_EXEC_STATUS_SCHEME_UNSUPPORTED, + AMDUAT_PEL_EXEC_ERROR_SCHEME, 1); + return amduat_store_surface_result(store, &core_result, scheme_ref, + program_ref, input_refs, input_refs_len, + NULL, 0, has_params_ref, params_ref, + false, NULL, false, trace_ref, + out_result_ref); + } + + store_err = amduat_asl_store_get(store, program_ref, &program_artifact); + if (store_err != AMDUAT_ASL_STORE_OK) { + if (!amduat_store_error_map(store_err, &store_error_code)) { + return false; + } + amduat_init_core_result(&core_result, scheme_ref, + AMDUAT_PEL_EXEC_STATUS_INVALID_PROGRAM, + AMDUAT_PEL_EXEC_ERROR_PROGRAM, 2); + store_failure.phase = AMDUAT_PEL_STORE_FAILURE_PROGRAM; + store_failure.error_code = store_error_code; + store_failure.failing_ref = program_ref; + return amduat_store_surface_result( + store, &core_result, scheme_ref, program_ref, input_refs, + input_refs_len, NULL, 0, has_params_ref, params_ref, true, + &store_failure, false, trace_ref, out_result_ref); + } + + input_artifacts = NULL; + if (input_refs_len != 0) { + input_artifacts = (amduat_artifact_t *)calloc( + input_refs_len, sizeof(*input_artifacts)); + if (input_artifacts == NULL) { + amduat_artifact_free(&program_artifact); + return false; + } + } + + for (i = 0; i < input_refs_len; ++i) { + store_err = amduat_asl_store_get(store, input_refs[i], + &input_artifacts[i]); + if (store_err != AMDUAT_ASL_STORE_OK) { + size_t j; + if (!amduat_store_error_map(store_err, &store_error_code)) { + amduat_artifact_free(&program_artifact); + free(input_artifacts); + return false; + } + for (j = 0; j < i; ++j) { + amduat_artifact_free(&input_artifacts[j]); + } + free(input_artifacts); + amduat_artifact_free(&program_artifact); + amduat_init_core_result(&core_result, scheme_ref, + AMDUAT_PEL_EXEC_STATUS_INVALID_INPUTS, + AMDUAT_PEL_EXEC_ERROR_INPUTS, 3); + store_failure.phase = AMDUAT_PEL_STORE_FAILURE_INPUT; + store_failure.error_code = store_error_code; + store_failure.failing_ref = input_refs[i]; + return amduat_store_surface_result( + store, &core_result, scheme_ref, program_ref, input_refs, + input_refs_len, NULL, 0, has_params_ref, params_ref, true, + &store_failure, false, trace_ref, out_result_ref); + } + } + + if (has_params_ref) { + store_err = amduat_asl_store_get(store, params_ref, ¶ms_artifact); + if (store_err != AMDUAT_ASL_STORE_OK) { + if (!amduat_store_error_map(store_err, &store_error_code)) { + amduat_artifact_free(&program_artifact); + for (i = 0; i < input_refs_len; ++i) { + amduat_artifact_free(&input_artifacts[i]); + } + free(input_artifacts); + return false; + } + amduat_artifact_free(&program_artifact); + for (i = 0; i < input_refs_len; ++i) { + amduat_artifact_free(&input_artifacts[i]); + } + free(input_artifacts); + amduat_init_core_result(&core_result, scheme_ref, + AMDUAT_PEL_EXEC_STATUS_INVALID_INPUTS, + AMDUAT_PEL_EXEC_ERROR_INPUTS, 3); + store_failure.phase = AMDUAT_PEL_STORE_FAILURE_INPUT; + store_failure.error_code = store_error_code; + store_failure.failing_ref = params_ref; + return amduat_store_surface_result( + store, &core_result, scheme_ref, program_ref, input_refs, + input_refs_len, NULL, 0, has_params_ref, params_ref, true, + &store_failure, false, trace_ref, out_result_ref); + } + has_params_artifact = true; + } + + exec_invoked = true; + outputs = NULL; + outputs_len = 0; + memset(&trace_eval, 0, sizeof(trace_eval)); + if (!program_artifact.has_type_tag || + program_artifact.type_tag.tag_id != + AMDUAT_PEL_TYPE_TAG_PROGRAM_DAG_1) { + amduat_init_core_result(&core_result, scheme_ref, + AMDUAT_PEL_EXEC_STATUS_INVALID_PROGRAM, + AMDUAT_PEL_EXEC_ERROR_PROGRAM, 2); + } else if (!amduat_enc_pel_program_dag_decode_v1(program_artifact.bytes, + &program)) { + amduat_init_core_result(&core_result, scheme_ref, + AMDUAT_PEL_EXEC_STATUS_INVALID_PROGRAM, + AMDUAT_PEL_EXEC_ERROR_PROGRAM, 2); + } else { + program_decoded = true; + if (!amduat_pel_program_dag_exec_trace( + &program, input_artifacts, input_refs_len, &outputs, &outputs_len, + &core_result, &trace_eval)) { + amduat_artifact_free(&program_artifact); + amduat_enc_pel_program_dag_free(&program); + for (i = 0; i < input_refs_len; ++i) { + amduat_artifact_free(&input_artifacts[i]); + } + free(input_artifacts); + if (has_params_artifact) { + amduat_artifact_free(¶ms_artifact); + } + amduat_pel_program_dag_free_outputs(outputs, outputs_len); + return false; + } + } + + amduat_artifact_free(&program_artifact); + + output_refs = NULL; + output_refs_len = outputs_len; + if (outputs_len != 0) { + output_refs = (amduat_reference_t *)calloc(outputs_len, sizeof(*output_refs)); + if (output_refs == NULL) { + trace_ok = false; + goto cleanup; + } + for (i = 0; i < outputs_len; ++i) { + store_err = amduat_asl_store_put(store, outputs[i], &output_refs[i]); + if (store_err != AMDUAT_ASL_STORE_OK) { + trace_ok = false; + goto cleanup; + } + } + } + + trace_ok = false; + if (exec_invoked) { + trace_ok = amduat_store_trace( + store, scheme_ref, program_ref, input_refs, input_refs_len, + has_params_ref, params_ref, &core_result, + program_decoded ? &program : NULL, + program_decoded ? &trace_eval : NULL, &trace_ref); + if (!trace_ok) { + goto cleanup; + } + } + + if (!amduat_store_surface_result( + store, &core_result, scheme_ref, program_ref, input_refs, + input_refs_len, output_refs, output_refs_len, has_params_ref, + params_ref, false, NULL, trace_ok, trace_ref, out_result_ref)) { + goto cleanup; + } + + *out_output_refs = output_refs; + *out_output_refs_len = output_refs_len; + + if (program_decoded) { + amduat_enc_pel_program_dag_free(&program); + amduat_pel_program_dag_trace_free(&trace_eval); + } + for (i = 0; i < input_refs_len; ++i) { + amduat_artifact_free(&input_artifacts[i]); + } + free(input_artifacts); + if (has_params_artifact) { + amduat_artifact_free(¶ms_artifact); + } + amduat_pel_program_dag_free_outputs(outputs, outputs_len); + return true; + +cleanup: + amduat_pel_surf_free_refs(output_refs, output_refs_len); + if (program_decoded) { + amduat_enc_pel_program_dag_free(&program); + amduat_pel_program_dag_trace_free(&trace_eval); + } + for (i = 0; i < input_refs_len; ++i) { + amduat_artifact_free(&input_artifacts[i]); + } + free(input_artifacts); + if (has_params_artifact) { + amduat_artifact_free(¶ms_artifact); + } + amduat_pel_program_dag_free_outputs(outputs, outputs_len); + return false; +} diff --git a/tests/pel/test_pel_surf_run.c b/tests/pel/test_pel_surf_run.c new file mode 100644 index 0000000..4e1261a --- /dev/null +++ b/tests/pel/test_pel_surf_run.c @@ -0,0 +1,677 @@ +#include "amduat/asl/store.h" +#include "amduat/enc/asl1_core.h" +#include "amduat/enc/asl1_core_codec.h" +#include "amduat/enc/pel1_result.h" +#include "amduat/enc/pel_program_dag.h" +#include "amduat/enc/pel_trace_dag.h" +#include "amduat/hash/asl1.h" +#include "amduat/pel/program_dag.h" +#include "amduat/pel/program_dag_desc.h" +#include "amduat/pel/surf.h" + +#include +#include +#include +#include +#include + +typedef struct { + amduat_reference_t ref; + amduat_artifact_t artifact; +} stub_store_entry_t; + +typedef struct { + stub_store_entry_t *entries; + size_t len; + size_t cap; + amduat_asl_store_config_t config; +} stub_store_t; + +static void stub_store_init(stub_store_t *store) { + if (store == NULL) { + return; + } + store->entries = NULL; + store->len = 0; + store->cap = 0; + store->config.encoding_profile_id = 0; + store->config.hash_id = 0; +} + +static void stub_store_free(stub_store_t *store) { + size_t i; + + if (store == NULL) { + return; + } + for (i = 0; i < store->len; ++i) { + stub_store_entry_t *entry = &store->entries[i]; + free((void *)entry->ref.digest.data); + entry->ref.digest.data = NULL; + entry->ref.digest.len = 0; + free((void *)entry->artifact.bytes.data); + entry->artifact.bytes.data = NULL; + entry->artifact.bytes.len = 0; + } + free(store->entries); + store->entries = NULL; + store->len = 0; + store->cap = 0; +} + +static bool artifact_eq(const amduat_artifact_t *a, + const amduat_artifact_t *b) { + if (a == NULL || b == NULL) { + return false; + } + if (a->has_type_tag != b->has_type_tag) { + return false; + } + if (a->has_type_tag && a->type_tag.tag_id != b->type_tag.tag_id) { + return false; + } + if (a->bytes.len != b->bytes.len) { + return false; + } + if (a->bytes.len != 0) { + if (a->bytes.data == NULL || b->bytes.data == NULL) { + return false; + } + if (memcmp(a->bytes.data, b->bytes.data, a->bytes.len) != 0) { + return false; + } + } + return true; +} + +static bool stub_store_add_entry(stub_store_t *store, + amduat_reference_t stored_ref, + amduat_artifact_t stored_artifact) { + stub_store_entry_t *entries; + size_t new_cap; + + if (store->len == store->cap) { + new_cap = store->cap == 0 ? 8 : store->cap * 2; + entries = (stub_store_entry_t *)realloc(store->entries, + new_cap * sizeof(*entries)); + if (entries == NULL) { + return false; + } + store->entries = entries; + store->cap = new_cap; + } + + store->entries[store->len++] = + (stub_store_entry_t){stored_ref, stored_artifact}; + return true; +} + +static amduat_asl_store_error_t stub_store_put( + void *ctx, + amduat_artifact_t artifact, + amduat_reference_t *out_ref) { + stub_store_t *store; + amduat_octets_t encoded; + const amduat_hash_asl1_desc_t *hash_desc; + uint8_t *digest_store = NULL; + uint8_t *digest_out = NULL; + uint8_t *payload; + amduat_reference_t stored_ref; + amduat_artifact_t stored_artifact; + size_t i; + + if (ctx == NULL || out_ref == NULL) { + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + store = (stub_store_t *)ctx; + out_ref->hash_id = 0; + out_ref->digest = amduat_octets(NULL, 0); + + if (store->config.encoding_profile_id != AMDUAT_ENC_ASL1_CORE_V1) { + return AMDUAT_ASL_STORE_ERR_UNSUPPORTED; + } + encoded = amduat_octets(NULL, 0); + if (!amduat_enc_asl1_core_encode_artifact_v1(artifact, &encoded)) { + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + + hash_desc = amduat_hash_asl1_desc_lookup(store->config.hash_id); + if (hash_desc == NULL || hash_desc->digest_len == 0) { + free((void *)encoded.data); + return AMDUAT_ASL_STORE_ERR_UNSUPPORTED; + } + + digest_store = (uint8_t *)malloc(hash_desc->digest_len); + digest_out = (uint8_t *)malloc(hash_desc->digest_len); + if (digest_store == NULL || digest_out == NULL) { + free((void *)encoded.data); + free(digest_store); + free(digest_out); + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + if (!amduat_hash_asl1_digest(store->config.hash_id, encoded, digest_store, + hash_desc->digest_len)) { + free((void *)encoded.data); + free(digest_store); + free(digest_out); + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + memcpy(digest_out, digest_store, hash_desc->digest_len); + free((void *)encoded.data); + + stored_ref.hash_id = store->config.hash_id; + stored_ref.digest = amduat_octets(digest_store, hash_desc->digest_len); + out_ref->hash_id = store->config.hash_id; + out_ref->digest = amduat_octets(digest_out, hash_desc->digest_len); + + for (i = 0; i < store->len; ++i) { + stub_store_entry_t *entry = &store->entries[i]; + if (amduat_reference_eq(entry->ref, stored_ref)) { + if (!artifact_eq(&entry->artifact, &artifact)) { + free(digest_store); + free(digest_out); + out_ref->hash_id = 0; + out_ref->digest = amduat_octets(NULL, 0); + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + free(digest_store); + return AMDUAT_ASL_STORE_OK; + } + } + + payload = NULL; + if (artifact.bytes.len != 0) { + if (artifact.bytes.data == NULL) { + free(digest_store); + free(digest_out); + out_ref->hash_id = 0; + out_ref->digest = amduat_octets(NULL, 0); + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + payload = (uint8_t *)malloc(artifact.bytes.len); + if (payload == NULL) { + free(digest_store); + free(digest_out); + out_ref->hash_id = 0; + out_ref->digest = amduat_octets(NULL, 0); + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + memcpy(payload, artifact.bytes.data, artifact.bytes.len); + } + stored_artifact.bytes = amduat_octets(payload, artifact.bytes.len); + stored_artifact.has_type_tag = artifact.has_type_tag; + stored_artifact.type_tag = artifact.type_tag; + + if (!stub_store_add_entry(store, stored_ref, stored_artifact)) { + free(payload); + free(digest_store); + free(digest_out); + out_ref->hash_id = 0; + out_ref->digest = amduat_octets(NULL, 0); + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + + return AMDUAT_ASL_STORE_OK; +} + +static amduat_asl_store_error_t stub_store_get( + void *ctx, + amduat_reference_t ref, + amduat_artifact_t *out_artifact) { + stub_store_t *store; + size_t i; + + if (ctx == NULL || out_artifact == NULL) { + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + store = (stub_store_t *)ctx; + + for (i = 0; i < store->len; ++i) { + stub_store_entry_t *entry = &store->entries[i]; + if (amduat_reference_eq(entry->ref, ref)) { + uint8_t *payload = NULL; + if (entry->artifact.bytes.len != 0) { + payload = (uint8_t *)malloc(entry->artifact.bytes.len); + if (payload == NULL) { + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + memcpy(payload, entry->artifact.bytes.data, entry->artifact.bytes.len); + } + out_artifact->bytes = amduat_octets(payload, + entry->artifact.bytes.len); + out_artifact->has_type_tag = entry->artifact.has_type_tag; + out_artifact->type_tag = entry->artifact.type_tag; + return AMDUAT_ASL_STORE_OK; + } + } + + return AMDUAT_ASL_STORE_ERR_NOT_FOUND; +} + +static void artifact_free(amduat_artifact_t *artifact) { + if (artifact == NULL) { + return; + } + free((void *)artifact->bytes.data); + artifact->bytes.data = NULL; + artifact->bytes.len = 0; +} + +static void store_u64_be(uint8_t *out, uint64_t value) { + out[0] = (uint8_t)((value >> 56) & 0xffu); + out[1] = (uint8_t)((value >> 48) & 0xffu); + out[2] = (uint8_t)((value >> 40) & 0xffu); + out[3] = (uint8_t)((value >> 32) & 0xffu); + out[4] = (uint8_t)((value >> 24) & 0xffu); + out[5] = (uint8_t)((value >> 16) & 0xffu); + out[6] = (uint8_t)((value >> 8) & 0xffu); + out[7] = (uint8_t)(value & 0xffu); +} + +static amduat_octets_t make_const_params(const uint8_t *bytes, size_t len) { + size_t total = 1 + 8 + len; + uint8_t *buffer = (uint8_t *)malloc(total); + if (buffer == NULL) { + return amduat_octets(NULL, 0); + } + buffer[0] = 0x00u; + store_u64_be(buffer + 1, (uint64_t)len); + if (len != 0 && bytes != NULL) { + memcpy(buffer + 1 + 8, bytes, len); + } + return amduat_octets(buffer, total); +} + +static bool build_const_program_artifact(amduat_artifact_t *out_artifact) { + amduat_pel_node_t nodes[1]; + amduat_pel_root_ref_t roots[1]; + amduat_pel_program_t program; + amduat_octets_t params; + amduat_octets_t encoded; + const char op_const[] = "pel.bytes.const"; + const uint8_t payload[] = {'h', 'i'}; + + params = make_const_params(payload, sizeof(payload)); + if (params.data == NULL) { + return false; + } + + nodes[0].id = 1; + nodes[0].op.name = amduat_octets(op_const, strlen(op_const)); + nodes[0].op.version = 1; + nodes[0].inputs = NULL; + nodes[0].inputs_len = 0; + nodes[0].params = params; + + roots[0].node_id = 1; + roots[0].output_index = 0; + + program.nodes = nodes; + program.nodes_len = 1; + program.roots = roots; + program.roots_len = 1; + + encoded = amduat_octets(NULL, 0); + if (!amduat_enc_pel_program_dag_encode_v1(&program, &encoded)) { + free((void *)params.data); + return false; + } + + *out_artifact = amduat_artifact_with_type( + encoded, amduat_type_tag(AMDUAT_PEL_TYPE_TAG_PROGRAM_DAG_1)); + free((void *)params.data); + return true; +} + +static bool build_concat_program_artifact(amduat_artifact_t *out_artifact) { + amduat_pel_dag_input_t inputs[1]; + amduat_pel_node_t nodes[1]; + amduat_pel_root_ref_t roots[1]; + amduat_pel_program_t program; + amduat_octets_t encoded; + const char op_concat[] = "pel.bytes.concat"; + + inputs[0].kind = AMDUAT_PEL_DAG_INPUT_EXTERNAL; + inputs[0].value.external.input_index = 0; + + nodes[0].id = 1; + nodes[0].op.name = amduat_octets(op_concat, strlen(op_concat)); + nodes[0].op.version = 1; + nodes[0].inputs = inputs; + nodes[0].inputs_len = 1; + nodes[0].params = amduat_octets(NULL, 0); + + roots[0].node_id = 1; + roots[0].output_index = 0; + + program.nodes = nodes; + program.nodes_len = 1; + program.roots = roots; + program.roots_len = 1; + + encoded = amduat_octets(NULL, 0); + if (!amduat_enc_pel_program_dag_encode_v1(&program, &encoded)) { + return false; + } + + *out_artifact = amduat_artifact_with_type( + encoded, amduat_type_tag(AMDUAT_PEL_TYPE_TAG_PROGRAM_DAG_1)); + return true; +} + +static amduat_reference_t make_ref(uint8_t seed) { + uint8_t *digest = (uint8_t *)malloc(32); + if (digest == NULL) { + return amduat_reference(0, amduat_octets(NULL, 0)); + } + memset(digest, seed, 32); + return amduat_reference(AMDUAT_HASH_ASL1_ID_SHA256, + amduat_octets(digest, 32)); +} + +static int test_surf_success(void) { + stub_store_t stub; + amduat_asl_store_t store; + amduat_asl_store_ops_t ops; + amduat_asl_store_config_t cfg; + amduat_artifact_t program_artifact; + amduat_reference_t program_ref; + amduat_reference_t *output_refs = NULL; + size_t output_refs_len = 0; + amduat_reference_t result_ref; + amduat_artifact_t result_artifact; + amduat_pel_surface_execution_result_t decoded; + amduat_artifact_t trace_artifact; + amduat_pel_trace_dag_value_t trace; + const char op_const[] = "pel.bytes.const"; + int exit_code = 1; + + cfg.encoding_profile_id = AMDUAT_ENC_ASL1_CORE_V1; + cfg.hash_id = AMDUAT_HASH_ASL1_ID_SHA256; + stub_store_init(&stub); + stub.config = cfg; + ops.put = stub_store_put; + ops.get = stub_store_get; + amduat_asl_store_init(&store, cfg, ops, &stub); + + if (!build_const_program_artifact(&program_artifact)) { + fprintf(stderr, "build program failed\n"); + goto cleanup_store; + } + if (stub_store_put(&stub, program_artifact, &program_ref) != + AMDUAT_ASL_STORE_OK) { + fprintf(stderr, "program put failed\n"); + free((void *)program_artifact.bytes.data); + goto cleanup_store; + } + free((void *)program_artifact.bytes.data); + + if (!amduat_pel_surf_run(&store, amduat_pel_program_dag_scheme_ref(), + program_ref, NULL, 0, false, + amduat_reference(0, amduat_octets(NULL, 0)), + &output_refs, &output_refs_len, &result_ref)) { + fprintf(stderr, "surf run failed\n"); + goto cleanup_refs; + } + + if (output_refs_len != 1) { + fprintf(stderr, "unexpected output ref count\n"); + goto cleanup_refs; + } + + if (stub_store_get(&stub, result_ref, &result_artifact) != + AMDUAT_ASL_STORE_OK) { + fprintf(stderr, "result get failed\n"); + goto cleanup_refs; + } + if (!result_artifact.has_type_tag || + result_artifact.type_tag.tag_id != AMDUAT_TYPE_TAG_PEL1_RESULT_1) { + fprintf(stderr, "result type tag mismatch\n"); + artifact_free(&result_artifact); + goto cleanup_refs; + } + if (!amduat_enc_pel1_result_decode_v1(result_artifact.bytes, &decoded)) { + fprintf(stderr, "result decode failed\n"); + artifact_free(&result_artifact); + goto cleanup_refs; + } + artifact_free(&result_artifact); + + if (decoded.core_result.status != AMDUAT_PEL_EXEC_STATUS_OK || + decoded.core_result.summary.kind != AMDUAT_PEL_EXEC_ERROR_NONE || + decoded.core_result.summary.status_code != 0) { + fprintf(stderr, "unexpected core status\n"); + goto cleanup_decoded; + } + if (!decoded.has_trace_ref) { + fprintf(stderr, "missing trace ref\n"); + goto cleanup_decoded; + } + if (decoded.output_refs_len != 1 || + !amduat_reference_eq(decoded.output_refs[0], output_refs[0])) { + fprintf(stderr, "output refs mismatch\n"); + goto cleanup_decoded; + } + + if (stub_store_get(&stub, decoded.trace_ref, &trace_artifact) != + AMDUAT_ASL_STORE_OK) { + fprintf(stderr, "trace get failed\n"); + goto cleanup_decoded; + } + if (!trace_artifact.has_type_tag || + trace_artifact.type_tag.tag_id != AMDUAT_TYPE_TAG_PEL_TRACE_DAG_1) { + fprintf(stderr, "trace type tag mismatch\n"); + artifact_free(&trace_artifact); + goto cleanup_decoded; + } + if (!amduat_enc_pel_trace_dag_decode_v1(trace_artifact.bytes, &trace)) { + fprintf(stderr, "trace decode failed\n"); + artifact_free(&trace_artifact); + goto cleanup_decoded; + } + artifact_free(&trace_artifact); + + if (trace.node_traces_len != 1 || + trace.node_traces[0].status != AMDUAT_PEL_NODE_TRACE_OK || + trace.node_traces[0].output_refs_len != 1 || + !amduat_reference_eq(trace.node_traces[0].output_refs[0], + output_refs[0]) || + trace.node_traces[0].op_name.len != strlen(op_const) || + memcmp(trace.node_traces[0].op_name.data, + op_const, trace.node_traces[0].op_name.len) != 0) { + fprintf(stderr, "trace node mismatch\n"); + amduat_enc_pel_trace_dag_free(&trace); + goto cleanup_decoded; + } + + amduat_enc_pel_trace_dag_free(&trace); + exit_code = 0; + +cleanup_decoded: + amduat_enc_pel1_result_free(&decoded); +cleanup_refs: + amduat_pel_surf_free_refs(output_refs, output_refs_len); + amduat_pel_surf_free_ref(&result_ref); + amduat_pel_surf_free_ref(&program_ref); +cleanup_store: + stub_store_free(&stub); + return exit_code; +} + +static int test_surf_missing_program(void) { + stub_store_t stub; + amduat_asl_store_t store; + amduat_asl_store_ops_t ops; + amduat_asl_store_config_t cfg; + amduat_reference_t program_ref; + amduat_reference_t *output_refs = NULL; + size_t output_refs_len = 0; + amduat_reference_t result_ref; + amduat_artifact_t result_artifact; + amduat_pel_surface_execution_result_t decoded; + int exit_code = 1; + + cfg.encoding_profile_id = AMDUAT_ENC_ASL1_CORE_V1; + cfg.hash_id = AMDUAT_HASH_ASL1_ID_SHA256; + stub_store_init(&stub); + stub.config = cfg; + ops.put = stub_store_put; + ops.get = stub_store_get; + amduat_asl_store_init(&store, cfg, ops, &stub); + + program_ref = make_ref(0x42u); + if (program_ref.digest.data == NULL) { + goto cleanup_store; + } + + if (!amduat_pel_surf_run(&store, amduat_pel_program_dag_scheme_ref(), + program_ref, NULL, 0, false, + amduat_reference(0, amduat_octets(NULL, 0)), + &output_refs, &output_refs_len, &result_ref)) { + fprintf(stderr, "surf run failed\n"); + goto cleanup_refs; + } + + if (output_refs_len != 0) { + fprintf(stderr, "unexpected output refs\n"); + goto cleanup_refs; + } + + if (stub_store_get(&stub, result_ref, &result_artifact) != + AMDUAT_ASL_STORE_OK) { + fprintf(stderr, "result get failed\n"); + goto cleanup_refs; + } + if (!amduat_enc_pel1_result_decode_v1(result_artifact.bytes, &decoded)) { + artifact_free(&result_artifact); + fprintf(stderr, "result decode failed\n"); + goto cleanup_refs; + } + artifact_free(&result_artifact); + + if (decoded.core_result.status != AMDUAT_PEL_EXEC_STATUS_INVALID_PROGRAM || + decoded.core_result.summary.kind != AMDUAT_PEL_EXEC_ERROR_PROGRAM || + decoded.core_result.summary.status_code != 2 || + !decoded.has_store_failure || + decoded.store_failure.phase != AMDUAT_PEL_STORE_FAILURE_PROGRAM || + decoded.store_failure.error_code != AMDUAT_PEL_STORE_ERROR_NOT_FOUND || + !amduat_reference_eq(decoded.store_failure.failing_ref, program_ref) || + decoded.has_trace_ref) { + fprintf(stderr, "missing program mapping mismatch\n"); + goto cleanup_decoded; + } + + exit_code = 0; + +cleanup_decoded: + amduat_enc_pel1_result_free(&decoded); +cleanup_refs: + amduat_pel_surf_free_refs(output_refs, output_refs_len); + amduat_pel_surf_free_ref(&result_ref); + amduat_pel_surf_free_ref(&program_ref); +cleanup_store: + stub_store_free(&stub); + return exit_code; +} + +static int test_surf_missing_input(void) { + stub_store_t stub; + amduat_asl_store_t store; + amduat_asl_store_ops_t ops; + amduat_asl_store_config_t cfg; + amduat_artifact_t program_artifact; + amduat_reference_t program_ref; + amduat_reference_t input_ref; + amduat_reference_t *output_refs = NULL; + size_t output_refs_len = 0; + amduat_reference_t result_ref; + amduat_artifact_t result_artifact; + amduat_pel_surface_execution_result_t decoded; + int exit_code = 1; + + cfg.encoding_profile_id = AMDUAT_ENC_ASL1_CORE_V1; + cfg.hash_id = AMDUAT_HASH_ASL1_ID_SHA256; + stub_store_init(&stub); + stub.config = cfg; + ops.put = stub_store_put; + ops.get = stub_store_get; + amduat_asl_store_init(&store, cfg, ops, &stub); + + if (!build_concat_program_artifact(&program_artifact)) { + goto cleanup_store; + } + if (stub_store_put(&stub, program_artifact, &program_ref) != + AMDUAT_ASL_STORE_OK) { + free((void *)program_artifact.bytes.data); + goto cleanup_store; + } + free((void *)program_artifact.bytes.data); + + input_ref = make_ref(0x33u); + if (input_ref.digest.data == NULL) { + goto cleanup_refs; + } + + if (!amduat_pel_surf_run(&store, amduat_pel_program_dag_scheme_ref(), + program_ref, &input_ref, 1, false, + amduat_reference(0, amduat_octets(NULL, 0)), + &output_refs, &output_refs_len, &result_ref)) { + fprintf(stderr, "surf run failed\n"); + goto cleanup_refs; + } + + if (output_refs_len != 0) { + fprintf(stderr, "unexpected output refs\n"); + goto cleanup_refs; + } + + if (stub_store_get(&stub, result_ref, &result_artifact) != + AMDUAT_ASL_STORE_OK) { + fprintf(stderr, "result get failed\n"); + goto cleanup_refs; + } + if (!amduat_enc_pel1_result_decode_v1(result_artifact.bytes, &decoded)) { + artifact_free(&result_artifact); + fprintf(stderr, "result decode failed\n"); + goto cleanup_refs; + } + artifact_free(&result_artifact); + + if (decoded.core_result.status != AMDUAT_PEL_EXEC_STATUS_INVALID_INPUTS || + decoded.core_result.summary.kind != AMDUAT_PEL_EXEC_ERROR_INPUTS || + decoded.core_result.summary.status_code != 3 || + !decoded.has_store_failure || + decoded.store_failure.phase != AMDUAT_PEL_STORE_FAILURE_INPUT || + decoded.store_failure.error_code != AMDUAT_PEL_STORE_ERROR_NOT_FOUND || + !amduat_reference_eq(decoded.store_failure.failing_ref, input_ref) || + decoded.has_trace_ref) { + fprintf(stderr, "missing input mapping mismatch\n"); + goto cleanup_decoded; + } + + exit_code = 0; + +cleanup_decoded: + amduat_enc_pel1_result_free(&decoded); +cleanup_refs: + amduat_pel_surf_free_refs(output_refs, output_refs_len); + amduat_pel_surf_free_ref(&result_ref); + amduat_pel_surf_free_ref(&program_ref); + amduat_pel_surf_free_ref(&input_ref); +cleanup_store: + stub_store_free(&stub); + return exit_code; +} + +int main(void) { + if (test_surf_success() != 0) { + return 1; + } + if (test_surf_missing_program() != 0) { + return 1; + } + if (test_surf_missing_input() != 0) { + return 1; + } + return 0; +}