Add PEL seed/run tools and quickstart README

This commit is contained in:
Carl Niklas Rydberg 2025-12-20 17:23:37 +01:00
parent a7ff4ec25a
commit 441b0191e8
4 changed files with 1250 additions and 0 deletions

View file

@ -149,6 +149,27 @@ target_link_libraries(amduat_asl_cli
)
set_target_properties(amduat_asl_cli PROPERTIES OUTPUT_NAME amduat-asl)
add_executable(amduat_pel_seed src/tools/amduat_pel_seed.c)
target_include_directories(amduat_pel_seed
PRIVATE ${AMDUAT_INTERNAL_DIR}
PRIVATE ${AMDUAT_INCLUDE_DIR}
)
target_link_libraries(amduat_pel_seed
PRIVATE amduat_asl_store_fs amduat_asl amduat_enc amduat_hash_asl1 amduat_util
)
set_target_properties(amduat_pel_seed PROPERTIES OUTPUT_NAME amduat-pel-seed)
add_executable(amduat_pel_run src/tools/amduat_pel_run.c)
target_include_directories(amduat_pel_run
PRIVATE ${AMDUAT_INTERNAL_DIR}
PRIVATE ${AMDUAT_INCLUDE_DIR}
)
target_link_libraries(amduat_pel_run
PRIVATE amduat_pel amduat_asl_store_fs amduat_asl amduat_enc
amduat_hash_asl1 amduat_util
)
set_target_properties(amduat_pel_run PROPERTIES OUTPUT_NAME amduat-pel-run)
enable_testing()
add_executable(amduat_test_pel_program_dag tests/enc/test_pel_program_dag.c)

98
README.md Normal file
View file

@ -0,0 +1,98 @@
# Amduat (PEL quickstart)
This repo contains the PEL/1 stack and small CLI tools to seed and run
PEL/PROGRAM-DAG/1 programs against an ASL store.
## Build
```
cmake --build build
```
## Initialize an ASL store
```
amduat-asl init --root .amduat-asl
```
## Seed a PEL program artifact
`amduat-pel-seed` creates a Program DAG in memory, encodes it under
`ENC/PEL-PROGRAM-DAG/1`, tags it as `TYPE_TAG_PEL_PROGRAM_DAG_1`, and
stores it in ASL.
```
concat1_ref=$(amduat-pel-seed --seed concat1 --root .amduat-asl --quiet)
```
Available seeds:
- `const` (const "hello", no inputs)
- `concat` (concat input 0 + input 1)
- `concat1` (identity: concat input 0 only)
- `slice` (slice input 0, offset=1 length=3)
- `hash` (HASH-ASL1-256 of input 0)
- `const-hash` (const "hello" then hash)
## Store an input artifact
```
input_ref=$(printf 'hello' | amduat-asl put --root .amduat-asl --input - --quiet)
```
## Run a program and print output bytes
`amduat-pel-run` executes a Program via `PEL/1-SURF`, writes outputs and
result artifacts to the store, and can stream an output artifact's bytes
to stdout (like `amduat-asl get`).
```
amduat-pel-run --root .amduat-asl \
--program-ref "$concat1_ref" \
--input-ref "$input_ref" \
--output-raw --quiet
```
The command above prints `hello` to stdout. Without `--quiet`, execution
status and refs are printed to stderr.
## Notes
- Program artifacts are standard ASL artifacts whose bytes are encoded
`ProgramBytes` (`ENC/PEL-PROGRAM-DAG/1`) and whose type tag is
`TYPE_TAG_PEL_PROGRAM_DAG_1` (`0x00000101`).
- `amduat-pel-run` reports `result_ref`, `trace_ref`, and `output_ref[N]`
when not using `--output-raw`.
## PEL reference
- Scheme ref (PEL/PROGRAM-DAG/1): `amduat_pel_program_dag_scheme_ref()`
- Type tags:
- Program DAG: `0x00000101` (`TYPE_TAG_PEL_PROGRAM_DAG_1`)
- Trace DAG: `0x00000102` (`TYPE_TAG_PEL_TRACE_DAG_1`)
- Surface result: `0x00000103` (`TYPE_TAG_PEL1_RESULT_1`)
- Encoding profile IDs:
- Program DAG: `0x0101` (`PEL_ENC_PROGRAM_DAG_V1`)
- Trace DAG: `0x0102` (`PEL_ENC_TRACE_DAG_V1`)
- Surface result: `0x0103` (`PEL_ENC_EXECUTION_RESULT_V1`)
## TGK handoff (stub)
TGK should consume PEL surface artifacts (result + trace) and their refs to
construct provenance graphs and overlays. Inputs to expect:
- `result_ref`: a `PEL/1-SURF` execution result artifact.
- `trace_ref`: a `PEL/TRACE-DAG/1` trace artifact (optional but recommended).
- `program_ref` + `input_refs`: available inside result/trace payloads.
Recommended next step: map trace nodes/outputs to TGK nodes/edges and build
overlay indexes (e.g., lookup by artifact ref, program ref, op name).
## Common mistakes
- Passing a **program ref** as an input ref. Program artifacts are encoded DAGs,
so printing their bytes yields strings like `pel.bytes.const` plus embedded
params (e.g. `hello`), not the intended data.
- Forgetting that `concat1` is identity: output bytes match input bytes.
- Expecting `params_ref` to affect DAG execution (it is accepted by the surface
API but not used in the current DAG executor).

455
src/tools/amduat_pel_run.c Normal file
View file

@ -0,0 +1,455 @@
#include "amduat/asl/asl_store_fs.h"
#include "amduat/asl/asl_store_fs_meta.h"
#include "amduat/asl/io.h"
#include "amduat/asl/parse.h"
#include "amduat/asl/ref_text.h"
#include "amduat/asl/store.h"
#include "amduat/enc/pel1_result.h"
#include "amduat/pel/program_dag_desc.h"
#include "amduat/pel/surf.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum {
AMDUAT_PEL_RUN_EXIT_OK = 0,
AMDUAT_PEL_RUN_EXIT_USAGE = 2,
AMDUAT_PEL_RUN_EXIT_IO = 3,
AMDUAT_PEL_RUN_EXIT_NOT_FOUND = 4,
AMDUAT_PEL_RUN_EXIT_STORE = 5,
AMDUAT_PEL_RUN_EXIT_UNSUPPORTED = 6,
AMDUAT_PEL_RUN_EXIT_CODEC = 7,
AMDUAT_PEL_RUN_EXIT_CONFIG = 8
};
static const char *const AMDUAT_PEL_RUN_DEFAULT_ROOT = ".amduat-asl";
typedef struct {
const char *root;
const char *program_ref;
const char *params_ref;
const char **input_refs;
size_t input_refs_len;
size_t output_index;
bool output_raw;
bool has_params_ref;
bool quiet;
} amduat_pel_run_opts_t;
static void amduat_pel_run_print_usage(FILE *stream) {
fprintf(stream,
"usage:\n"
" amduat-pel-run --program-ref REF [--input-ref REF ...]\n"
" [--params-ref REF] [--output-raw]\n"
" [--output-index N] [--root PATH] [--quiet]\n"
"\n"
"defaults:\n"
" --root %s\n"
" --output-index 0\n"
"\n"
"notes:\n"
" REF values are ASL reference hex strings.\n"
" --output-raw writes output bytes to stdout and exec result to stderr.\n",
AMDUAT_PEL_RUN_DEFAULT_ROOT);
}
static const char *amduat_pel_run_store_error_str(
amduat_asl_store_error_t err) {
switch (err) {
case AMDUAT_ASL_STORE_ERR_NOT_FOUND:
return "not found";
case AMDUAT_ASL_STORE_ERR_UNSUPPORTED:
return "unsupported";
case AMDUAT_ASL_STORE_ERR_INTEGRITY:
return "integrity";
case AMDUAT_ASL_STORE_OK:
return "ok";
default:
return "unknown";
}
}
static int amduat_pel_run_map_store_error(amduat_asl_store_error_t err) {
switch (err) {
case AMDUAT_ASL_STORE_ERR_NOT_FOUND:
return AMDUAT_PEL_RUN_EXIT_NOT_FOUND;
case AMDUAT_ASL_STORE_ERR_UNSUPPORTED:
return AMDUAT_PEL_RUN_EXIT_UNSUPPORTED;
case AMDUAT_ASL_STORE_ERR_INTEGRITY:
return AMDUAT_PEL_RUN_EXIT_STORE;
case AMDUAT_ASL_STORE_OK:
default:
return AMDUAT_PEL_RUN_EXIT_STORE;
}
}
static void amduat_pel_run_free_reference(amduat_reference_t *ref) {
if (ref == NULL) {
return;
}
free((void *)ref->digest.data);
ref->digest.data = NULL;
ref->digest.len = 0u;
}
static void amduat_pel_run_free_artifact(amduat_artifact_t *artifact) {
if (artifact == NULL) {
return;
}
free((void *)artifact->bytes.data);
artifact->bytes.data = NULL;
artifact->bytes.len = 0u;
}
static void amduat_pel_run_free_refs(amduat_reference_t *refs,
size_t refs_len) {
size_t i;
if (refs == NULL) {
return;
}
for (i = 0; i < refs_len; ++i) {
amduat_pel_run_free_reference(&refs[i]);
}
free(refs);
}
static const char *amduat_pel_run_status_name(
amduat_pel_execution_status_t status) {
switch (status) {
case AMDUAT_PEL_EXEC_STATUS_OK:
return "OK";
case AMDUAT_PEL_EXEC_STATUS_SCHEME_UNSUPPORTED:
return "SCHEME_UNSUPPORTED";
case AMDUAT_PEL_EXEC_STATUS_INVALID_PROGRAM:
return "INVALID_PROGRAM";
case AMDUAT_PEL_EXEC_STATUS_INVALID_INPUTS:
return "INVALID_INPUTS";
case AMDUAT_PEL_EXEC_STATUS_RUNTIME_FAILED:
return "RUNTIME_FAILED";
default:
return "UNKNOWN";
}
}
static const char *amduat_pel_run_error_kind_name(
amduat_pel_execution_error_kind_t kind) {
switch (kind) {
case AMDUAT_PEL_EXEC_ERROR_NONE:
return "NONE";
case AMDUAT_PEL_EXEC_ERROR_SCHEME:
return "SCHEME";
case AMDUAT_PEL_EXEC_ERROR_PROGRAM:
return "PROGRAM";
case AMDUAT_PEL_EXEC_ERROR_INPUTS:
return "INPUTS";
case AMDUAT_PEL_EXEC_ERROR_RUNTIME:
return "RUNTIME";
default:
return "UNKNOWN";
}
}
int main(int argc, char **argv) {
amduat_pel_run_opts_t opts;
amduat_asl_store_fs_config_t cfg;
amduat_asl_store_fs_t fs;
amduat_asl_store_t store;
amduat_reference_t program_ref;
amduat_reference_t params_ref;
amduat_reference_t *input_refs = NULL;
amduat_reference_t *output_refs = NULL;
size_t output_refs_len = 0;
amduat_reference_t result_ref;
amduat_artifact_t result_artifact;
amduat_pel_surface_execution_result_t result_value;
bool has_result_value = false;
bool has_trace_ref = false;
amduat_reference_t trace_ref;
amduat_artifact_t output_artifact;
bool has_output_artifact = false;
int exit_code = AMDUAT_PEL_RUN_EXIT_OK;
int i;
memset(&opts, 0, sizeof(opts));
opts.root = AMDUAT_PEL_RUN_DEFAULT_ROOT;
opts.output_index = 0u;
for (i = 1; i < argc; ++i) {
if (strcmp(argv[i], "--root") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "error: --root requires a path\n");
return AMDUAT_PEL_RUN_EXIT_USAGE;
}
opts.root = argv[++i];
} else if (strcmp(argv[i], "--program-ref") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "error: --program-ref requires a value\n");
return AMDUAT_PEL_RUN_EXIT_USAGE;
}
opts.program_ref = argv[++i];
} else if (strcmp(argv[i], "--input-ref") == 0) {
const char **next_inputs;
if (i + 1 >= argc) {
fprintf(stderr, "error: --input-ref requires a value\n");
return AMDUAT_PEL_RUN_EXIT_USAGE;
}
next_inputs = (const char **)realloc(
opts.input_refs,
(opts.input_refs_len + 1u) * sizeof(*opts.input_refs));
if (next_inputs == NULL) {
fprintf(stderr, "error: out of memory\n");
return AMDUAT_PEL_RUN_EXIT_STORE;
}
opts.input_refs = next_inputs;
opts.input_refs[opts.input_refs_len++] = argv[++i];
} else if (strcmp(argv[i], "--params-ref") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "error: --params-ref requires a value\n");
return AMDUAT_PEL_RUN_EXIT_USAGE;
}
opts.params_ref = argv[++i];
opts.has_params_ref = true;
} else if (strcmp(argv[i], "--output-raw") == 0) {
opts.output_raw = true;
} else if (strcmp(argv[i], "--output-index") == 0) {
uint32_t index = 0;
if (i + 1 >= argc) {
fprintf(stderr, "error: --output-index requires a value\n");
return AMDUAT_PEL_RUN_EXIT_USAGE;
}
if (!amduat_asl_parse_u32(argv[++i], &index)) {
fprintf(stderr, "error: invalid --output-index\n");
return AMDUAT_PEL_RUN_EXIT_USAGE;
}
opts.output_index = (size_t)index;
} else if (strcmp(argv[i], "--quiet") == 0) {
opts.quiet = true;
} else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
amduat_pel_run_print_usage(stdout);
return AMDUAT_PEL_RUN_EXIT_OK;
} else {
fprintf(stderr, "error: unknown option: %s\n", argv[i]);
return AMDUAT_PEL_RUN_EXIT_USAGE;
}
}
if (opts.program_ref == NULL) {
fprintf(stderr, "error: --program-ref is required\n");
return AMDUAT_PEL_RUN_EXIT_USAGE;
}
if (!amduat_asl_store_fs_load_config(opts.root, &cfg)) {
fprintf(stderr, "error: failed to load store config: %s\n", opts.root);
return AMDUAT_PEL_RUN_EXIT_CONFIG;
}
if (!amduat_asl_store_fs_init(&fs, cfg.config, opts.root)) {
fprintf(stderr, "error: failed to initialize store\n");
return AMDUAT_PEL_RUN_EXIT_CONFIG;
}
amduat_asl_store_init(&store, cfg.config, amduat_asl_store_fs_ops(), &fs);
memset(&program_ref, 0, sizeof(program_ref));
if (!amduat_asl_ref_decode_hex(opts.program_ref, &program_ref)) {
fprintf(stderr, "error: invalid --program-ref\n");
return AMDUAT_PEL_RUN_EXIT_USAGE;
}
if (opts.has_params_ref) {
memset(&params_ref, 0, sizeof(params_ref));
if (!amduat_asl_ref_decode_hex(opts.params_ref, &params_ref)) {
amduat_pel_run_free_reference(&program_ref);
fprintf(stderr, "error: invalid --params-ref\n");
return AMDUAT_PEL_RUN_EXIT_USAGE;
}
} else {
memset(&params_ref, 0, sizeof(params_ref));
}
if (opts.input_refs_len > 0) {
input_refs = (amduat_reference_t *)calloc(
opts.input_refs_len, sizeof(*input_refs));
if (input_refs == NULL) {
amduat_pel_run_free_reference(&program_ref);
if (opts.has_params_ref) {
amduat_pel_run_free_reference(&params_ref);
}
fprintf(stderr, "error: out of memory\n");
return AMDUAT_PEL_RUN_EXIT_STORE;
}
for (i = 0; i < (int)opts.input_refs_len; ++i) {
if (!amduat_asl_ref_decode_hex(opts.input_refs[i], &input_refs[i])) {
size_t j;
fprintf(stderr, "error: invalid --input-ref\n");
for (j = 0; j <= (size_t)i; ++j) {
amduat_pel_run_free_reference(&input_refs[j]);
}
free(input_refs);
amduat_pel_run_free_reference(&program_ref);
if (opts.has_params_ref) {
amduat_pel_run_free_reference(&params_ref);
}
return AMDUAT_PEL_RUN_EXIT_USAGE;
}
}
}
memset(&result_ref, 0, sizeof(result_ref));
if (!amduat_pel_surf_run(
&store,
amduat_pel_program_dag_scheme_ref(),
program_ref,
input_refs,
opts.input_refs_len,
opts.has_params_ref,
params_ref,
&output_refs,
&output_refs_len,
&result_ref)) {
fprintf(stderr, "error: PEL surface execution failed\n");
exit_code = AMDUAT_PEL_RUN_EXIT_STORE;
goto cleanup;
}
memset(&trace_ref, 0, sizeof(trace_ref));
memset(&result_artifact, 0, sizeof(result_artifact));
memset(&output_artifact, 0, sizeof(output_artifact));
if (amduat_asl_store_get(&store, result_ref, &result_artifact) ==
AMDUAT_ASL_STORE_OK) {
if (amduat_enc_pel1_result_decode_v1(result_artifact.bytes,
&result_value)) {
has_result_value = true;
if (result_value.has_trace_ref) {
trace_ref = result_value.trace_ref;
has_trace_ref = true;
}
}
}
if (opts.output_raw) {
if (opts.output_index >= output_refs_len) {
fprintf(stderr, "error: output index out of range\n");
exit_code = AMDUAT_PEL_RUN_EXIT_USAGE;
goto cleanup;
}
if (amduat_asl_store_get(&store, output_refs[opts.output_index],
&output_artifact) != AMDUAT_ASL_STORE_OK) {
fprintf(stderr, "error: failed to load output artifact\n");
exit_code = AMDUAT_PEL_RUN_EXIT_STORE;
goto cleanup;
}
has_output_artifact = true;
if (!amduat_asl_write_stream(stdout,
output_artifact.bytes.data,
output_artifact.bytes.len)) {
fprintf(stderr, "error: failed to write output bytes\n");
exit_code = AMDUAT_PEL_RUN_EXIT_IO;
goto cleanup;
}
if (!opts.quiet) {
char *hex_ref = NULL;
fprintf(stderr, "status=%s(%u)\n",
has_result_value
? amduat_pel_run_status_name(result_value.core_result.status)
: "UNKNOWN",
has_result_value ? (unsigned int)result_value.core_result.status
: 0u);
fprintf(stderr, "error_kind=%s(%u)\n",
has_result_value
? amduat_pel_run_error_kind_name(
result_value.core_result.summary.kind)
: "UNKNOWN",
has_result_value
? (unsigned int)result_value.core_result.summary.kind
: 0u);
fprintf(stderr, "status_code=%u\n",
has_result_value
? (unsigned int)result_value.core_result.summary.status_code
: 0u);
if (amduat_asl_ref_encode_hex(result_ref, &hex_ref)) {
fprintf(stderr, "result_ref=%s\n", hex_ref);
free(hex_ref);
}
if (has_trace_ref && amduat_asl_ref_encode_hex(trace_ref, &hex_ref)) {
fprintf(stderr, "trace_ref=%s\n", hex_ref);
free(hex_ref);
}
if (amduat_asl_ref_encode_hex(output_refs[opts.output_index], &hex_ref)) {
fprintf(stderr, "output_ref[%zu]=%s\n", opts.output_index, hex_ref);
free(hex_ref);
}
}
} else {
if (!opts.quiet) {
char *hex_ref = NULL;
fprintf(stderr, "root=%s\n", opts.root);
if (amduat_asl_ref_encode_hex(program_ref, &hex_ref)) {
fprintf(stderr, "program_ref=%s\n", hex_ref);
free(hex_ref);
}
if (opts.has_params_ref &&
amduat_asl_ref_encode_hex(params_ref, &hex_ref)) {
fprintf(stderr, "params_ref=%s\n", hex_ref);
free(hex_ref);
}
}
{
char *hex_ref = NULL;
if (!amduat_asl_ref_encode_hex(result_ref, &hex_ref)) {
fprintf(stderr, "error: failed to encode result ref\n");
exit_code = AMDUAT_PEL_RUN_EXIT_CODEC;
} else {
fprintf(stdout, "result_ref=%s\n", hex_ref);
free(hex_ref);
}
}
if (has_trace_ref) {
char *hex_ref = NULL;
if (!amduat_asl_ref_encode_hex(trace_ref, &hex_ref)) {
fprintf(stderr, "error: failed to encode trace ref\n");
exit_code = AMDUAT_PEL_RUN_EXIT_CODEC;
} else {
fprintf(stdout, "trace_ref=%s\n", hex_ref);
free(hex_ref);
}
}
for (i = 0; i < (int)output_refs_len; ++i) {
char *hex_ref = NULL;
if (!amduat_asl_ref_encode_hex(output_refs[i], &hex_ref)) {
fprintf(stderr, "error: failed to encode output ref\n");
exit_code = AMDUAT_PEL_RUN_EXIT_CODEC;
break;
}
fprintf(stdout, "output_ref[%d]=%s\n", i, hex_ref);
free(hex_ref);
}
}
cleanup:
if (has_result_value) {
amduat_enc_pel1_result_free(&result_value);
}
if (has_output_artifact) {
amduat_pel_run_free_artifact(&output_artifact);
}
if (output_refs != NULL) {
amduat_pel_surf_free_refs(output_refs, output_refs_len);
}
amduat_pel_surf_free_ref(&result_ref);
amduat_pel_run_free_artifact(&result_artifact);
if (input_refs != NULL) {
amduat_pel_run_free_refs(input_refs, opts.input_refs_len);
}
if (opts.has_params_ref) {
amduat_pel_run_free_reference(&params_ref);
}
amduat_pel_run_free_reference(&program_ref);
free(opts.input_refs);
return exit_code;
}

676
src/tools/amduat_pel_seed.c Normal file
View file

@ -0,0 +1,676 @@
#include "amduat/asl/asl_store_fs.h"
#include "amduat/asl/asl_store_fs_meta.h"
#include "amduat/asl/io.h"
#include "amduat/asl/ref_text.h"
#include "amduat/asl/store.h"
#include "amduat/enc/asl1_core_codec.h"
#include "amduat/enc/pel_program_dag.h"
#include "amduat/pel/opreg_kernel.h"
#include "amduat/pel/program_dag_desc.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
enum {
AMDUAT_PEL_SEED_EXIT_OK = 0,
AMDUAT_PEL_SEED_EXIT_USAGE = 2,
AMDUAT_PEL_SEED_EXIT_IO = 3,
AMDUAT_PEL_SEED_EXIT_NOT_FOUND = 4,
AMDUAT_PEL_SEED_EXIT_STORE = 5,
AMDUAT_PEL_SEED_EXIT_UNSUPPORTED = 6,
AMDUAT_PEL_SEED_EXIT_CODEC = 7,
AMDUAT_PEL_SEED_EXIT_CONFIG = 8
};
static const char *const AMDUAT_PEL_SEED_DEFAULT_ROOT = ".amduat-asl";
typedef enum {
AMDUAT_PEL_SEED_REF_HEX = 0,
AMDUAT_PEL_SEED_REF_BYTES = 1
} amduat_pel_seed_ref_format_t;
typedef enum {
AMDUAT_PEL_SEED_CONST = 0,
AMDUAT_PEL_SEED_CONCAT = 1,
AMDUAT_PEL_SEED_CONCAT1 = 2,
AMDUAT_PEL_SEED_SLICE = 3,
AMDUAT_PEL_SEED_HASH = 4,
AMDUAT_PEL_SEED_CONST_HASH = 5
} amduat_pel_seed_kind_t;
typedef struct {
amduat_pel_program_t program;
amduat_pel_node_t *nodes;
amduat_pel_root_ref_t *roots;
amduat_pel_dag_input_t **inputs;
amduat_octets_t *params;
size_t nodes_len;
size_t roots_len;
} amduat_pel_seed_program_t;
typedef struct {
const char *root;
const char *output_path;
amduat_pel_seed_kind_t seed;
amduat_pel_seed_ref_format_t ref_format;
bool quiet;
bool list_only;
} amduat_pel_seed_opts_t;
static void amduat_pel_seed_print_usage(FILE *stream) {
fprintf(stream,
"usage:\n"
" amduat-pel-seed [--root PATH] [--seed NAME]\n"
" [--ref-format hex|bytes] [--output PATH|-]\n"
" [--quiet]\n"
" amduat-pel-seed --list\n"
"\n"
"defaults:\n"
" --root %s\n"
" --seed const\n"
" --ref-format hex\n"
" --output -\n",
AMDUAT_PEL_SEED_DEFAULT_ROOT);
}
static void amduat_pel_seed_print_list(FILE *stream) {
fprintf(stream,
"seeds:\n"
" const Constant bytes \"hello\" (no inputs)\n"
" concat Concatenate external inputs 0 and 1\n"
" concat1 Concatenate external input 0 (identity)\n"
" slice Slice external input 0 (offset=1 length=3)\n"
" hash Hash external input 0 (HASH-ASL1-256)\n"
" const-hash Const \"hello\" then hash (no inputs)\n");
}
static bool amduat_pel_seed_parse_ref_format(
const char *text,
amduat_pel_seed_ref_format_t *out_fmt) {
if (text == NULL || out_fmt == NULL) {
return false;
}
if (strcmp(text, "hex") == 0) {
*out_fmt = AMDUAT_PEL_SEED_REF_HEX;
return true;
}
if (strcmp(text, "bytes") == 0) {
*out_fmt = AMDUAT_PEL_SEED_REF_BYTES;
return true;
}
return false;
}
static bool amduat_pel_seed_parse_kind(const char *text,
amduat_pel_seed_kind_t *out_kind) {
if (text == NULL || out_kind == NULL) {
return false;
}
if (strcmp(text, "const") == 0) {
*out_kind = AMDUAT_PEL_SEED_CONST;
return true;
}
if (strcmp(text, "concat") == 0) {
*out_kind = AMDUAT_PEL_SEED_CONCAT;
return true;
}
if (strcmp(text, "concat1") == 0) {
*out_kind = AMDUAT_PEL_SEED_CONCAT1;
return true;
}
if (strcmp(text, "slice") == 0) {
*out_kind = AMDUAT_PEL_SEED_SLICE;
return true;
}
if (strcmp(text, "hash") == 0) {
*out_kind = AMDUAT_PEL_SEED_HASH;
return true;
}
if (strcmp(text, "const-hash") == 0) {
*out_kind = AMDUAT_PEL_SEED_CONST_HASH;
return true;
}
return false;
}
static const char *amduat_pel_seed_kind_name(amduat_pel_seed_kind_t kind) {
switch (kind) {
case AMDUAT_PEL_SEED_CONST:
return "const";
case AMDUAT_PEL_SEED_CONCAT:
return "concat";
case AMDUAT_PEL_SEED_CONCAT1:
return "concat1";
case AMDUAT_PEL_SEED_SLICE:
return "slice";
case AMDUAT_PEL_SEED_HASH:
return "hash";
case AMDUAT_PEL_SEED_CONST_HASH:
return "const-hash";
default:
return "unknown";
}
}
static const char *amduat_pel_seed_store_error_str(
amduat_asl_store_error_t err) {
switch (err) {
case AMDUAT_ASL_STORE_ERR_NOT_FOUND:
return "not found";
case AMDUAT_ASL_STORE_ERR_UNSUPPORTED:
return "unsupported";
case AMDUAT_ASL_STORE_ERR_INTEGRITY:
return "integrity";
case AMDUAT_ASL_STORE_OK:
return "ok";
default:
return "unknown";
}
}
static int amduat_pel_seed_map_store_error(amduat_asl_store_error_t err) {
switch (err) {
case AMDUAT_ASL_STORE_ERR_NOT_FOUND:
return AMDUAT_PEL_SEED_EXIT_NOT_FOUND;
case AMDUAT_ASL_STORE_ERR_UNSUPPORTED:
return AMDUAT_PEL_SEED_EXIT_UNSUPPORTED;
case AMDUAT_ASL_STORE_ERR_INTEGRITY:
return AMDUAT_PEL_SEED_EXIT_STORE;
case AMDUAT_ASL_STORE_OK:
default:
return AMDUAT_PEL_SEED_EXIT_STORE;
}
}
static void amduat_pel_seed_free_reference(amduat_reference_t *ref) {
if (ref == NULL) {
return;
}
free((void *)ref->digest.data);
ref->digest.data = NULL;
ref->digest.len = 0u;
}
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_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 amduat_make_const_params(const uint8_t *bytes,
size_t len) {
size_t total = 1u + 8u + len;
uint8_t *buffer = (uint8_t *)malloc(total);
if (buffer == NULL) {
return amduat_octets(NULL, 0);
}
buffer[0] = 0x00u;
amduat_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 amduat_octets_t amduat_make_slice_params(uint64_t offset,
uint64_t length) {
uint8_t *buffer = (uint8_t *)malloc(16u);
if (buffer == NULL) {
return amduat_octets(NULL, 0);
}
amduat_store_u64_be(buffer, offset);
amduat_store_u64_be(buffer + 8, length);
return amduat_octets(buffer, 16u);
}
static amduat_octets_t amduat_make_hash_params(uint16_t hash_id) {
uint8_t *buffer = (uint8_t *)malloc(2u);
if (buffer == NULL) {
return amduat_octets(NULL, 0);
}
amduat_store_u16_be(buffer, hash_id);
return amduat_octets(buffer, 2u);
}
static bool amduat_pel_seed_program_init(amduat_pel_seed_program_t *seed,
size_t nodes_len,
size_t roots_len) {
if (seed == NULL) {
return false;
}
memset(seed, 0, sizeof(*seed));
seed->nodes = (amduat_pel_node_t *)calloc(nodes_len, sizeof(*seed->nodes));
seed->roots = (amduat_pel_root_ref_t *)calloc(roots_len,
sizeof(*seed->roots));
seed->inputs = (amduat_pel_dag_input_t **)calloc(nodes_len,
sizeof(*seed->inputs));
seed->params = (amduat_octets_t *)calloc(nodes_len, sizeof(*seed->params));
if (seed->nodes == NULL || seed->roots == NULL ||
seed->inputs == NULL || seed->params == NULL) {
return false;
}
seed->nodes_len = nodes_len;
seed->roots_len = roots_len;
seed->program.nodes = seed->nodes;
seed->program.nodes_len = nodes_len;
seed->program.roots = seed->roots;
seed->program.roots_len = roots_len;
return true;
}
static void amduat_pel_seed_program_free(amduat_pel_seed_program_t *seed) {
size_t i;
if (seed == NULL) {
return;
}
for (i = 0; i < seed->nodes_len; ++i) {
free(seed->inputs[i]);
if (seed->params[i].data != NULL) {
free((void *)seed->params[i].data);
}
}
free(seed->inputs);
free(seed->params);
free(seed->nodes);
free(seed->roots);
memset(seed, 0, sizeof(*seed));
}
static bool amduat_pel_seed_build_const(amduat_pel_seed_program_t *seed) {
static const uint8_t k_const_bytes[] = {'h', 'e', 'l', 'l', 'o'};
const char *op_const = AMDUAT_PEL_KERNEL_OP_CONST_NAME;
amduat_octets_t params;
if (!amduat_pel_seed_program_init(seed, 1u, 1u)) {
return false;
}
params = amduat_make_const_params(k_const_bytes, sizeof(k_const_bytes));
if (params.data == NULL) {
return false;
}
seed->params[0] = params;
seed->nodes[0].id = 1u;
seed->nodes[0].op.name = amduat_octets(op_const, strlen(op_const));
seed->nodes[0].op.version = 1u;
seed->nodes[0].inputs = NULL;
seed->nodes[0].inputs_len = 0u;
seed->nodes[0].params = params;
seed->roots[0].node_id = 1u;
seed->roots[0].output_index = 0u;
return true;
}
static bool amduat_pel_seed_build_concat(amduat_pel_seed_program_t *seed) {
const char *op_concat = AMDUAT_PEL_KERNEL_OP_CONCAT_NAME;
amduat_pel_dag_input_t *inputs;
if (!amduat_pel_seed_program_init(seed, 1u, 1u)) {
return false;
}
inputs = (amduat_pel_dag_input_t *)calloc(2u, sizeof(*inputs));
if (inputs == NULL) {
return false;
}
inputs[0].kind = AMDUAT_PEL_DAG_INPUT_EXTERNAL;
inputs[0].value.external.input_index = 0u;
inputs[1].kind = AMDUAT_PEL_DAG_INPUT_EXTERNAL;
inputs[1].value.external.input_index = 1u;
seed->inputs[0] = inputs;
seed->nodes[0].id = 1u;
seed->nodes[0].op.name = amduat_octets(op_concat, strlen(op_concat));
seed->nodes[0].op.version = 1u;
seed->nodes[0].inputs = inputs;
seed->nodes[0].inputs_len = 2u;
seed->nodes[0].params = amduat_octets(NULL, 0u);
seed->params[0] = seed->nodes[0].params;
seed->roots[0].node_id = 1u;
seed->roots[0].output_index = 0u;
return true;
}
static bool amduat_pel_seed_build_concat1(amduat_pel_seed_program_t *seed) {
const char *op_concat = AMDUAT_PEL_KERNEL_OP_CONCAT_NAME;
amduat_pel_dag_input_t *inputs;
if (!amduat_pel_seed_program_init(seed, 1u, 1u)) {
return false;
}
inputs = (amduat_pel_dag_input_t *)calloc(1u, sizeof(*inputs));
if (inputs == NULL) {
return false;
}
inputs[0].kind = AMDUAT_PEL_DAG_INPUT_EXTERNAL;
inputs[0].value.external.input_index = 0u;
seed->inputs[0] = inputs;
seed->nodes[0].id = 1u;
seed->nodes[0].op.name = amduat_octets(op_concat, strlen(op_concat));
seed->nodes[0].op.version = 1u;
seed->nodes[0].inputs = inputs;
seed->nodes[0].inputs_len = 1u;
seed->nodes[0].params = amduat_octets(NULL, 0u);
seed->params[0] = seed->nodes[0].params;
seed->roots[0].node_id = 1u;
seed->roots[0].output_index = 0u;
return true;
}
static bool amduat_pel_seed_build_slice(amduat_pel_seed_program_t *seed) {
const char *op_slice = AMDUAT_PEL_KERNEL_OP_SLICE_NAME;
amduat_pel_dag_input_t *inputs;
amduat_octets_t params;
if (!amduat_pel_seed_program_init(seed, 1u, 1u)) {
return false;
}
params = amduat_make_slice_params(1u, 3u);
if (params.data == NULL) {
return false;
}
seed->params[0] = params;
inputs = (amduat_pel_dag_input_t *)calloc(1u, sizeof(*inputs));
if (inputs == NULL) {
return false;
}
inputs[0].kind = AMDUAT_PEL_DAG_INPUT_EXTERNAL;
inputs[0].value.external.input_index = 0u;
seed->inputs[0] = inputs;
seed->nodes[0].id = 1u;
seed->nodes[0].op.name = amduat_octets(op_slice, strlen(op_slice));
seed->nodes[0].op.version = 1u;
seed->nodes[0].inputs = inputs;
seed->nodes[0].inputs_len = 1u;
seed->nodes[0].params = params;
seed->roots[0].node_id = 1u;
seed->roots[0].output_index = 0u;
return true;
}
static bool amduat_pel_seed_build_hash(amduat_pel_seed_program_t *seed) {
const char *op_hash = AMDUAT_PEL_KERNEL_OP_HASH_ASL1_NAME;
amduat_pel_dag_input_t *inputs;
amduat_octets_t params;
if (!amduat_pel_seed_program_init(seed, 1u, 1u)) {
return false;
}
params = amduat_make_hash_params(0x0001u);
if (params.data == NULL) {
return false;
}
seed->params[0] = params;
inputs = (amduat_pel_dag_input_t *)calloc(1u, sizeof(*inputs));
if (inputs == NULL) {
return false;
}
inputs[0].kind = AMDUAT_PEL_DAG_INPUT_EXTERNAL;
inputs[0].value.external.input_index = 0u;
seed->inputs[0] = inputs;
seed->nodes[0].id = 1u;
seed->nodes[0].op.name = amduat_octets(op_hash, strlen(op_hash));
seed->nodes[0].op.version = 1u;
seed->nodes[0].inputs = inputs;
seed->nodes[0].inputs_len = 1u;
seed->nodes[0].params = params;
seed->roots[0].node_id = 1u;
seed->roots[0].output_index = 0u;
return true;
}
static bool amduat_pel_seed_build_const_hash(amduat_pel_seed_program_t *seed) {
static const uint8_t k_const_bytes[] = {'h', 'e', 'l', 'l', 'o'};
const char *op_const = AMDUAT_PEL_KERNEL_OP_CONST_NAME;
const char *op_hash = AMDUAT_PEL_KERNEL_OP_HASH_ASL1_NAME;
amduat_pel_dag_input_t *inputs;
amduat_octets_t const_params;
amduat_octets_t hash_params;
if (!amduat_pel_seed_program_init(seed, 2u, 1u)) {
return false;
}
const_params = amduat_make_const_params(k_const_bytes,
sizeof(k_const_bytes));
if (const_params.data == NULL) {
return false;
}
seed->params[0] = const_params;
hash_params = amduat_make_hash_params(0x0001u);
if (hash_params.data == NULL) {
return false;
}
seed->params[1] = hash_params;
seed->nodes[0].id = 1u;
seed->nodes[0].op.name = amduat_octets(op_const, strlen(op_const));
seed->nodes[0].op.version = 1u;
seed->nodes[0].inputs = NULL;
seed->nodes[0].inputs_len = 0u;
seed->nodes[0].params = const_params;
inputs = (amduat_pel_dag_input_t *)calloc(1u, sizeof(*inputs));
if (inputs == NULL) {
return false;
}
inputs[0].kind = AMDUAT_PEL_DAG_INPUT_NODE;
inputs[0].value.node.node_id = 1u;
inputs[0].value.node.output_index = 0u;
seed->inputs[1] = inputs;
seed->nodes[1].id = 2u;
seed->nodes[1].op.name = amduat_octets(op_hash, strlen(op_hash));
seed->nodes[1].op.version = 1u;
seed->nodes[1].inputs = inputs;
seed->nodes[1].inputs_len = 1u;
seed->nodes[1].params = hash_params;
seed->roots[0].node_id = 2u;
seed->roots[0].output_index = 0u;
return true;
}
static bool amduat_pel_seed_build(amduat_pel_seed_kind_t kind,
amduat_pel_seed_program_t *out_seed) {
switch (kind) {
case AMDUAT_PEL_SEED_CONST:
return amduat_pel_seed_build_const(out_seed);
case AMDUAT_PEL_SEED_CONCAT:
return amduat_pel_seed_build_concat(out_seed);
case AMDUAT_PEL_SEED_CONCAT1:
return amduat_pel_seed_build_concat1(out_seed);
case AMDUAT_PEL_SEED_SLICE:
return amduat_pel_seed_build_slice(out_seed);
case AMDUAT_PEL_SEED_HASH:
return amduat_pel_seed_build_hash(out_seed);
case AMDUAT_PEL_SEED_CONST_HASH:
return amduat_pel_seed_build_const_hash(out_seed);
default:
return false;
}
}
int main(int argc, char **argv) {
amduat_pel_seed_opts_t opts;
amduat_asl_store_fs_config_t cfg;
amduat_asl_store_fs_t fs;
amduat_asl_store_t store;
amduat_pel_seed_program_t seed_program;
amduat_octets_t encoded;
amduat_artifact_t artifact;
amduat_reference_t ref;
amduat_octets_t encoded_ref;
int exit_code = AMDUAT_PEL_SEED_EXIT_OK;
int i;
memset(&opts, 0, sizeof(opts));
opts.root = AMDUAT_PEL_SEED_DEFAULT_ROOT;
opts.output_path = "-";
opts.seed = AMDUAT_PEL_SEED_CONST;
opts.ref_format = AMDUAT_PEL_SEED_REF_HEX;
for (i = 1; i < argc; ++i) {
if (strcmp(argv[i], "--root") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "error: --root requires a path\n");
return AMDUAT_PEL_SEED_EXIT_USAGE;
}
opts.root = argv[++i];
} else if (strcmp(argv[i], "--seed") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "error: --seed requires a value\n");
return AMDUAT_PEL_SEED_EXIT_USAGE;
}
if (!amduat_pel_seed_parse_kind(argv[++i], &opts.seed)) {
fprintf(stderr, "error: invalid seed\n");
return AMDUAT_PEL_SEED_EXIT_USAGE;
}
} else if (strcmp(argv[i], "--ref-format") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "error: --ref-format requires a value\n");
return AMDUAT_PEL_SEED_EXIT_USAGE;
}
if (!amduat_pel_seed_parse_ref_format(argv[++i], &opts.ref_format)) {
fprintf(stderr, "error: invalid ref-format\n");
return AMDUAT_PEL_SEED_EXIT_USAGE;
}
} else if (strcmp(argv[i], "--output") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "error: --output requires a path or -\n");
return AMDUAT_PEL_SEED_EXIT_USAGE;
}
opts.output_path = argv[++i];
} else if (strcmp(argv[i], "--quiet") == 0) {
opts.quiet = true;
} else if (strcmp(argv[i], "--list") == 0) {
opts.list_only = true;
} else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
amduat_pel_seed_print_usage(stdout);
return AMDUAT_PEL_SEED_EXIT_OK;
} else {
fprintf(stderr, "error: unknown option: %s\n", argv[i]);
return AMDUAT_PEL_SEED_EXIT_USAGE;
}
}
if (opts.list_only) {
amduat_pel_seed_print_list(stdout);
return AMDUAT_PEL_SEED_EXIT_OK;
}
if (!amduat_asl_store_fs_load_config(opts.root, &cfg)) {
fprintf(stderr, "error: failed to load store config: %s\n", opts.root);
return AMDUAT_PEL_SEED_EXIT_CONFIG;
}
if (!amduat_asl_store_fs_init(&fs, cfg.config, opts.root)) {
fprintf(stderr, "error: failed to initialize store\n");
return AMDUAT_PEL_SEED_EXIT_CONFIG;
}
amduat_asl_store_init(&store, cfg.config, amduat_asl_store_fs_ops(), &fs);
memset(&seed_program, 0, sizeof(seed_program));
if (!amduat_pel_seed_build(opts.seed, &seed_program)) {
amduat_pel_seed_program_free(&seed_program);
fprintf(stderr, "error: failed to build seed program\n");
return AMDUAT_PEL_SEED_EXIT_CODEC;
}
encoded = amduat_octets(NULL, 0);
if (!amduat_enc_pel_program_dag_encode_v1(&seed_program.program, &encoded)) {
amduat_pel_seed_program_free(&seed_program);
fprintf(stderr, "error: failed to encode program\n");
return AMDUAT_PEL_SEED_EXIT_CODEC;
}
artifact = amduat_artifact_with_type(
encoded, amduat_type_tag(AMDUAT_PEL_TYPE_TAG_PROGRAM_DAG_1));
memset(&ref, 0, sizeof(ref));
{
amduat_asl_store_error_t err =
amduat_asl_store_put(&store, artifact, &ref);
if (err != AMDUAT_ASL_STORE_OK) {
fprintf(stderr, "error: store put failed: %s\n",
amduat_pel_seed_store_error_str(err));
exit_code = amduat_pel_seed_map_store_error(err);
}
}
if (exit_code == AMDUAT_PEL_SEED_EXIT_OK) {
if (opts.ref_format == AMDUAT_PEL_SEED_REF_HEX) {
char *hex_ref = NULL;
if (!amduat_asl_ref_encode_hex(ref, &hex_ref)) {
fprintf(stderr, "error: failed to encode reference\n");
exit_code = AMDUAT_PEL_SEED_EXIT_CODEC;
} else {
if (!amduat_asl_write_text_line(opts.output_path, hex_ref)) {
fprintf(stderr, "error: failed to write output: %s\n",
opts.output_path);
exit_code = AMDUAT_PEL_SEED_EXIT_IO;
}
free(hex_ref);
}
} else {
if (!amduat_enc_asl1_core_encode_reference_v1(ref, &encoded_ref)) {
fprintf(stderr, "error: failed to encode reference\n");
exit_code = AMDUAT_PEL_SEED_EXIT_CODEC;
} else {
if (!amduat_asl_write_path(opts.output_path,
encoded_ref.data,
encoded_ref.len)) {
fprintf(stderr, "error: failed to write output: %s\n",
opts.output_path);
exit_code = AMDUAT_PEL_SEED_EXIT_IO;
}
free((void *)encoded_ref.data);
}
}
}
if (exit_code == AMDUAT_PEL_SEED_EXIT_OK && !opts.quiet) {
char *hex_ref = NULL;
fprintf(stderr, "root=%s\n", opts.root);
fprintf(stderr, "seed=%s\n", amduat_pel_seed_kind_name(opts.seed));
fprintf(stderr, "bytes=%zu\n", encoded.len);
fprintf(stderr, "type_tag=0x%08x\n",
(unsigned int)artifact.type_tag.tag_id);
if (amduat_asl_ref_encode_hex(ref, &hex_ref)) {
fprintf(stderr, "ref=%s\n", hex_ref);
free(hex_ref);
}
}
amduat_pel_seed_program_free(&seed_program);
free((void *)encoded.data);
amduat_pel_seed_free_reference(&ref);
return exit_code;
}