Implement PEL encodings and tests

This commit is contained in:
Carl Niklas Rydberg 2025-12-20 13:54:18 +01:00
parent 96bf3f08b3
commit 585844a6fc
14 changed files with 2876 additions and 0 deletions

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,56 @@
#ifndef AMDUAT_PEL_CORE_H
#define AMDUAT_PEL_CORE_H
#include "amduat/asl/core.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#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 */

View file

@ -0,0 +1,67 @@
#ifndef AMDUAT_PEL_PROGRAM_DAG_H
#define AMDUAT_PEL_PROGRAM_DAG_H
#include "amduat/asl/core.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#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 */

View file

@ -0,0 +1,55 @@
#ifndef AMDUAT_PEL_SURF_H
#define AMDUAT_PEL_SURF_H
#include "amduat/pel/core.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#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 */

View file

@ -0,0 +1,54 @@
#ifndef AMDUAT_PEL_TRACE_DAG_H
#define AMDUAT_PEL_TRACE_DAG_H
#include "amduat/pel/core.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#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 */

View file

@ -0,0 +1,734 @@
#include "amduat/enc/pel1_result.h"
#include "amduat/enc/asl1_core_codec.h"
#include "amduat/hash/asl1.h"
#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
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;
}

View file

@ -0,0 +1,666 @@
#include "amduat/enc/pel_program_dag.h"
#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
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, &params_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;
}

View file

@ -0,0 +1,775 @@
#include "amduat/enc/pel_trace_dag.h"
#include "amduat/enc/asl1_core_codec.h"
#include "amduat/hash/asl1.h"
#include <limits.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
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;
}

View file

@ -0,0 +1,126 @@
#include "amduat/enc/pel1_result.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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();
}

View file

@ -0,0 +1,113 @@
#include "amduat/enc/pel_program_dag.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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();
}

View file

@ -0,0 +1,155 @@
#include "amduat/enc/pel_trace_dag.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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();
}