diff --git a/CMakeLists.txt b/CMakeLists.txt index 53c11cc..e862265 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,6 +57,7 @@ set(AMDUAT_UTIL_SRCS src/internal/varint.c src/internal/endian.c src/internal/hex.c + src/internal/log.c ) set(AMDUAT_ASL_SRCS @@ -105,6 +106,7 @@ set(AMDUAT_FORMAT_SRCS set(AMDUAT_PEL_SRCS src/kernel/pel/core.c + src/core/derivation_sid.c src/pel_stack/decode.c src/pel_stack/surf/surf.c src/pel_stack/program_dag/program_dag.c @@ -144,6 +146,10 @@ set(AMDUAT_ASL_DERIVATION_INDEX_FS_SRCS src/adapters/asl_derivation_index_fs/asl_derivation_index_fs.c ) +set(AMDUAT_ASL_MATERIALIZATION_CACHE_FS_SRCS + src/adapters/asl_materialization_cache_fs/asl_materialization_cache_fs.c +) + set(AMDUAT_TGK_STORE_MEM_SRCS src/adapters/tgk_store_mem/tgk_store_mem.c ) @@ -171,7 +177,7 @@ amduat_add_lib(format SRCS ${AMDUAT_FORMAT_SRCS}) amduat_link(format amduat_asl amduat_enc amduat_util) amduat_add_lib(pel SRCS ${AMDUAT_PEL_SRCS}) -amduat_link(pel amduat_asl amduat_enc amduat_hash_asl1 amduat_util) +amduat_link(pel amduat_asl_materialization_cache_fs amduat_asl amduat_enc amduat_hash_asl1 amduat_util) amduat_add_lib(tgk SRCS ${AMDUAT_TGK_SRCS}) amduat_link(tgk amduat_asl amduat_enc amduat_hash_asl1 amduat_util) @@ -191,6 +197,10 @@ amduat_add_lib(asl_derivation_index_fs SRCS ${AMDUAT_ASL_DERIVATION_INDEX_FS_SRC amduat_link(asl_derivation_index_fs amduat_asl amduat_enc amduat_hash_asl1 amduat_util) target_compile_definitions(amduat_asl_derivation_index_fs_obj PRIVATE _POSIX_C_SOURCE=200809L) +amduat_add_lib(asl_materialization_cache_fs SRCS ${AMDUAT_ASL_MATERIALIZATION_CACHE_FS_SRCS}) +amduat_link(asl_materialization_cache_fs amduat_asl amduat_enc amduat_hash_asl1 amduat_util) +target_compile_definitions(amduat_asl_materialization_cache_fs_obj PRIVATE _POSIX_C_SOURCE=200809L) + amduat_add_lib(tgk_store_mem SRCS ${AMDUAT_TGK_STORE_MEM_SRCS}) amduat_link(tgk_store_mem amduat_tgk amduat_asl amduat_enc amduat_hash_asl1 amduat_util) diff --git a/include/amduat/asl/asl_materialization_cache_fs.h b/include/amduat/asl/asl_materialization_cache_fs.h new file mode 100644 index 0000000..9851d56 --- /dev/null +++ b/include/amduat/asl/asl_materialization_cache_fs.h @@ -0,0 +1,40 @@ +#ifndef AMDUAT_ASL_MATERIALIZATION_CACHE_FS_H +#define AMDUAT_ASL_MATERIALIZATION_CACHE_FS_H + +#include "amduat/asl/core.h" +#include "amduat/asl/store.h" + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum { AMDUAT_ASL_MATERIALIZATION_CACHE_FS_ROOT_MAX = 1024 }; + +typedef struct { + char root_path[AMDUAT_ASL_MATERIALIZATION_CACHE_FS_ROOT_MAX]; +} amduat_asl_materialization_cache_fs_t; + +bool amduat_asl_materialization_cache_fs_init( + amduat_asl_materialization_cache_fs_t *cache, + const char *root_path); + +amduat_asl_store_error_t amduat_asl_materialization_cache_fs_get( + amduat_asl_materialization_cache_fs_t *cache, + amduat_octets_t sid, + amduat_reference_t **out_refs, + size_t *out_refs_len); + +amduat_asl_store_error_t amduat_asl_materialization_cache_fs_put( + amduat_asl_materialization_cache_fs_t *cache, + amduat_octets_t sid, + const amduat_reference_t *refs, + size_t refs_len); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* AMDUAT_ASL_MATERIALIZATION_CACHE_FS_H */ diff --git a/include/amduat/pel/derivation_sid.h b/include/amduat/pel/derivation_sid.h new file mode 100644 index 0000000..968b400 --- /dev/null +++ b/include/amduat/pel/derivation_sid.h @@ -0,0 +1,31 @@ +#ifndef AMDUAT_PEL_DERIVATION_SID_H +#define AMDUAT_PEL_DERIVATION_SID_H + +#include "amduat/asl/core.h" + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + amduat_reference_t program_ref; + const amduat_reference_t *input_refs; + size_t input_refs_len; + bool has_params_ref; + amduat_reference_t params_ref; + bool has_exec_profile; + amduat_octets_t exec_profile; +} amduat_pel_derivation_sid_input_t; + +bool amduat_pel_derivation_sid_compute( + const amduat_pel_derivation_sid_input_t *in, + amduat_octets_t *out_sid); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* AMDUAT_PEL_DERIVATION_SID_H */ diff --git a/include/amduat/util/log.h b/include/amduat/util/log.h new file mode 100644 index 0000000..99a8029 --- /dev/null +++ b/include/amduat/util/log.h @@ -0,0 +1,23 @@ +#ifndef AMDUAT_UTIL_LOG_H +#define AMDUAT_UTIL_LOG_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + AMDUAT_LOG_ERROR = 0, + AMDUAT_LOG_WARN = 1, + AMDUAT_LOG_INFO = 2, + AMDUAT_LOG_DEBUG = 3 +} amduat_log_level_t; + +void amduat_log(amduat_log_level_t level, const char *fmt, ...); + +#ifdef __cplusplus +} /* extern "C" */ +#endif + +#endif /* AMDUAT_UTIL_LOG_H */ diff --git a/src/adapters/asl_materialization_cache_fs/asl_materialization_cache_fs.c b/src/adapters/asl_materialization_cache_fs/asl_materialization_cache_fs.c new file mode 100644 index 0000000..fef8bd1 --- /dev/null +++ b/src/adapters/asl_materialization_cache_fs/asl_materialization_cache_fs.c @@ -0,0 +1,716 @@ +#include "amduat/asl/asl_materialization_cache_fs.h" + +#include "amduat/enc/asl1_core_codec.h" +#include "amduat/util/log.h" +#include "amduat/util/hex.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +enum { + AMDUAT_ASL_MATERIALIZATION_MAGIC_LEN = 8, + AMDUAT_ASL_MATERIALIZATION_VERSION = 1 +}; + +static const uint8_t k_amduat_asl_materialization_magic[ + AMDUAT_ASL_MATERIALIZATION_MAGIC_LEN] = {'A', 'S', 'L', 'M', + 'A', 'T', '1', '\0'}; + +enum { + AMDUAT_ASL_MATERIALIZATION_FLAG_TIMESTAMP = 1u << 0, + AMDUAT_ASL_MATERIALIZATION_FLAG_PEL_VERSION = 1u << 1 +}; + +typedef struct { + const uint8_t *data; + size_t len; + size_t offset; +} amduat_asl_materialization_cursor_t; + +static void amduat_asl_materialization_store_u32_le(uint8_t *out, + uint32_t value) { + out[0] = (uint8_t)(value & 0xffu); + out[1] = (uint8_t)((value >> 8) & 0xffu); + out[2] = (uint8_t)((value >> 16) & 0xffu); + out[3] = (uint8_t)((value >> 24) & 0xffu); +} + +static bool amduat_asl_materialization_read_u32_le( + amduat_asl_materialization_cursor_t *cur, + uint32_t *out) { + const uint8_t *data; + + if (cur->len - cur->offset < 4u) { + return false; + } + data = cur->data + cur->offset; + *out = (uint32_t)data[0] | ((uint32_t)data[1] << 8) | + ((uint32_t)data[2] << 16) | ((uint32_t)data[3] << 24); + cur->offset += 4u; + return true; +} + +static bool amduat_asl_materialization_read_u64_le( + amduat_asl_materialization_cursor_t *cur, + uint64_t *out) { + const uint8_t *data; + + if (cur->len - cur->offset < 8u) { + return false; + } + data = cur->data + cur->offset; + *out = (uint64_t)data[0] | ((uint64_t)data[1] << 8) | + ((uint64_t)data[2] << 16) | ((uint64_t)data[3] << 24) | + ((uint64_t)data[4] << 32) | ((uint64_t)data[5] << 40) | + ((uint64_t)data[6] << 48) | ((uint64_t)data[7] << 56); + cur->offset += 8u; + return true; +} + +static bool amduat_asl_materialization_read_u16_le( + amduat_asl_materialization_cursor_t *cur, + uint16_t *out) { + const uint8_t *data; + + if (cur->len - cur->offset < 2u) { + return false; + } + data = cur->data + cur->offset; + *out = (uint16_t)data[0] | ((uint16_t)data[1] << 8); + cur->offset += 2u; + return true; +} + +static bool amduat_asl_materialization_read_u8( + amduat_asl_materialization_cursor_t *cur, + uint8_t *out) { + if (cur->len - cur->offset < 1u) { + return false; + } + *out = cur->data[cur->offset++]; + return true; +} + +static bool amduat_asl_materialization_join_path(const char *base, + const char *segment, + char **out_path) { + size_t base_len; + size_t segment_len; + bool needs_sep; + size_t total_len; + char *buffer; + size_t offset; + + if (base == NULL || segment == NULL || out_path == NULL) { + return false; + } + if (base[0] == '\0' || segment[0] == '\0') { + return false; + } + + base_len = strlen(base); + segment_len = strlen(segment); + needs_sep = base[base_len - 1u] != '/'; + total_len = base_len + (needs_sep ? 1u : 0u) + segment_len + 1u; + + buffer = (char *)malloc(total_len); + if (buffer == NULL) { + return false; + } + + offset = 0u; + memcpy(buffer + offset, base, base_len); + offset += base_len; + if (needs_sep) { + buffer[offset++] = '/'; + } + memcpy(buffer + offset, segment, segment_len); + offset += segment_len; + buffer[offset] = '\0'; + + *out_path = buffer; + return true; +} + +static bool amduat_asl_materialization_ensure_directory(const char *path) { + struct stat st; + + if (path == NULL || path[0] == '\0') { + return false; + } + if (stat(path, &st) == 0) { + return S_ISDIR(st.st_mode); + } + if (errno != ENOENT) { + return false; + } + if (mkdir(path, 0755) != 0) { + if (errno == EEXIST) { + return stat(path, &st) == 0 && S_ISDIR(st.st_mode); + } + return false; + } + return true; +} + +static bool amduat_asl_materialization_hex_byte(uint8_t value, char out[3]) { + static const char k_hex[] = "0123456789abcdef"; + out[0] = k_hex[value >> 4u]; + out[1] = k_hex[value & 0x0fu]; + out[2] = '\0'; + return true; +} + +static char *amduat_asl_materialization_parent_dir(const char *path) { + const char *slash; + size_t len; + char *dir; + + if (path == NULL) { + return NULL; + } + slash = strrchr(path, '/'); + if (slash == NULL || slash == path) { + return NULL; + } + len = (size_t)(slash - path); + dir = (char *)malloc(len + 1u); + if (dir == NULL) { + return NULL; + } + memcpy(dir, path, len); + dir[len] = '\0'; + return dir; +} + +static bool amduat_asl_materialization_fsync_directory(const char *path) { + int fd; + int flags = O_RDONLY; + + if (path == NULL) { + return false; + } +#ifdef O_DIRECTORY + flags |= O_DIRECTORY; +#endif + fd = open(path, flags); + if (fd < 0) { + return false; + } + if (fsync(fd) != 0) { + close(fd); + return false; + } + return close(fd) == 0; +} + +static bool amduat_asl_materialization_build_sid_path( + const char *root_path, + amduat_octets_t sid, + bool ensure_dirs, + char **out_path) { + char *index_path = NULL; + char *materializations_path = NULL; + char *by_sid_path = NULL; + char *prefix_a_path = NULL; + char *prefix_b_path = NULL; + char *sid_hex = NULL; + char prefix_a[3]; + char prefix_b[3]; + bool ok = false; + + if (root_path == NULL || out_path == NULL) { + return false; + } + *out_path = NULL; + + if (sid.len < 2u || sid.data == NULL) { + return false; + } + + if (!amduat_hex_encode_alloc(sid.data, sid.len, &sid_hex)) { + return false; + } + amduat_asl_materialization_hex_byte(sid.data[0], prefix_a); + amduat_asl_materialization_hex_byte(sid.data[1], prefix_b); + + if (!amduat_asl_materialization_join_path(root_path, "index", &index_path)) { + goto cleanup; + } + if (!amduat_asl_materialization_join_path(index_path, "materializations", + &materializations_path)) { + goto cleanup; + } + if (!amduat_asl_materialization_join_path(materializations_path, "by_sid", + &by_sid_path)) { + goto cleanup; + } + if (!amduat_asl_materialization_join_path(by_sid_path, prefix_a, + &prefix_a_path)) { + goto cleanup; + } + if (!amduat_asl_materialization_join_path(prefix_a_path, prefix_b, + &prefix_b_path)) { + goto cleanup; + } + if (!amduat_asl_materialization_join_path(prefix_b_path, sid_hex, + out_path)) { + goto cleanup; + } + + if (ensure_dirs) { + if (!amduat_asl_materialization_ensure_directory(index_path) || + !amduat_asl_materialization_ensure_directory(materializations_path) || + !amduat_asl_materialization_ensure_directory(by_sid_path) || + !amduat_asl_materialization_ensure_directory(prefix_a_path) || + !amduat_asl_materialization_ensure_directory(prefix_b_path)) { + free(*out_path); + *out_path = NULL; + goto cleanup; + } + } + + ok = true; + +cleanup: + free(index_path); + free(materializations_path); + free(by_sid_path); + free(prefix_a_path); + free(prefix_b_path); + free(sid_hex); + return ok; +} + +bool amduat_asl_materialization_cache_fs_init( + amduat_asl_materialization_cache_fs_t *cache, + const char *root_path) { + size_t len; + + if (cache == NULL || root_path == NULL) { + return false; + } + len = strlen(root_path); + if (len == 0u || len >= AMDUAT_ASL_MATERIALIZATION_CACHE_FS_ROOT_MAX) { + return false; + } + memcpy(cache->root_path, root_path, len); + cache->root_path[len] = '\0'; + return true; +} + +static amduat_asl_store_error_t amduat_asl_materialization_decode_refs( + amduat_asl_materialization_cursor_t *cur, + uint32_t count, + amduat_reference_t **out_refs, + size_t *out_refs_len) { + amduat_reference_t *refs; + uint32_t i; + + if (out_refs == NULL || out_refs_len == NULL) { + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + *out_refs = NULL; + *out_refs_len = 0u; + + if (count == 0u) { + return AMDUAT_ASL_STORE_OK; + } + if (count > SIZE_MAX / sizeof(*refs)) { + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + + refs = (amduat_reference_t *)calloc(count, sizeof(*refs)); + if (refs == NULL) { + return AMDUAT_ASL_STORE_ERR_IO; + } + + for (i = 0u; i < count; ++i) { + uint32_t ref_len; + amduat_octets_t ref_bytes; + + if (!amduat_asl_materialization_read_u32_le(cur, &ref_len)) { + goto decode_error; + } + if (ref_len < 2u || cur->len - cur->offset < ref_len) { + goto decode_error; + } + ref_bytes = amduat_octets(cur->data + cur->offset, ref_len); + if (!amduat_enc_asl1_core_decode_reference_v1(ref_bytes, &refs[i])) { + goto decode_error; + } + cur->offset += ref_len; + } + + *out_refs = refs; + *out_refs_len = count; + return AMDUAT_ASL_STORE_OK; + +decode_error: + for (uint32_t j = 0u; j < i; ++j) { + amduat_reference_free(&refs[j]); + } + free(refs); + return AMDUAT_ASL_STORE_ERR_INTEGRITY; +} + +static void amduat_asl_materialization_refs_free(amduat_reference_t *refs, + size_t refs_len) { + size_t i; + + if (refs == NULL) { + return; + } + for (i = 0u; i < refs_len; ++i) { + amduat_reference_free(&refs[i]); + } + free(refs); +} + +amduat_asl_store_error_t amduat_asl_materialization_cache_fs_get( + amduat_asl_materialization_cache_fs_t *cache, + amduat_octets_t sid, + amduat_reference_t **out_refs, + size_t *out_refs_len) { + char *path = NULL; + FILE *fp = NULL; + uint8_t *buffer = NULL; + long file_size; + amduat_asl_materialization_cursor_t cur; + uint8_t flags; + uint32_t version; + uint32_t sid_len; + uint32_t output_count; + amduat_asl_store_error_t err = AMDUAT_ASL_STORE_ERR_NOT_FOUND; + + if (out_refs == NULL || out_refs_len == NULL) { + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + *out_refs = NULL; + *out_refs_len = 0u; + + if (cache == NULL || sid.len == 0u || sid.data == NULL) { + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + + if (!amduat_asl_materialization_build_sid_path(cache->root_path, sid, false, + &path)) { + return AMDUAT_ASL_STORE_ERR_IO; + } + + fp = fopen(path, "rb"); + if (fp == NULL) { + free(path); + return errno == ENOENT ? AMDUAT_ASL_STORE_ERR_NOT_FOUND + : AMDUAT_ASL_STORE_ERR_IO; + } + if (fseek(fp, 0, SEEK_END) != 0) { + fclose(fp); + free(path); + return AMDUAT_ASL_STORE_ERR_IO; + } + file_size = ftell(fp); + if (file_size < 0) { + fclose(fp); + free(path); + return AMDUAT_ASL_STORE_ERR_IO; + } + if (fseek(fp, 0, SEEK_SET) != 0) { + fclose(fp); + free(path); + return AMDUAT_ASL_STORE_ERR_IO; + } + + buffer = (uint8_t *)malloc((size_t)file_size); + if (buffer == NULL) { + fclose(fp); + free(path); + return AMDUAT_ASL_STORE_ERR_IO; + } + if (fread(buffer, 1u, (size_t)file_size, fp) != (size_t)file_size) { + free(buffer); + fclose(fp); + free(path); + return AMDUAT_ASL_STORE_ERR_IO; + } + fclose(fp); + free(path); + + cur.data = buffer; + cur.len = (size_t)file_size; + cur.offset = 0u; + + if (cur.len < AMDUAT_ASL_MATERIALIZATION_MAGIC_LEN + 4u) { + err = AMDUAT_ASL_STORE_ERR_INTEGRITY; + goto cleanup; + } + if (memcmp(cur.data, k_amduat_asl_materialization_magic, + AMDUAT_ASL_MATERIALIZATION_MAGIC_LEN) != 0) { + err = AMDUAT_ASL_STORE_ERR_INTEGRITY; + goto cleanup; + } + cur.offset += AMDUAT_ASL_MATERIALIZATION_MAGIC_LEN; + if (!amduat_asl_materialization_read_u32_le(&cur, &version) || + version != AMDUAT_ASL_MATERIALIZATION_VERSION) { + err = AMDUAT_ASL_STORE_ERR_INTEGRITY; + goto cleanup; + } + if (!amduat_asl_materialization_read_u32_le(&cur, &sid_len)) { + err = AMDUAT_ASL_STORE_ERR_INTEGRITY; + goto cleanup; + } + if (sid_len != sid.len || cur.len - cur.offset < sid_len) { + err = AMDUAT_ASL_STORE_ERR_INTEGRITY; + goto cleanup; + } + if (memcmp(cur.data + cur.offset, sid.data, sid.len) != 0) { + err = AMDUAT_ASL_STORE_ERR_INTEGRITY; + goto cleanup; + } + cur.offset += sid_len; + if (!amduat_asl_materialization_read_u32_le(&cur, &output_count)) { + err = AMDUAT_ASL_STORE_ERR_INTEGRITY; + goto cleanup; + } + + err = amduat_asl_materialization_decode_refs(&cur, output_count, out_refs, + out_refs_len); + if (err != AMDUAT_ASL_STORE_OK) { + goto cleanup; + } + + if (!amduat_asl_materialization_read_u8(&cur, &flags)) { + err = AMDUAT_ASL_STORE_ERR_INTEGRITY; + goto cleanup; + } + if (flags & AMDUAT_ASL_MATERIALIZATION_FLAG_TIMESTAMP) { + uint64_t ignored; + if (!amduat_asl_materialization_read_u64_le(&cur, &ignored)) { + err = AMDUAT_ASL_STORE_ERR_INTEGRITY; + goto cleanup; + } + } + if (flags & AMDUAT_ASL_MATERIALIZATION_FLAG_PEL_VERSION) { + uint16_t ignored; + if (!amduat_asl_materialization_read_u16_le(&cur, &ignored)) { + err = AMDUAT_ASL_STORE_ERR_INTEGRITY; + goto cleanup; + } + } + + if (cur.offset != cur.len) { + err = AMDUAT_ASL_STORE_ERR_INTEGRITY; + goto cleanup; + } + + err = AMDUAT_ASL_STORE_OK; + +cleanup: + if (err != AMDUAT_ASL_STORE_OK) { + amduat_asl_materialization_refs_free(*out_refs, *out_refs_len); + *out_refs = NULL; + *out_refs_len = 0u; + } + free(buffer); + return err; +} + +static bool amduat_asl_materialization_refs_equal( + const amduat_reference_t *a, + size_t a_len, + const amduat_reference_t *b, + size_t b_len) { + size_t i; + + if (a_len != b_len) { + return false; + } + for (i = 0; i < a_len; ++i) { + if (!amduat_reference_eq(a[i], b[i])) { + return false; + } + } + return true; +} + +static amduat_asl_store_error_t amduat_asl_materialization_write_record( + FILE *fp, + amduat_octets_t sid, + const amduat_reference_t *refs, + size_t refs_len) { + uint8_t header[AMDUAT_ASL_MATERIALIZATION_MAGIC_LEN + 4u]; + uint8_t flags = 0u; + uint32_t count_u32; + size_t i; + + if (sid.len > UINT32_MAX || refs_len > UINT32_MAX) { + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + + memcpy(header, k_amduat_asl_materialization_magic, + AMDUAT_ASL_MATERIALIZATION_MAGIC_LEN); + amduat_asl_materialization_store_u32_le( + header + AMDUAT_ASL_MATERIALIZATION_MAGIC_LEN, + AMDUAT_ASL_MATERIALIZATION_VERSION); + if (fwrite(header, 1u, sizeof(header), fp) != sizeof(header)) { + return AMDUAT_ASL_STORE_ERR_IO; + } + + amduat_asl_materialization_store_u32_le(header, (uint32_t)sid.len); + if (fwrite(header, 1u, 4u, fp) != 4u) { + return AMDUAT_ASL_STORE_ERR_IO; + } + if (sid.len != 0u && + fwrite(sid.data, 1u, sid.len, fp) != sid.len) { + return AMDUAT_ASL_STORE_ERR_IO; + } + + count_u32 = (uint32_t)refs_len; + amduat_asl_materialization_store_u32_le(header, count_u32); + if (fwrite(header, 1u, 4u, fp) != 4u) { + return AMDUAT_ASL_STORE_ERR_IO; + } + + for (i = 0u; i < refs_len; ++i) { + amduat_octets_t ref_bytes = amduat_octets(NULL, 0u); + uint8_t len_buf[4u]; + if (!amduat_enc_asl1_core_encode_reference_v1(refs[i], &ref_bytes)) { + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + amduat_asl_materialization_store_u32_le(len_buf, + (uint32_t)ref_bytes.len); + if (fwrite(len_buf, 1u, 4u, fp) != 4u || + (ref_bytes.len != 0u && + fwrite(ref_bytes.data, 1u, ref_bytes.len, fp) != ref_bytes.len)) { + free((void *)ref_bytes.data); + return AMDUAT_ASL_STORE_ERR_IO; + } + free((void *)ref_bytes.data); + } + + if (fwrite(&flags, 1u, 1u, fp) != 1u) { + return AMDUAT_ASL_STORE_ERR_IO; + } + + return AMDUAT_ASL_STORE_OK; +} + +amduat_asl_store_error_t amduat_asl_materialization_cache_fs_put( + amduat_asl_materialization_cache_fs_t *cache, + amduat_octets_t sid, + const amduat_reference_t *refs, + size_t refs_len) { + amduat_reference_t *existing_refs = NULL; + size_t existing_len = 0u; + amduat_asl_store_error_t err; + char *path = NULL; + char *tmp_path = NULL; + FILE *fp = NULL; + size_t tmp_len; + + if (cache == NULL || sid.len == 0u || sid.data == NULL) { + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + if (refs_len != 0u && refs == NULL) { + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + + err = amduat_asl_materialization_cache_fs_get(cache, sid, + &existing_refs, &existing_len); + if (err == AMDUAT_ASL_STORE_OK) { + bool same = amduat_asl_materialization_refs_equal( + existing_refs, existing_len, refs, refs_len); + amduat_asl_materialization_refs_free(existing_refs, existing_len); + if (!same) { + amduat_log(AMDUAT_LOG_ERROR, + "materialization cache SID collision with mismatched outputs"); + return AMDUAT_ASL_STORE_ERR_INTEGRITY; + } + return AMDUAT_ASL_STORE_OK; + } + if (err != AMDUAT_ASL_STORE_ERR_NOT_FOUND) { + return err; + } + + if (!amduat_asl_materialization_build_sid_path(cache->root_path, sid, true, + &path)) { + return AMDUAT_ASL_STORE_ERR_IO; + } + + tmp_len = strlen(path) + 5u; + tmp_path = (char *)malloc(tmp_len); + if (tmp_path == NULL) { + free(path); + return AMDUAT_ASL_STORE_ERR_IO; + } + snprintf(tmp_path, tmp_len, "%s.tmp", path); + + fp = fopen(tmp_path, "wb"); + if (fp == NULL) { + free(tmp_path); + free(path); + return AMDUAT_ASL_STORE_ERR_IO; + } + + /* + * Crash consistency: write + fsync temp file, rename, then fsync parent + * directory. Failure only affects cache persistence, not correctness. + */ + err = amduat_asl_materialization_write_record(fp, sid, refs, refs_len); + if (fflush(fp) != 0) { + err = AMDUAT_ASL_STORE_ERR_IO; + } + if (err == AMDUAT_ASL_STORE_OK && fsync(fileno(fp)) != 0) { + err = AMDUAT_ASL_STORE_ERR_IO; + } + if (fclose(fp) != 0) { + err = AMDUAT_ASL_STORE_ERR_IO; + } + fp = NULL; + + if (err == AMDUAT_ASL_STORE_OK && rename(tmp_path, path) != 0) { + err = AMDUAT_ASL_STORE_ERR_IO; + } + if (err == AMDUAT_ASL_STORE_OK) { + char *parent_dir = amduat_asl_materialization_parent_dir(path); + if (parent_dir != NULL) { + if (!amduat_asl_materialization_fsync_directory(parent_dir)) { + amduat_log(AMDUAT_LOG_WARN, + "materialization cache fsync dir failed for %s", + parent_dir); + err = AMDUAT_ASL_STORE_ERR_IO; + } + free(parent_dir); + } + } + if (err != AMDUAT_ASL_STORE_OK) { + (void)remove(tmp_path); + } + +#ifndef NDEBUG + if (err == AMDUAT_ASL_STORE_OK) { + amduat_reference_t *check_refs = NULL; + size_t check_len = 0u; + amduat_asl_store_error_t check_err = + amduat_asl_materialization_cache_fs_get(cache, sid, &check_refs, + &check_len); + assert(check_err == AMDUAT_ASL_STORE_OK); + assert(amduat_asl_materialization_refs_equal( + check_refs, check_len, refs, refs_len)); + amduat_asl_materialization_refs_free(check_refs, check_len); + } +#endif + + free(tmp_path); + free(path); + return err; +} diff --git a/src/core/derivation_sid.c b/src/core/derivation_sid.c new file mode 100644 index 0000000..d5d20cd --- /dev/null +++ b/src/core/derivation_sid.c @@ -0,0 +1,163 @@ +#include "amduat/pel/derivation_sid.h" + +#include "amduat/enc/asl1_core_codec.h" +#include "amduat/hash/asl1.h" + +#include +#include +#include +#include +#include + +static bool amduat_derivation_sid_check_ref(amduat_reference_t ref) { + const amduat_hash_asl1_desc_t *desc; + size_t digest_len; + + if (ref.digest.len != 0 && ref.digest.data == NULL) { + return false; + } + if (amduat_hash_asl1_is_reserved(ref.hash_id)) { + return false; + } + + desc = amduat_hash_asl1_desc_lookup(ref.hash_id); + digest_len = ref.digest.len; + if (desc != NULL && desc->digest_len != 0) { + assert(desc->digest_len == digest_len); + if (desc->digest_len != digest_len) { + return false; + } + } + + return true; +} + +bool amduat_pel_derivation_sid_compute( + const amduat_pel_derivation_sid_input_t *in, + amduat_octets_t *out_sid) { + amduat_hash_asl1_stream_t stream; + uint8_t marker; + size_t i; + + if (out_sid == NULL) { + return false; + } + out_sid->data = NULL; + out_sid->len = 0; + + if (in == NULL) { + return false; + } + if (in->input_refs_len != 0 && in->input_refs == NULL) { + return false; + } + if (in->has_params_ref && !amduat_derivation_sid_check_ref(in->params_ref)) { + return false; + } + if (!amduat_derivation_sid_check_ref(in->program_ref)) { + return false; + } + for (i = 0; i < in->input_refs_len; ++i) { + if (!amduat_derivation_sid_check_ref(in->input_refs[i])) { + return false; + } + } + + if (!amduat_hash_asl1_stream_init(AMDUAT_HASH_ASL1_ID_SHA256, &stream)) { + return false; + } + + { + amduat_octets_t ref_bytes = amduat_octets(NULL, 0u); + bool ok; + + /* ReferenceBytes are self-delimiting because hash_id implies digest_len. */ + ok = amduat_enc_asl1_core_encode_reference_v1(in->program_ref, &ref_bytes); + if (!ok || + !amduat_hash_asl1_stream_update(&stream, ref_bytes.data, + ref_bytes.len)) { + amduat_hash_asl1_stream_destroy(&stream); + free((void *)ref_bytes.data); + return false; + } + free((void *)ref_bytes.data); + } + + for (i = 0; i < in->input_refs_len; ++i) { + amduat_octets_t ref_bytes = amduat_octets(NULL, 0u); + bool ok = amduat_enc_asl1_core_encode_reference_v1(in->input_refs[i], + &ref_bytes); + if (!ok || + !amduat_hash_asl1_stream_update(&stream, ref_bytes.data, + ref_bytes.len)) { + amduat_hash_asl1_stream_destroy(&stream); + free((void *)ref_bytes.data); + return false; + } + free((void *)ref_bytes.data); + } + + marker = in->has_params_ref ? 0x01u : 0x00u; + if (!amduat_hash_asl1_stream_update(&stream, &marker, 1u)) { + amduat_hash_asl1_stream_destroy(&stream); + return false; + } + if (in->has_params_ref) { + amduat_octets_t ref_bytes = amduat_octets(NULL, 0u); + bool ok = amduat_enc_asl1_core_encode_reference_v1(in->params_ref, + &ref_bytes); + if (!ok || + !amduat_hash_asl1_stream_update(&stream, ref_bytes.data, + ref_bytes.len)) { + amduat_hash_asl1_stream_destroy(&stream); + free((void *)ref_bytes.data); + return false; + } + free((void *)ref_bytes.data); + } + + /* ExecProfile is currently absent; presence must be explicitly marked. */ + marker = in->has_exec_profile ? 0x01u : 0x00u; + if (!amduat_hash_asl1_stream_update(&stream, &marker, 1u)) { + amduat_hash_asl1_stream_destroy(&stream); + return false; + } + if (in->has_exec_profile) { + if (in->exec_profile.len != 0 && in->exec_profile.data == NULL) { + amduat_hash_asl1_stream_destroy(&stream); + return false; + } + if (!amduat_hash_asl1_stream_update(&stream, in->exec_profile.data, + in->exec_profile.len)) { + amduat_hash_asl1_stream_destroy(&stream); + return false; + } + } + + { + const amduat_hash_asl1_desc_t *desc = + amduat_hash_asl1_desc_lookup(AMDUAT_HASH_ASL1_ID_SHA256); + uint8_t *digest; + size_t digest_len; + + if (desc == NULL || desc->digest_len == 0u) { + amduat_hash_asl1_stream_destroy(&stream); + return false; + } + digest_len = desc->digest_len; + digest = (uint8_t *)malloc(digest_len); + if (digest == NULL) { + amduat_hash_asl1_stream_destroy(&stream); + return false; + } + if (!amduat_hash_asl1_stream_final(&stream, digest, digest_len)) { + free(digest); + amduat_hash_asl1_stream_destroy(&stream); + return false; + } + amduat_hash_asl1_stream_destroy(&stream); + *out_sid = amduat_octets(digest, digest_len); + } + + return true; +} diff --git a/src/internal/log.c b/src/internal/log.c new file mode 100644 index 0000000..6d67deb --- /dev/null +++ b/src/internal/log.c @@ -0,0 +1,41 @@ +#include "amduat/util/log.h" + +#include +#include + +static const char *amduat_log_level_label(amduat_log_level_t level) { + switch (level) { + case AMDUAT_LOG_ERROR: + return "ERROR"; + case AMDUAT_LOG_WARN: + return "WARN"; + case AMDUAT_LOG_INFO: + return "INFO"; + case AMDUAT_LOG_DEBUG: + return "DEBUG"; + default: + return "LOG"; + } +} + +static bool amduat_log_debug_enabled(void) { +#ifdef AMDUAT_LOG_ENABLE_DEBUG + return true; +#else + return false; +#endif +} + +void amduat_log(amduat_log_level_t level, const char *fmt, ...) { + va_list ap; + + if (level == AMDUAT_LOG_DEBUG && !amduat_log_debug_enabled()) { + return; + } + + fprintf(stderr, "%s: ", amduat_log_level_label(level)); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fputc('\n', stderr); +} diff --git a/src/pel_stack/surf/surf.c b/src/pel_stack/surf/surf.c index 9d3355b..3f3fb54 100644 --- a/src/pel_stack/surf/surf.c +++ b/src/pel_stack/surf/surf.c @@ -1,12 +1,17 @@ #include "amduat/pel/surf.h" +#include "amduat/asl/asl_materialization_cache_fs.h" +#include "amduat/asl/asl_store_fs.h" #include "amduat/enc/pel1_result.h" #include "amduat/enc/pel_program_dag.h" #include "amduat/enc/pel_trace_dag.h" +#include "amduat/pel/derivation_sid.h" +#include "amduat/util/log.h" #include "pel_program_dag_internal.h" #include "amduat/pel/program_dag_desc.h" #include +#include #include #include #include @@ -217,6 +222,37 @@ static void amduat_trace_nodes_free(amduat_pel_node_trace_dag_t *nodes, free(nodes); } +static const char k_materialized_hit_op_name[] = "materialized_hit"; + +static bool amduat_pel_surf_store_fs_ctx( + const amduat_asl_store_t *store, + amduat_asl_store_fs_t **out_fs) { + amduat_asl_store_ops_t fs_ops; + + if (out_fs == NULL) { + return false; + } + *out_fs = NULL; + if (store == NULL) { + return false; + } + + fs_ops = amduat_asl_store_fs_ops(); + if (store->ops.put != fs_ops.put || + store->ops.get != fs_ops.get || + store->ops.put_indexed != fs_ops.put_indexed || + store->ops.get_indexed != fs_ops.get_indexed || + store->ops.tombstone != fs_ops.tombstone || + store->ops.tombstone_lift != fs_ops.tombstone_lift || + store->ops.log_scan != fs_ops.log_scan || + store->ops.current_state != fs_ops.current_state || + store->ops.validate_config != fs_ops.validate_config) { + return false; + } + *out_fs = (amduat_asl_store_fs_t *)store->ctx; + return *out_fs != NULL; +} + static bool amduat_store_trace( amduat_asl_store_t *store, amduat_reference_t scheme_ref, @@ -230,6 +266,7 @@ static bool amduat_store_trace( const amduat_pel_execution_result_value_t *core_result, const amduat_pel_program_t *program, const amduat_pel_program_dag_trace_t *trace_eval, + bool materialized_hit, amduat_reference_t *out_trace_ref) { amduat_pel_trace_dag_value_t trace; amduat_pel_node_trace_dag_t *node_traces; @@ -311,6 +348,29 @@ static bool amduat_store_trace( } } + if (materialized_hit) { + amduat_pel_node_trace_dag_t *next; + + /* Emit a synthetic trace entry to mark a materialization cache hit. */ + next = (amduat_pel_node_trace_dag_t *)realloc( + node_traces, (node_count + 1u) * sizeof(*node_traces)); + if (next == NULL) { + amduat_trace_nodes_free(node_traces, node_count); + return false; + } + node_traces = next; + memset(&node_traces[node_count], 0, sizeof(*node_traces)); + /* UINT32_MAX is a reserved sentinel; decoders treat node_id as opaque. */ + node_traces[node_count].node_id = UINT32_MAX; + node_traces[node_count].op_name = amduat_octets( + (const uint8_t *)k_materialized_hit_op_name, + sizeof(k_materialized_hit_op_name) - 1u); + node_traces[node_count].op_version = 1u; + node_traces[node_count].status = AMDUAT_PEL_NODE_TRACE_SKIPPED; + node_traces[node_count].status_code = 0u; + node_count += 1u; + } + memset(&trace, 0, sizeof(trace)); trace.pel1_version = 1; trace.scheme_ref = scheme_ref; @@ -367,6 +427,8 @@ bool amduat_pel_surf_run(amduat_asl_store_t *store, size_t outputs_len; amduat_reference_t *output_refs; size_t output_refs_len; + amduat_asl_materialization_cache_fs_t mat_cache; + amduat_octets_t sid; amduat_reference_t trace_ref; amduat_reference_t exec_result_ref; size_t i; @@ -375,6 +437,10 @@ bool amduat_pel_surf_run(amduat_asl_store_t *store, bool exec_invoked = false; bool trace_ok = false; bool has_exec_result_ref = false; + bool mat_cache_ready = false; + bool materialized_hit = false; + bool cache_miss_due_missing = false; + bool executed = false; if (store == NULL || out_output_refs == NULL || out_output_refs_len == NULL || out_result_ref == NULL) { @@ -392,6 +458,7 @@ bool amduat_pel_surf_run(amduat_asl_store_t *store, trace_ref.digest = amduat_octets(NULL, 0); exec_result_ref.hash_id = 0; exec_result_ref.digest = amduat_octets(NULL, 0); + sid = amduat_octets(NULL, 0); if (!amduat_reference_eq(scheme_ref, amduat_pel_program_dag_scheme_ref())) { @@ -490,6 +557,75 @@ bool amduat_pel_surf_run(amduat_asl_store_t *store, has_params_artifact = true; } + /* + * Cache safety assumptions: + * - PEL DAG execution is deterministic for ProgramRef + Inputs + Params. + * - ExecProfile is currently absent and encoded as a marker only. + * - The store is single-tenant; SID collisions are treated as integrity errors. + * - This code path assumes amduat_asl_store_fs_t as the backing store. + */ + { + amduat_pel_derivation_sid_input_t sid_input; + + memset(&sid_input, 0, sizeof(sid_input)); + sid_input.program_ref = program_ref; + sid_input.input_refs = input_refs; + sid_input.input_refs_len = input_refs_len; + sid_input.has_params_ref = has_params_ref; + if (has_params_ref) { + sid_input.params_ref = params_ref; + } + sid_input.has_exec_profile = false; + sid_input.exec_profile = amduat_octets(NULL, 0u); + + if (amduat_pel_derivation_sid_compute(&sid_input, &sid)) { + amduat_asl_store_fs_t *fs = NULL; + if (amduat_pel_surf_store_fs_ctx(store, &fs) && + amduat_asl_materialization_cache_fs_init(&mat_cache, + fs->root_path)) { + mat_cache_ready = true; + } + } + } + + if (mat_cache_ready) { + amduat_reference_t *cached_refs = NULL; + size_t cached_len = 0; + amduat_asl_store_error_t cache_err; + + cache_err = amduat_asl_materialization_cache_fs_get(&mat_cache, sid, + &cached_refs, + &cached_len); + if (cache_err == AMDUAT_ASL_STORE_OK) { + bool cache_valid = true; + for (i = 0; i < cached_len; ++i) { + amduat_artifact_t cached_artifact; + if (amduat_asl_store_get(store, cached_refs[i], + &cached_artifact) != + AMDUAT_ASL_STORE_OK) { + cache_valid = false; + break; + } + amduat_artifact_free(&cached_artifact); + } + if (cache_valid) { + output_refs = cached_refs; + output_refs_len = cached_len; + materialized_hit = true; + exec_invoked = true; + amduat_init_core_result(&core_result, scheme_ref, + AMDUAT_PEL_EXEC_STATUS_OK, + AMDUAT_PEL_EXEC_ERROR_NONE, 0); + outputs = NULL; + outputs_len = 0; + amduat_artifact_free(&program_artifact); + goto cache_hit; + } + cache_miss_due_missing = true; + amduat_pel_surf_free_refs(cached_refs, cached_len); + } + } + exec_invoked = true; outputs = NULL; outputs_len = 0; @@ -570,6 +706,7 @@ bool amduat_pel_surf_run(amduat_asl_store_t *store, amduat_pel_program_dag_free_outputs(outputs, outputs_len); return false; } + executed = true; } } } @@ -593,6 +730,27 @@ bool amduat_pel_surf_run(amduat_asl_store_t *store, } } + if (mat_cache_ready) { + (void)amduat_asl_materialization_cache_fs_put(&mat_cache, sid, + output_refs, output_refs_len); + } + +cache_hit: +#ifndef NDEBUG + if (cache_miss_due_missing) { + assert(!materialized_hit); + } +#endif + if (materialized_hit) { + amduat_log(AMDUAT_LOG_DEBUG, "pel surf: materialization hit"); + } else if (executed) { + if (cache_miss_due_missing) { + amduat_log(AMDUAT_LOG_DEBUG, + "pel surf: executed (cache miss: missing outputs)"); + } else { + amduat_log(AMDUAT_LOG_DEBUG, "pel surf: executed"); + } + } trace_ok = false; if (exec_invoked) { if (!amduat_store_surface_result( @@ -607,7 +765,9 @@ bool amduat_pel_surf_run(amduat_asl_store_t *store, has_params_ref, params_ref, has_exec_result_ref, exec_result_ref, &core_result, program_decoded ? &program : NULL, - program_decoded ? &trace_eval : NULL, &trace_ref); + program_decoded ? &trace_eval : NULL, + materialized_hit, + &trace_ref); if (!trace_ok) { goto cleanup; } @@ -637,6 +797,7 @@ bool amduat_pel_surf_run(amduat_asl_store_t *store, amduat_pel_program_dag_free_outputs(outputs, outputs_len); amduat_pel_execution_result_free(&core_result); amduat_pel_surf_free_ref(&exec_result_ref); + amduat_octets_free(&sid); return true; cleanup: @@ -655,5 +816,6 @@ cleanup: amduat_pel_program_dag_free_outputs(outputs, outputs_len); amduat_pel_execution_result_free(&core_result); amduat_pel_surf_free_ref(&exec_result_ref); + amduat_octets_free(&sid); return false; } diff --git a/src/tools/amduat_pel_cli.c b/src/tools/amduat_pel_cli.c index ba0b5aa..e967cbb 100644 --- a/src/tools/amduat_pel_cli.c +++ b/src/tools/amduat_pel_cli.c @@ -1,5 +1,6 @@ #include "amduat/asl/artifact_io.h" #include "amduat/asl/asl_derivation_index_fs.h" +#include "amduat/asl/asl_materialization_cache_fs.h" #include "amduat/asl/asl_store_fs.h" #include "amduat/asl/asl_store_fs_meta.h" #include "amduat/asl/io.h" @@ -18,11 +19,13 @@ #include "amduat/format/pel.h" #include "amduat/format/ref.h" #include "amduat/pel/decode.h" +#include "amduat/pel/derivation_sid.h" #include "amduat/pel/opreg_kernel.h" #include "amduat/pel/opreg_kernel_params.h" #include "amduat/pel/program_dag_desc.h" #include "amduat/pel/run.h" #include "amduat/pel/surf.h" +#include "amduat/util/hex.h" #include #include @@ -66,6 +69,7 @@ static void amduat_pel_cli_print_usage(FILE *stream) { " trace Trace DAG tools (decode, from-result).\n" " result Surface result tools (decode).\n" " op Kernel op registry tools.\n" + " matcache Materialization cache tools (get, sid).\n" " scheme Scheme refs, type tags, profile IDs.\n" " help Show help for a command.\n" "\n" @@ -135,6 +139,11 @@ static void amduat_pel_cli_print_usage(FILE *stream) { " amduat-pel scheme show [--format text|json] [--ref-format hex|bytes]\n" " amduat-pel scheme dag-ref [--format hex|bytes]\n" "\n" + "matcache:\n" + " amduat-pel matcache get --sid HEX [--verify]\n" + " amduat-pel matcache sid --program-ref REF --input-ref REF...\n" + " [--params-ref REF]\n" + "\n" "defaults:\n" " --root .amduat-asl\n" " --ref-format hex\n" @@ -355,41 +364,68 @@ static bool amduat_pel_cli_index_derivations( return false; } - for (i = 0u; i < output_refs_len; ++i) { - amduat_asl_derivation_record_t record; + { + amduat_pel_derivation_sid_input_t sid_input; amduat_octets_t sid = amduat_octets(NULL, 0u); - amduat_asl_store_error_t err; - if (!amduat_octets_clone(output_refs[i].digest, &sid)) { - if (!quiet) { - fprintf(stderr, "error: failed to allocate derivation sid\n"); - } - return false; - } - - memset(&record, 0, sizeof(record)); - record.sid = sid; - record.program_ref = program_ref; - record.output_index = (uint32_t)i; - record.input_refs = (amduat_reference_t *)input_refs; - record.input_refs_len = input_refs_len; - record.has_params_ref = has_params_ref; + memset(&sid_input, 0, sizeof(sid_input)); + sid_input.program_ref = program_ref; + sid_input.input_refs = input_refs; + sid_input.input_refs_len = input_refs_len; + sid_input.has_params_ref = has_params_ref; if (has_params_ref) { - record.params_ref = params_ref; + sid_input.params_ref = params_ref; } - record.has_exec_profile = false; - record.exec_profile = amduat_octets(NULL, 0u); + sid_input.has_exec_profile = false; + sid_input.exec_profile = amduat_octets(NULL, 0u); - err = amduat_asl_derivation_index_fs_add(&index, - output_refs[i], - &record); - amduat_octets_free(&record.sid); - if (err != AMDUAT_ASL_STORE_OK) { + if (!amduat_pel_derivation_sid_compute(&sid_input, &sid)) { if (!quiet) { - fprintf(stderr, "error: derivation index add failed: %d\n", err); + fprintf(stderr, "error: failed to compute derivation sid\n"); } return false; } + + for (i = 0u; i < output_refs_len; ++i) { + amduat_asl_derivation_record_t record; + amduat_asl_store_error_t err; + amduat_octets_t record_sid = amduat_octets(NULL, 0u); + + if (!amduat_octets_clone(sid, &record_sid)) { + if (!quiet) { + fprintf(stderr, "error: failed to clone derivation sid\n"); + } + amduat_octets_free(&sid); + return false; + } + + memset(&record, 0, sizeof(record)); + record.sid = record_sid; + record.program_ref = program_ref; + record.output_index = (uint32_t)i; + record.input_refs = (amduat_reference_t *)input_refs; + record.input_refs_len = input_refs_len; + record.has_params_ref = has_params_ref; + if (has_params_ref) { + record.params_ref = params_ref; + } + record.has_exec_profile = false; + record.exec_profile = amduat_octets(NULL, 0u); + + err = amduat_asl_derivation_index_fs_add(&index, + output_refs[i], + &record); + amduat_octets_free(&record.sid); + if (err != AMDUAT_ASL_STORE_OK) { + if (!quiet) { + fprintf(stderr, "error: derivation index add failed: %d\n", err); + } + amduat_octets_free(&sid); + return false; + } + } + + amduat_octets_free(&sid); } return true; @@ -2723,6 +2759,257 @@ static int amduat_pel_cli_cmd_scheme( return AMDUAT_PEL_CLI_EXIT_USAGE; } +static int amduat_pel_cli_cmd_matcache_get( + int argc, + char **argv, + const amduat_pel_cli_global_opts_t *global) { + const char *sid_hex = NULL; + bool verify = false; + uint8_t *sid_bytes = NULL; + size_t sid_len = 0u; + amduat_asl_materialization_cache_fs_t cache; + amduat_reference_t *refs = NULL; + size_t refs_len = 0u; + int i; + + if (global == NULL) { + return AMDUAT_PEL_CLI_EXIT_USAGE; + } + + for (i = 0; i < argc; ++i) { + if (strcmp(argv[i], "--sid") == 0) { + if (i + 1 >= argc) { + fprintf(stderr, "error: --sid requires a value\n"); + return AMDUAT_PEL_CLI_EXIT_USAGE; + } + sid_hex = argv[++i]; + } else if (strcmp(argv[i], "--verify") == 0) { + verify = true; + } else if (strcmp(argv[i], "--help") == 0 || + strcmp(argv[i], "-h") == 0) { + amduat_pel_cli_print_usage(stdout); + return AMDUAT_PEL_CLI_EXIT_OK; + } else { + fprintf(stderr, "error: unknown option: %s\n", argv[i]); + return AMDUAT_PEL_CLI_EXIT_USAGE; + } + } + + if (sid_hex == NULL) { + fprintf(stderr, "error: --sid is required\n"); + return AMDUAT_PEL_CLI_EXIT_USAGE; + } + if (!amduat_hex_decode_alloc(sid_hex, &sid_bytes, &sid_len)) { + fprintf(stderr, "error: invalid SID hex\n"); + return AMDUAT_PEL_CLI_EXIT_USAGE; + } + if (!amduat_asl_materialization_cache_fs_init(&cache, global->root)) { + free(sid_bytes); + fprintf(stderr, "error: failed to init materialization cache\n"); + return AMDUAT_PEL_CLI_EXIT_CONFIG; + } + + { + amduat_octets_t sid = amduat_octets(sid_bytes, sid_len); + amduat_asl_store_error_t err = + amduat_asl_materialization_cache_fs_get(&cache, sid, &refs, &refs_len); + if (err != AMDUAT_ASL_STORE_OK) { + free(sid_bytes); + return amduat_pel_cli_map_store_error(err); + } + + { + char *sid_norm = NULL; + if (amduat_hex_encode_alloc(sid_bytes, sid_len, &sid_norm)) { + printf("sid=%s\n", sid_norm); + free(sid_norm); + } + } + printf("outputs=%zu\n", refs_len); + for (size_t j = 0u; j < refs_len; ++j) { + fputs("output_ref=", stdout); + if (!amduat_format_ref_write_text(stdout, refs[j], + global->ref_format)) { + fprintf(stderr, "error: failed to format output ref\n"); + amduat_pel_cli_free_refs(refs, refs_len); + free(sid_bytes); + return AMDUAT_PEL_CLI_EXIT_CODEC; + } + fputc('\n', stdout); + } + + if (verify) { + err = amduat_asl_materialization_cache_fs_put(&cache, sid, refs, + refs_len); + if (err != AMDUAT_ASL_STORE_OK) { + fprintf(stderr, "error: cache verify failed: %s\n", + amduat_pel_cli_store_error_str(err)); + amduat_pel_cli_free_refs(refs, refs_len); + free(sid_bytes); + return amduat_pel_cli_map_store_error(err); + } + printf("verify=ok\n"); + } + } + + amduat_pel_cli_free_refs(refs, refs_len); + free(sid_bytes); + return AMDUAT_PEL_CLI_EXIT_OK; +} + +static int amduat_pel_cli_cmd_matcache_sid( + int argc, + char **argv, + const amduat_pel_cli_global_opts_t *global) { + const char *program_ref_text = NULL; + const char *params_ref_text = NULL; + amduat_reference_t program_ref; + amduat_reference_t params_ref; + amduat_reference_t *input_refs = NULL; + size_t input_refs_len = 0u; + bool has_params_ref = false; + bool stdin_used = false; + int i; + + if (global == NULL) { + return AMDUAT_PEL_CLI_EXIT_USAGE; + } + + for (i = 0; i < argc; ++i) { + if (strcmp(argv[i], "--program-ref") == 0) { + if (i + 1 >= argc) { + fprintf(stderr, "error: --program-ref requires a value\n"); + return AMDUAT_PEL_CLI_EXIT_USAGE; + } + program_ref_text = argv[++i]; + } else if (strcmp(argv[i], "--input-ref") == 0) { + amduat_reference_t ref; + if (i + 1 >= argc) { + fprintf(stderr, "error: --input-ref requires a value\n"); + return AMDUAT_PEL_CLI_EXIT_USAGE; + } + if (!amduat_pel_cli_ref_from_text(argv[++i], global->ref_format, + &stdin_used, &ref)) { + fprintf(stderr, "error: invalid input ref\n"); + amduat_pel_cli_free_refs(input_refs, input_refs_len); + return AMDUAT_PEL_CLI_EXIT_USAGE; + } + if (!amduat_pel_cli_append_ref(&input_refs, &input_refs_len, ref)) { + fprintf(stderr, "error: out of memory\n"); + amduat_pel_cli_free_reference(&ref); + amduat_pel_cli_free_refs(input_refs, input_refs_len); + return AMDUAT_PEL_CLI_EXIT_IO; + } + } else if (strcmp(argv[i], "--params-ref") == 0) { + if (i + 1 >= argc) { + fprintf(stderr, "error: --params-ref requires a value\n"); + amduat_pel_cli_free_refs(input_refs, input_refs_len); + return AMDUAT_PEL_CLI_EXIT_USAGE; + } + params_ref_text = argv[++i]; + has_params_ref = true; + } else if (strcmp(argv[i], "--help") == 0 || + strcmp(argv[i], "-h") == 0) { + amduat_pel_cli_print_usage(stdout); + amduat_pel_cli_free_refs(input_refs, input_refs_len); + return AMDUAT_PEL_CLI_EXIT_OK; + } else { + fprintf(stderr, "error: unknown option: %s\n", argv[i]); + amduat_pel_cli_free_refs(input_refs, input_refs_len); + return AMDUAT_PEL_CLI_EXIT_USAGE; + } + } + + if (program_ref_text == NULL || input_refs_len == 0u) { + fprintf(stderr, "error: --program-ref and --input-ref are required\n"); + amduat_pel_cli_free_refs(input_refs, input_refs_len); + return AMDUAT_PEL_CLI_EXIT_USAGE; + } + + if (!amduat_pel_cli_ref_from_text(program_ref_text, global->ref_format, + &stdin_used, &program_ref)) { + fprintf(stderr, "error: invalid program ref\n"); + amduat_pel_cli_free_refs(input_refs, input_refs_len); + return AMDUAT_PEL_CLI_EXIT_USAGE; + } + + if (has_params_ref) { + if (!amduat_pel_cli_ref_from_text(params_ref_text, global->ref_format, + &stdin_used, ¶ms_ref)) { + fprintf(stderr, "error: invalid params ref\n"); + amduat_pel_cli_free_reference(&program_ref); + amduat_pel_cli_free_refs(input_refs, input_refs_len); + return AMDUAT_PEL_CLI_EXIT_USAGE; + } + } + + { + amduat_pel_derivation_sid_input_t sid_input; + amduat_octets_t sid = amduat_octets(NULL, 0u); + char *sid_hex = NULL; + + memset(&sid_input, 0, sizeof(sid_input)); + sid_input.program_ref = program_ref; + sid_input.input_refs = input_refs; + sid_input.input_refs_len = input_refs_len; + sid_input.has_params_ref = has_params_ref; + if (has_params_ref) { + sid_input.params_ref = params_ref; + } + sid_input.has_exec_profile = false; + sid_input.exec_profile = amduat_octets(NULL, 0u); + + if (!amduat_pel_derivation_sid_compute(&sid_input, &sid)) { + fprintf(stderr, "error: failed to compute sid\n"); + if (has_params_ref) { + amduat_pel_cli_free_reference(¶ms_ref); + } + amduat_pel_cli_free_reference(&program_ref); + amduat_pel_cli_free_refs(input_refs, input_refs_len); + return AMDUAT_PEL_CLI_EXIT_CODEC; + } + + if (!amduat_hex_encode_alloc(sid.data, sid.len, &sid_hex)) { + fprintf(stderr, "error: failed to encode sid\n"); + amduat_octets_free(&sid); + if (has_params_ref) { + amduat_pel_cli_free_reference(¶ms_ref); + } + amduat_pel_cli_free_reference(&program_ref); + amduat_pel_cli_free_refs(input_refs, input_refs_len); + return AMDUAT_PEL_CLI_EXIT_CODEC; + } + printf("%s\n", sid_hex); + free(sid_hex); + amduat_octets_free(&sid); + } + + if (has_params_ref) { + amduat_pel_cli_free_reference(¶ms_ref); + } + amduat_pel_cli_free_reference(&program_ref); + amduat_pel_cli_free_refs(input_refs, input_refs_len); + return AMDUAT_PEL_CLI_EXIT_OK; +} + +static int amduat_pel_cli_cmd_matcache( + int argc, + char **argv, + const amduat_pel_cli_global_opts_t *global) { + if (argc < 1) { + fprintf(stderr, "error: matcache requires a subcommand\n"); + return AMDUAT_PEL_CLI_EXIT_USAGE; + } + if (strcmp(argv[0], "get") == 0) { + return amduat_pel_cli_cmd_matcache_get(argc - 1, argv + 1, global); + } + if (strcmp(argv[0], "sid") == 0) { + return amduat_pel_cli_cmd_matcache_sid(argc - 1, argv + 1, global); + } + fprintf(stderr, "error: unknown matcache subcommand: %s\n", argv[0]); + return AMDUAT_PEL_CLI_EXIT_USAGE; +} + static int amduat_pel_cli_cmd_help(int argc, char **argv) { (void)argc; (void)argv; @@ -2810,6 +3097,9 @@ int main(int argc, char **argv) { if (strcmp(command, "op") == 0) { return amduat_pel_cli_cmd_op(argc - i, argv + i, &global); } + if (strcmp(command, "matcache") == 0) { + return amduat_pel_cli_cmd_matcache(argc - i, argv + i, &global); + } if (strcmp(command, "scheme") == 0) { return amduat_pel_cli_cmd_scheme(argc - i, argv + i, &global); }