Add PEL program DAG validation and kernel op execution

This commit is contained in:
Carl Niklas Rydberg 2025-12-20 14:27:26 +01:00
parent 585844a6fc
commit a6425067bf
10 changed files with 1681 additions and 0 deletions

View file

@ -180,3 +180,14 @@ target_link_libraries(amduat_test_pel1_result
PRIVATE amduat_enc amduat_hash_asl1 amduat_asl amduat_util PRIVATE amduat_enc amduat_hash_asl1 amduat_asl amduat_util
) )
add_test(NAME pel1_result COMMAND amduat_test_pel1_result) add_test(NAME pel1_result COMMAND amduat_test_pel1_result)
add_executable(amduat_test_pel_program_dag_exec
tests/pel/test_pel_program_dag_exec.c)
target_include_directories(amduat_test_pel_program_dag_exec
PRIVATE ${AMDUAT_INTERNAL_DIR}
PRIVATE ${AMDUAT_INCLUDE_DIR}
)
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)

View file

@ -0,0 +1,66 @@
#ifndef AMDUAT_PEL_OPREG_KERNEL_H
#define AMDUAT_PEL_OPREG_KERNEL_H
#include "amduat/asl/core.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define AMDUAT_PEL_KERNEL_OP_CONCAT_NAME "pel.bytes.concat"
#define AMDUAT_PEL_KERNEL_OP_SLICE_NAME "pel.bytes.slice"
#define AMDUAT_PEL_KERNEL_OP_CONST_NAME "pel.bytes.const"
#define AMDUAT_PEL_KERNEL_OP_HASH_ASL1_NAME "pel.bytes.hash.asl1"
enum {
AMDUAT_PEL_KERNEL_OP_CODE_CONCAT = 0x0001u,
AMDUAT_PEL_KERNEL_OP_CODE_SLICE = 0x0002u,
AMDUAT_PEL_KERNEL_OP_CODE_CONST = 0x0003u,
AMDUAT_PEL_KERNEL_OP_CODE_HASH_ASL1 = 0x0004u
};
enum {
AMDUAT_PEL_KERNEL_STATUS_CONCAT_TYPE_TAG_MISMATCH = 0x00010001u,
AMDUAT_PEL_KERNEL_STATUS_SLICE_RANGE_OUT_OF_BOUNDS = 0x00020001u
};
typedef enum {
AMDUAT_PEL_KERNEL_OP_CONCAT = 1,
AMDUAT_PEL_KERNEL_OP_SLICE = 2,
AMDUAT_PEL_KERNEL_OP_CONST = 3,
AMDUAT_PEL_KERNEL_OP_HASH_ASL1 = 4
} amduat_pel_kernel_op_kind_t;
typedef struct {
amduat_pel_kernel_op_kind_t kind;
uint32_t kernel_op_code;
size_t min_inputs;
size_t max_inputs;
size_t outputs_len;
} amduat_pel_kernel_op_desc_t;
struct amduat_pel_kernel_params;
typedef struct amduat_pel_kernel_params amduat_pel_kernel_params_t;
const amduat_pel_kernel_op_desc_t *amduat_pel_kernel_op_lookup(
amduat_octets_t name,
uint32_t version);
bool amduat_pel_kernel_op_eval(
const amduat_pel_kernel_op_desc_t *desc,
const amduat_artifact_t *inputs,
size_t inputs_len,
const amduat_pel_kernel_params_t *params,
amduat_artifact_t **out_outputs,
size_t *out_outputs_len,
uint32_t *out_status_code);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* AMDUAT_PEL_OPREG_KERNEL_H */

View file

@ -0,0 +1,46 @@
#ifndef AMDUAT_PEL_OPREG_KERNEL_PARAMS_H
#define AMDUAT_PEL_OPREG_KERNEL_PARAMS_H
#include "amduat/pel/opreg_kernel.h"
#include <stdbool.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct {
uint64_t offset;
uint64_t length;
} amduat_pel_kernel_slice_params_t;
typedef struct {
amduat_octets_t bytes;
bool has_type_tag;
uint32_t tag_id;
} amduat_pel_kernel_const_params_t;
typedef struct {
amduat_hash_id_t hash_id;
} amduat_pel_kernel_hash_params_t;
struct amduat_pel_kernel_params {
amduat_pel_kernel_op_kind_t kind;
union {
amduat_pel_kernel_slice_params_t slice;
amduat_pel_kernel_const_params_t konst;
amduat_pel_kernel_hash_params_t hash;
} value;
};
bool amduat_pel_kernel_params_decode(
const amduat_pel_kernel_op_desc_t *desc,
amduat_octets_t params_bytes,
amduat_pel_kernel_params_t *out_params);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* AMDUAT_PEL_OPREG_KERNEL_PARAMS_H */

View file

@ -2,6 +2,7 @@
#define AMDUAT_PEL_PROGRAM_DAG_H #define AMDUAT_PEL_PROGRAM_DAG_H
#include "amduat/asl/core.h" #include "amduat/asl/core.h"
#include "amduat/pel/core.h"
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
@ -60,6 +61,19 @@ typedef struct {
size_t roots_len; size_t roots_len;
} amduat_pel_program_t; } amduat_pel_program_t;
bool amduat_pel_program_dag_validate(const amduat_pel_program_t *program);
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);
void amduat_pel_program_dag_free_outputs(amduat_artifact_t *outputs,
size_t outputs_len);
#ifdef __cplusplus #ifdef __cplusplus
} /* extern "C" */ } /* extern "C" */
#endif #endif

View file

@ -0,0 +1,23 @@
#ifndef AMDUAT_PEL_PROGRAM_DAG_DESC_H
#define AMDUAT_PEL_PROGRAM_DAG_DESC_H
#include "amduat/asl/core.h"
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
enum {
AMDUAT_PEL_TYPE_TAG_SCHEME_DESC_1 = 0x00000100u,
AMDUAT_PEL_TYPE_TAG_PROGRAM_DAG_1 = 0x00000101u
};
amduat_reference_t amduat_pel_program_dag_scheme_ref(void);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* AMDUAT_PEL_PROGRAM_DAG_DESC_H */

View file

@ -0,0 +1,436 @@
#include "amduat/pel/opreg_kernel.h"
#include "amduat/pel/opreg_kernel_params.h"
#include "amduat/hash/asl1.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
enum { AMDUAT_PEL_KERNEL_STATUS_INTERNAL = 1 };
static bool amduat_name_eq(amduat_octets_t name, const char *literal) {
size_t len = strlen(literal);
if (name.len != len) {
return false;
}
if (len == 0) {
return true;
}
return name.data != NULL &&
memcmp(name.data, literal, len) == 0;
}
static const amduat_pel_kernel_op_desc_t k_concat_desc = {
AMDUAT_PEL_KERNEL_OP_CONCAT,
AMDUAT_PEL_KERNEL_OP_CODE_CONCAT,
1,
SIZE_MAX,
1
};
static const amduat_pel_kernel_op_desc_t k_slice_desc = {
AMDUAT_PEL_KERNEL_OP_SLICE,
AMDUAT_PEL_KERNEL_OP_CODE_SLICE,
1,
1,
1
};
static const amduat_pel_kernel_op_desc_t k_const_desc = {
AMDUAT_PEL_KERNEL_OP_CONST,
AMDUAT_PEL_KERNEL_OP_CODE_CONST,
0,
0,
1
};
static const amduat_pel_kernel_op_desc_t k_hash_desc = {
AMDUAT_PEL_KERNEL_OP_HASH_ASL1,
AMDUAT_PEL_KERNEL_OP_CODE_HASH_ASL1,
1,
1,
1
};
const amduat_pel_kernel_op_desc_t *amduat_pel_kernel_op_lookup(
amduat_octets_t name,
uint32_t version) {
if (version != 1) {
return NULL;
}
if (amduat_name_eq(name, AMDUAT_PEL_KERNEL_OP_CONCAT_NAME)) {
return &k_concat_desc;
}
if (amduat_name_eq(name, AMDUAT_PEL_KERNEL_OP_SLICE_NAME)) {
return &k_slice_desc;
}
if (amduat_name_eq(name, AMDUAT_PEL_KERNEL_OP_CONST_NAME)) {
return &k_const_desc;
}
if (amduat_name_eq(name, AMDUAT_PEL_KERNEL_OP_HASH_ASL1_NAME)) {
return &k_hash_desc;
}
return NULL;
}
static bool amduat_type_tags_match(const amduat_artifact_t *a,
const amduat_artifact_t *b) {
if (a->has_type_tag != b->has_type_tag) {
return false;
}
if (!a->has_type_tag) {
return true;
}
return a->type_tag.tag_id == b->type_tag.tag_id;
}
static bool amduat_alloc_outputs(size_t count,
amduat_artifact_t **out_outputs) {
amduat_artifact_t *outputs;
if (out_outputs == NULL) {
return false;
}
outputs = (amduat_artifact_t *)calloc(count, sizeof(*outputs));
if (outputs == NULL) {
return false;
}
*out_outputs = outputs;
return true;
}
static bool amduat_kernel_concat(const amduat_artifact_t *inputs,
size_t inputs_len,
amduat_artifact_t **out_outputs,
size_t *out_outputs_len,
uint32_t *out_status_code) {
size_t i;
size_t total_len = 0;
uint8_t *buffer;
if (inputs == NULL) {
if (out_status_code) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL;
}
return false;
}
if (inputs_len == 0) {
if (out_status_code) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL;
}
return false;
}
for (i = 1; i < inputs_len; ++i) {
if (!amduat_type_tags_match(&inputs[0], &inputs[i])) {
if (out_status_code) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_CONCAT_TYPE_TAG_MISMATCH;
}
return false;
}
}
for (i = 0; i < inputs_len; ++i) {
if (inputs[i].bytes.len != 0 && inputs[i].bytes.data == NULL) {
if (out_status_code) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL;
}
return false;
}
if (inputs[i].bytes.len > SIZE_MAX - total_len) {
if (out_status_code) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL;
}
return false;
}
total_len += inputs[i].bytes.len;
}
buffer = NULL;
if (total_len != 0) {
buffer = (uint8_t *)malloc(total_len);
if (buffer == NULL) {
if (out_status_code) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL;
}
return false;
}
}
{
size_t offset = 0;
for (i = 0; i < inputs_len; ++i) {
if (inputs[i].bytes.len != 0 && inputs[i].bytes.data != NULL) {
memcpy(buffer + offset, inputs[i].bytes.data, inputs[i].bytes.len);
}
offset += inputs[i].bytes.len;
}
}
if (!amduat_alloc_outputs(1, out_outputs)) {
free(buffer);
if (out_status_code) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL;
}
return false;
}
(*out_outputs)[0].bytes = amduat_octets(buffer, total_len);
if (inputs[0].has_type_tag) {
(*out_outputs)[0].has_type_tag = true;
(*out_outputs)[0].type_tag = inputs[0].type_tag;
} else {
(*out_outputs)[0].has_type_tag = false;
(*out_outputs)[0].type_tag.tag_id = 0;
}
if (out_outputs_len) {
*out_outputs_len = 1;
}
return true;
}
static bool amduat_kernel_slice(const amduat_artifact_t *inputs,
size_t inputs_len,
const amduat_pel_kernel_slice_params_t *params,
amduat_artifact_t **out_outputs,
size_t *out_outputs_len,
uint32_t *out_status_code) {
const amduat_artifact_t *input;
uint64_t offset;
uint64_t length;
uint64_t total_len;
uint8_t *buffer;
if (inputs == NULL) {
if (out_status_code) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL;
}
return false;
}
if (inputs_len != 1 || params == NULL) {
if (out_status_code) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL;
}
return false;
}
input = &inputs[0];
total_len = (uint64_t)input->bytes.len;
offset = params->offset;
length = params->length;
if (offset > total_len || length > total_len - offset) {
if (out_status_code) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_SLICE_RANGE_OUT_OF_BOUNDS;
}
return false;
}
buffer = NULL;
if (length != 0) {
buffer = (uint8_t *)malloc((size_t)length);
if (buffer == NULL) {
if (out_status_code) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL;
}
return false;
}
if (input->bytes.data == NULL) {
free(buffer);
if (out_status_code) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL;
}
return false;
}
memcpy(buffer, input->bytes.data + (size_t)offset, (size_t)length);
}
if (!amduat_alloc_outputs(1, out_outputs)) {
free(buffer);
if (out_status_code) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL;
}
return false;
}
(*out_outputs)[0].bytes = amduat_octets(buffer, (size_t)length);
if (input->has_type_tag) {
(*out_outputs)[0].has_type_tag = true;
(*out_outputs)[0].type_tag = input->type_tag;
} else {
(*out_outputs)[0].has_type_tag = false;
(*out_outputs)[0].type_tag.tag_id = 0;
}
if (out_outputs_len) {
*out_outputs_len = 1;
}
return true;
}
static bool amduat_kernel_const(const amduat_pel_kernel_const_params_t *params,
amduat_artifact_t **out_outputs,
size_t *out_outputs_len,
uint32_t *out_status_code) {
uint8_t *buffer;
if (params == NULL) {
if (out_status_code) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL;
}
return false;
}
if (params->bytes.len != 0 && params->bytes.data == NULL) {
if (out_status_code) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL;
}
return false;
}
buffer = NULL;
if (params->bytes.len != 0) {
buffer = (uint8_t *)malloc(params->bytes.len);
if (buffer == NULL) {
if (out_status_code) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL;
}
return false;
}
if (params->bytes.data != NULL) {
memcpy(buffer, params->bytes.data, params->bytes.len);
}
}
if (!amduat_alloc_outputs(1, out_outputs)) {
free(buffer);
if (out_status_code) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL;
}
return false;
}
(*out_outputs)[0].bytes = amduat_octets(buffer, params->bytes.len);
if (params->has_type_tag) {
(*out_outputs)[0].has_type_tag = true;
(*out_outputs)[0].type_tag.tag_id = params->tag_id;
} else {
(*out_outputs)[0].has_type_tag = false;
(*out_outputs)[0].type_tag.tag_id = 0;
}
if (out_outputs_len) {
*out_outputs_len = 1;
}
return true;
}
static bool amduat_kernel_hash(const amduat_artifact_t *inputs,
size_t inputs_len,
const amduat_pel_kernel_hash_params_t *params,
amduat_artifact_t **out_outputs,
size_t *out_outputs_len,
uint32_t *out_status_code) {
const amduat_hash_asl1_desc_t *desc;
uint8_t *buffer;
if (inputs == NULL) {
if (out_status_code) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL;
}
return false;
}
if (inputs_len != 1 || params == NULL) {
if (out_status_code) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL;
}
return false;
}
desc = amduat_hash_asl1_desc_lookup(params->hash_id);
if (desc == NULL || desc->digest_len == 0) {
if (out_status_code) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL;
}
return false;
}
if (inputs[0].bytes.len != 0 && inputs[0].bytes.data == NULL) {
if (out_status_code) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL;
}
return false;
}
buffer = (uint8_t *)malloc(desc->digest_len);
if (buffer == NULL) {
if (out_status_code) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL;
}
return false;
}
if (!amduat_hash_asl1_digest(params->hash_id, inputs[0].bytes, buffer,
desc->digest_len)) {
free(buffer);
if (out_status_code) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL;
}
return false;
}
if (!amduat_alloc_outputs(1, out_outputs)) {
free(buffer);
if (out_status_code) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL;
}
return false;
}
(*out_outputs)[0].bytes = amduat_octets(buffer, desc->digest_len);
(*out_outputs)[0].has_type_tag = false;
(*out_outputs)[0].type_tag.tag_id = 0;
if (out_outputs_len) {
*out_outputs_len = 1;
}
return true;
}
bool amduat_pel_kernel_op_eval(
const amduat_pel_kernel_op_desc_t *desc,
const amduat_artifact_t *inputs,
size_t inputs_len,
const amduat_pel_kernel_params_t *params,
amduat_artifact_t **out_outputs,
size_t *out_outputs_len,
uint32_t *out_status_code) {
if (out_outputs_len != NULL) {
*out_outputs_len = 0;
}
if (out_outputs != NULL) {
*out_outputs = NULL;
}
if (desc == NULL || out_status_code == NULL) {
return false;
}
if (params == NULL) {
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL;
return false;
}
switch (desc->kind) {
case AMDUAT_PEL_KERNEL_OP_CONCAT:
return amduat_kernel_concat(inputs, inputs_len, out_outputs,
out_outputs_len, out_status_code);
case AMDUAT_PEL_KERNEL_OP_SLICE:
return amduat_kernel_slice(inputs, inputs_len, &params->value.slice,
out_outputs, out_outputs_len, out_status_code);
case AMDUAT_PEL_KERNEL_OP_CONST:
return amduat_kernel_const(&params->value.konst, out_outputs,
out_outputs_len, out_status_code);
case AMDUAT_PEL_KERNEL_OP_HASH_ASL1:
return amduat_kernel_hash(inputs, inputs_len, &params->value.hash,
out_outputs, out_outputs_len, out_status_code);
default:
*out_status_code = AMDUAT_PEL_KERNEL_STATUS_INTERNAL;
return false;
}
}

View file

@ -0,0 +1,132 @@
#include "amduat/pel/opreg_kernel_params.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
static uint16_t amduat_load_u16_be(const uint8_t *data) {
return (uint16_t)((data[0] << 8) | data[1]);
}
static uint32_t amduat_load_u32_be(const uint8_t *data) {
return ((uint32_t)data[0] << 24) | ((uint32_t)data[1] << 16) |
((uint32_t)data[2] << 8) | (uint32_t)data[3];
}
static uint64_t amduat_load_u64_be(const uint8_t *data) {
return ((uint64_t)data[0] << 56) | ((uint64_t)data[1] << 48) |
((uint64_t)data[2] << 40) | ((uint64_t)data[3] << 32) |
((uint64_t)data[4] << 24) | ((uint64_t)data[5] << 16) |
((uint64_t)data[6] << 8) | (uint64_t)data[7];
}
static bool amduat_decode_unit(amduat_octets_t bytes) {
return bytes.len == 0;
}
static bool amduat_decode_slice(amduat_octets_t bytes,
amduat_pel_kernel_slice_params_t *out_params) {
if (out_params == NULL) {
return false;
}
if (bytes.len != 16 || bytes.data == NULL) {
return false;
}
out_params->offset = amduat_load_u64_be(bytes.data);
out_params->length = amduat_load_u64_be(bytes.data + 8);
return true;
}
static bool amduat_decode_const(amduat_octets_t bytes,
amduat_pel_kernel_const_params_t *out_params) {
const uint8_t *data;
uint64_t payload_len;
uint64_t expected_total;
size_t offset;
if (out_params == NULL) {
return false;
}
if (bytes.len < 1 || bytes.data == NULL) {
return false;
}
data = bytes.data;
offset = 0;
if (data[offset] == 0x00u) {
out_params->has_type_tag = false;
offset += 1;
if (bytes.len < offset + 8) {
return false;
}
payload_len = amduat_load_u64_be(data + offset);
offset += 8;
expected_total = (uint64_t)offset + payload_len;
if (payload_len > SIZE_MAX || expected_total > SIZE_MAX ||
expected_total != bytes.len) {
return false;
}
out_params->bytes = amduat_octets(data + offset, (size_t)payload_len);
out_params->tag_id = 0;
return true;
}
if (data[offset] == 0x01u) {
out_params->has_type_tag = true;
offset += 1;
if (bytes.len < offset + 4 + 8) {
return false;
}
out_params->tag_id = amduat_load_u32_be(data + offset);
offset += 4;
payload_len = amduat_load_u64_be(data + offset);
offset += 8;
expected_total = (uint64_t)offset + payload_len;
if (payload_len > SIZE_MAX || expected_total > SIZE_MAX ||
expected_total != bytes.len) {
return false;
}
out_params->bytes = amduat_octets(data + offset, (size_t)payload_len);
return true;
}
return false;
}
static bool amduat_decode_hash(amduat_octets_t bytes,
amduat_pel_kernel_hash_params_t *out_params) {
if (out_params == NULL) {
return false;
}
if (bytes.len != 2 || bytes.data == NULL) {
return false;
}
out_params->hash_id = (amduat_hash_id_t)amduat_load_u16_be(bytes.data);
if (out_params->hash_id != 0x0001u) {
return false;
}
return true;
}
bool amduat_pel_kernel_params_decode(
const amduat_pel_kernel_op_desc_t *desc,
amduat_octets_t params_bytes,
amduat_pel_kernel_params_t *out_params) {
if (desc == NULL || out_params == NULL) {
return false;
}
out_params->kind = desc->kind;
switch (desc->kind) {
case AMDUAT_PEL_KERNEL_OP_CONCAT:
return amduat_decode_unit(params_bytes);
case AMDUAT_PEL_KERNEL_OP_SLICE:
return amduat_decode_slice(params_bytes, &out_params->value.slice);
case AMDUAT_PEL_KERNEL_OP_CONST:
return amduat_decode_const(params_bytes, &out_params->value.konst);
case AMDUAT_PEL_KERNEL_OP_HASH_ASL1:
return amduat_decode_hash(params_bytes, &out_params->value.hash);
default:
return false;
}
}

View file

@ -0,0 +1,642 @@
#include "amduat/pel/program_dag.h"
#include "amduat/pel/opreg_kernel.h"
#include "amduat/pel/opreg_kernel_params.h"
#include "amduat/pel/program_dag_desc.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
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;
amduat_pel_kernel_params_t *params;
} amduat_pel_program_dag_prepared_t;
static void amduat_prepared_reset(amduat_pel_program_dag_prepared_t *prepared) {
if (prepared == NULL) {
return;
}
prepared->order = NULL;
prepared->ops = NULL;
prepared->params = NULL;
}
static void amduat_prepared_free(amduat_pel_program_dag_prepared_t *prepared) {
if (prepared == NULL) {
return;
}
free(prepared->order);
free(prepared->ops);
free(prepared->params);
amduat_prepared_reset(prepared);
}
static void amduat_set_result(amduat_pel_execution_result_value_t *result,
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 = amduat_pel_program_dag_scheme_ref();
result->summary.kind = kind;
result->summary.status_code = status_code;
result->diagnostics = NULL;
result->diagnostics_len = 0;
}
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;
} else if (input->kind != AMDUAT_PEL_DAG_INPUT_EXTERNAL) {
free(deps);
free(placed);
return false;
}
}
}
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;
}
if (out_order != NULL) {
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;
}
static void amduat_free_node_outputs(amduat_pel_node_outputs_t *node_outputs,
size_t len) {
size_t i;
if (node_outputs == NULL) {
return;
}
for (i = 0; i < len; ++i) {
amduat_pel_node_outputs_t *entry = &node_outputs[i];
size_t j;
for (j = 0; j < entry->outputs_len; ++j) {
free((void *)entry->outputs[j].bytes.data);
entry->outputs[j].bytes.data = NULL;
entry->outputs[j].bytes.len = 0;
}
free(entry->outputs);
entry->outputs = NULL;
entry->outputs_len = 0;
}
free(node_outputs);
}
static bool amduat_copy_artifact(amduat_artifact_t *out,
const amduat_artifact_t *src) {
uint8_t *buffer = NULL;
if (out == NULL || src == NULL) {
return false;
}
if (src->bytes.len != 0) {
buffer = (uint8_t *)malloc(src->bytes.len);
if (buffer == NULL) {
return false;
}
if (src->bytes.data != NULL) {
memcpy(buffer, src->bytes.data, src->bytes.len);
}
}
out->bytes = amduat_octets(buffer, src->bytes.len);
out->has_type_tag = src->has_type_tag;
out->type_tag = src->type_tag;
return true;
}
static bool amduat_program_prepare(const amduat_pel_program_t *program,
amduat_pel_program_dag_prepared_t *prepared) {
size_t i;
if (program == NULL || prepared == NULL) {
return false;
}
amduat_prepared_reset(prepared);
if (program->nodes_len > 0 && program->nodes == NULL) {
return false;
}
if (program->roots_len > 0 && program->roots == NULL) {
return false;
}
if (program->nodes_len == 0) {
if (program->roots_len != 0) {
return false;
}
return true;
}
prepared->order = (size_t *)malloc(program->nodes_len *
sizeof(*prepared->order));
prepared->ops = (const amduat_pel_kernel_op_desc_t **)calloc(
program->nodes_len, sizeof(*prepared->ops));
prepared->params = (amduat_pel_kernel_params_t *)calloc(
program->nodes_len, sizeof(*prepared->params));
if (prepared->order == NULL || prepared->ops == NULL ||
prepared->params == NULL) {
amduat_prepared_free(prepared);
return false;
}
for (i = 0; i < program->nodes_len; ++i) {
const amduat_pel_node_t *node = &program->nodes[i];
const amduat_pel_kernel_op_desc_t *desc;
if (node->op.name.len > 0 && node->op.name.data == NULL) {
amduat_prepared_free(prepared);
return false;
}
if (!amduat_utf8_is_valid(node->op.name)) {
amduat_prepared_free(prepared);
return false;
}
if (node->inputs_len > 0 && node->inputs == NULL) {
amduat_prepared_free(prepared);
return false;
}
if (node->params.len > 0 && node->params.data == NULL) {
amduat_prepared_free(prepared);
return false;
}
desc = amduat_pel_kernel_op_lookup(node->op.name, node->op.version);
if (desc == NULL) {
amduat_prepared_free(prepared);
return false;
}
if (node->inputs_len < desc->min_inputs ||
node->inputs_len > desc->max_inputs) {
amduat_prepared_free(prepared);
return false;
}
if (!amduat_pel_kernel_params_decode(desc, node->params,
&prepared->params[i])) {
amduat_prepared_free(prepared);
return false;
}
prepared->ops[i] = desc;
}
if (!amduat_build_node_order(program, prepared->order)) {
amduat_prepared_free(prepared);
return false;
}
for (i = 0; i < program->nodes_len; ++i) {
const amduat_pel_node_t *node = &program->nodes[i];
size_t j;
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) {
int dep_index = amduat_find_node_index(program,
input->value.node.node_id);
if (dep_index < 0) {
amduat_prepared_free(prepared);
return false;
}
if (input->value.node.output_index >=
prepared->ops[dep_index]->outputs_len) {
amduat_prepared_free(prepared);
return false;
}
} else if (input->kind != AMDUAT_PEL_DAG_INPUT_EXTERNAL) {
amduat_prepared_free(prepared);
return false;
}
}
}
for (i = 0; i < program->roots_len; ++i) {
int root_index = amduat_find_node_index(program, program->roots[i].node_id);
if (root_index < 0) {
amduat_prepared_free(prepared);
return false;
}
if (program->roots[i].output_index >=
prepared->ops[root_index]->outputs_len) {
amduat_prepared_free(prepared);
return false;
}
}
return true;
}
bool amduat_pel_program_dag_validate(const amduat_pel_program_t *program) {
amduat_pel_program_dag_prepared_t prepared;
bool ok;
amduat_prepared_reset(&prepared);
ok = amduat_program_prepare(program, &prepared);
amduat_prepared_free(&prepared);
return ok;
}
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) {
amduat_pel_program_dag_prepared_t prepared;
amduat_pel_node_outputs_t *node_outputs;
amduat_artifact_t *resolved_inputs;
size_t max_inputs;
size_t i;
if (out_outputs == NULL || out_outputs_len == NULL || out_result == NULL) {
return false;
}
*out_outputs = NULL;
*out_outputs_len = 0;
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);
return true;
}
if (inputs_len > 0 && inputs == NULL) {
bool needs_inputs = false;
for (i = 0; i < program->nodes_len; ++i) {
size_t j;
const amduat_pel_node_t *node = &program->nodes[i];
for (j = 0; j < node->inputs_len; ++j) {
if (node->inputs[j].kind == AMDUAT_PEL_DAG_INPUT_EXTERNAL) {
needs_inputs = true;
break;
}
}
if (needs_inputs) {
break;
}
}
if (needs_inputs) {
amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_INVALID_INPUTS,
AMDUAT_PEL_EXEC_ERROR_INPUTS, 3);
amduat_prepared_free(&prepared);
return true;
}
}
if (program->nodes_len == 0) {
amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_OK,
AMDUAT_PEL_EXEC_ERROR_NONE, 0);
amduat_prepared_free(&prepared);
return true;
}
node_outputs = (amduat_pel_node_outputs_t *)calloc(
program->nodes_len, sizeof(*node_outputs));
if (node_outputs == NULL) {
amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_RUNTIME_FAILED,
AMDUAT_PEL_EXEC_ERROR_RUNTIME, 1);
amduat_prepared_free(&prepared);
return true;
}
max_inputs = 0;
for (i = 0; i < program->nodes_len; ++i) {
if (program->nodes[i].inputs_len > max_inputs) {
max_inputs = program->nodes[i].inputs_len;
}
}
resolved_inputs = NULL;
if (max_inputs != 0) {
resolved_inputs = (amduat_artifact_t *)malloc(
max_inputs * sizeof(*resolved_inputs));
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_prepared_free(&prepared);
return true;
}
}
for (i = 0; i < program->nodes_len; ++i) {
size_t node_index = prepared.order[i];
const amduat_pel_node_t *node = &program->nodes[node_index];
size_t j;
uint32_t status_code = 0;
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_EXTERNAL) {
if (input->value.external.input_index >= inputs_len) {
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;
}
resolved_inputs[j] = inputs[input->value.external.input_index];
} else if (input->kind == AMDUAT_PEL_DAG_INPUT_NODE) {
int dep_index = amduat_find_node_index(program,
input->value.node.node_id);
if (dep_index < 0 ||
input->value.node.output_index >=
node_outputs[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;
}
resolved_inputs[j] =
node_outputs[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;
}
}
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)) {
if (status_code == 2 || status_code == 3 || status_code == 0) {
status_code = 1;
}
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;
}
}
if (program->roots_len != 0) {
*out_outputs = (amduat_artifact_t *)calloc(
program->roots_len, sizeof(**out_outputs));
if (*out_outputs == NULL) {
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;
}
}
for (i = 0; i < program->roots_len; ++i) {
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) {
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,
program->roots_len);
*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;
}
if (!amduat_copy_artifact(
&(*out_outputs)[i],
&node_outputs[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);
amduat_pel_program_dag_free_outputs(*out_outputs,
program->roots_len);
*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;
}
}
*out_outputs_len = program->roots_len;
amduat_set_result(out_result, AMDUAT_PEL_EXEC_STATUS_OK,
AMDUAT_PEL_EXEC_ERROR_NONE, 0);
free(resolved_inputs);
amduat_free_node_outputs(node_outputs, program->nodes_len);
amduat_prepared_free(&prepared);
return true;
}
void amduat_pel_program_dag_free_outputs(amduat_artifact_t *outputs,
size_t outputs_len) {
size_t i;
if (outputs == NULL) {
return;
}
for (i = 0; i < outputs_len; ++i) {
free((void *)outputs[i].bytes.data);
outputs[i].bytes.data = NULL;
outputs[i].bytes.len = 0;
}
free(outputs);
}

View file

@ -0,0 +1,15 @@
#include "amduat/pel/program_dag_desc.h"
#include "amduat/hash/asl1.h"
amduat_reference_t amduat_pel_program_dag_scheme_ref(void) {
static const uint8_t digest[] = {
0xc5, 0x0f, 0xb2, 0xa7, 0x34, 0xa5, 0xcc, 0x23,
0x3c, 0x38, 0x75, 0xb7, 0x0a, 0x7d, 0x96, 0xea,
0xad, 0x37, 0x4f, 0x00, 0x00, 0x29, 0x77, 0x1d,
0x8b, 0xef, 0x1a, 0xf2, 0xcd, 0x63, 0x84, 0xdd,
};
return amduat_reference(AMDUAT_HASH_ASL1_ID_SHA256,
amduat_octets(digest, sizeof(digest)));
}

View file

@ -0,0 +1,296 @@
#include "amduat/pel/program_dag.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
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 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_valid_program(void) {
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_artifact_t inputs[1];
amduat_artifact_t *outputs = NULL;
size_t outputs_len = 0;
amduat_pel_execution_result_value_t result;
const char op_const[] = "pel.bytes.const";
const char op_concat[] = "pel.bytes.concat";
const uint8_t const_bytes[] = {'h', 'i'};
const uint8_t expected[] = {'h', 'i', '!'};
amduat_octets_t const_params;
int exit_code = 1;
const_params = make_const_params(const_bytes, sizeof(const_bytes));
if (const_params.data == NULL) {
fprintf(stderr, "const params alloc failed\n");
return exit_code;
}
nodes[0].id = 2;
nodes[0].op.name = amduat_octets(op_concat, strlen(op_concat));
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(op_const, strlen(op_const));
nodes[1].op.version = 1;
nodes[1].inputs = NULL;
nodes[1].inputs_len = 0;
nodes[1].params = const_params;
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 = 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;
inputs[0] = amduat_artifact(amduat_octets("!", 1));
if (!amduat_pel_program_dag_exec(&program, inputs, 1, &outputs,
&outputs_len, &result)) {
fprintf(stderr, "exec failed\n");
goto cleanup;
}
if (result.status != AMDUAT_PEL_EXEC_STATUS_OK ||
result.summary.kind != AMDUAT_PEL_EXEC_ERROR_NONE ||
result.summary.status_code != 0) {
fprintf(stderr, "unexpected status\n");
goto cleanup;
}
if (outputs_len != 1 ||
!bytes_equal(outputs[0].bytes, expected, sizeof(expected))) {
fprintf(stderr, "unexpected output\n");
goto cleanup;
}
exit_code = 0;
cleanup:
amduat_pel_program_dag_free_outputs(outputs, outputs_len);
free((void *)const_params.data);
return exit_code;
}
static int test_invalid_program_cycle(void) {
amduat_pel_dag_input_t node1_inputs[1];
amduat_pel_dag_input_t node2_inputs[1];
amduat_pel_node_t nodes[2];
amduat_pel_root_ref_t roots[1];
amduat_pel_program_t program;
amduat_artifact_t *outputs = NULL;
size_t outputs_len = 0;
amduat_pel_execution_result_value_t result;
const char op_concat[] = "pel.bytes.concat";
node1_inputs[0].kind = AMDUAT_PEL_DAG_INPUT_NODE;
node1_inputs[0].value.node.node_id = 2;
node1_inputs[0].value.node.output_index = 0;
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;
nodes[0].id = 1;
nodes[0].op.name = amduat_octets(op_concat, strlen(op_concat));
nodes[0].op.version = 1;
nodes[0].inputs = node1_inputs;
nodes[0].inputs_len = 1;
nodes[0].params = amduat_octets(NULL, 0);
nodes[1].id = 2;
nodes[1].op.name = amduat_octets(op_concat, strlen(op_concat));
nodes[1].op.version = 1;
nodes[1].inputs = node2_inputs;
nodes[1].inputs_len = 1;
nodes[1].params = amduat_octets(NULL, 0);
roots[0].node_id = 1;
roots[0].output_index = 0;
program.nodes = nodes;
program.nodes_len = 2;
program.roots = roots;
program.roots_len = 1;
if (!amduat_pel_program_dag_exec(&program, NULL, 0, &outputs,
&outputs_len, &result)) {
fprintf(stderr, "exec failed\n");
return 1;
}
if (result.status != AMDUAT_PEL_EXEC_STATUS_INVALID_PROGRAM ||
result.summary.kind != AMDUAT_PEL_EXEC_ERROR_PROGRAM ||
result.summary.status_code != 2) {
fprintf(stderr, "unexpected invalid program status\n");
amduat_pel_program_dag_free_outputs(outputs, outputs_len);
return 1;
}
amduat_pel_program_dag_free_outputs(outputs, outputs_len);
return 0;
}
static int test_invalid_params(void) {
amduat_pel_dag_input_t node_inputs[1];
amduat_pel_node_t nodes[1];
amduat_pel_root_ref_t roots[1];
amduat_pel_program_t program;
amduat_artifact_t inputs[1];
amduat_artifact_t *outputs = NULL;
size_t outputs_len = 0;
amduat_pel_execution_result_value_t result;
const char op_concat[] = "pel.bytes.concat";
uint8_t bad_params[] = {0x01u};
node_inputs[0].kind = AMDUAT_PEL_DAG_INPUT_EXTERNAL;
node_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 = node_inputs;
nodes[0].inputs_len = 1;
nodes[0].params = amduat_octets(bad_params, sizeof(bad_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;
inputs[0] = amduat_artifact(amduat_octets("x", 1));
if (!amduat_pel_program_dag_exec(&program, inputs, 1, &outputs,
&outputs_len, &result)) {
fprintf(stderr, "exec failed\n");
return 1;
}
if (result.status != AMDUAT_PEL_EXEC_STATUS_INVALID_PROGRAM ||
result.summary.kind != AMDUAT_PEL_EXEC_ERROR_PROGRAM ||
result.summary.status_code != 2) {
fprintf(stderr, "unexpected invalid params status\n");
amduat_pel_program_dag_free_outputs(outputs, outputs_len);
return 1;
}
amduat_pel_program_dag_free_outputs(outputs, outputs_len);
return 0;
}
static int test_invalid_input_index(void) {
amduat_pel_dag_input_t node_inputs[1];
amduat_pel_node_t nodes[1];
amduat_pel_root_ref_t roots[1];
amduat_pel_program_t program;
amduat_artifact_t inputs[1];
amduat_artifact_t *outputs = NULL;
size_t outputs_len = 0;
amduat_pel_execution_result_value_t result;
const char op_concat[] = "pel.bytes.concat";
node_inputs[0].kind = AMDUAT_PEL_DAG_INPUT_EXTERNAL;
node_inputs[0].value.external.input_index = 1;
nodes[0].id = 1;
nodes[0].op.name = amduat_octets(op_concat, strlen(op_concat));
nodes[0].op.version = 1;
nodes[0].inputs = node_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;
inputs[0] = amduat_artifact(amduat_octets("x", 1));
if (!amduat_pel_program_dag_exec(&program, inputs, 1, &outputs,
&outputs_len, &result)) {
fprintf(stderr, "exec failed\n");
return 1;
}
if (result.status != AMDUAT_PEL_EXEC_STATUS_INVALID_INPUTS ||
result.summary.kind != AMDUAT_PEL_EXEC_ERROR_INPUTS ||
result.summary.status_code != 3) {
fprintf(stderr, "unexpected invalid inputs status\n");
amduat_pel_program_dag_free_outputs(outputs, outputs_len);
return 1;
}
amduat_pel_program_dag_free_outputs(outputs, outputs_len);
return 0;
}
int main(void) {
if (test_valid_program() != 0) {
return 1;
}
if (test_invalid_program_cycle() != 0) {
return 1;
}
if (test_invalid_params() != 0) {
return 1;
}
if (test_invalid_input_index() != 0) {
return 1;
}
return 0;
}