wip(kernel): the proxy Zuse -- a stick's first boot mints its own Zuse (#92, Task 1) [skip ci]
Work in progress on StarForth-v4.0.0; not yet accepted (plan 2026-10-29-stick-5, Task 1). - zuse_genesis_marker.h: the marker's version 2 -- the proxy's key and the real Zuse's -- beside version 1. - capsule_zuse_boot.c: capsule_zuse_boot_check_key() (the identity-record half of the check) and capsule_zuse_boot_genesis_mint() (the mint half of v3's genesis) split out; v3's two callers unchanged in behaviour. - sk_v4_marker.c: the v4 boot reads version 1 as a proxy with no real Zuse, and writes version 2. - sk_v4_identity.c: no marker and a blank identity partition -> genesis: mint, read back, then the marker; the proxy logs in. A marker with a real key: no session for the proxy (the fixed screen is Task 5). - qemu_session.py: boot()/shutdown(), so a mode can boot twice; modes genesis and stick_genesis; stick_boot now expects genesis and the prompt. Logs: genesis on amd64 before the change (both boots: "no genesis on this disk", FAIL) and after (minted, then recognised: PASS). The DoE CSV of 032532 is from a run whose QEMU never started (no display; its empty log directory was removed). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GE3SDvQn5EoxdGufk84zz2
This commit is contained in:
@@ -113,6 +113,36 @@ static void install_and_activate(VM *mama_vm, struct blkio_dev *dev,
|
||||
* "ACL-ZUSE-BOOT") above already sets. Nothing to call here anymore. */
|
||||
}
|
||||
|
||||
/* The identity-record half of the check (split out 2026-10-29 so the v4 boot
|
||||
* can check against either of the version 2 marker's keys: plan
|
||||
* 2026-10-29-stick-5, Task 1). */
|
||||
zuse_drive_t capsule_zuse_boot_check_key(struct blkio_dev *dev,
|
||||
homeblocks_sig_result_t sig_rc,
|
||||
const homeblocks_sig_t *sig,
|
||||
const uint8_t want[32],
|
||||
uint8_t seed[32], uint8_t pubkey[32]) {
|
||||
if (!dev || !want) return ZUSE_DRIVE_NOT_HERS;
|
||||
if (sig_rc != HOMEBLOCKS_SIG_OK || !sig) return ZUSE_DRIVE_NOT_HERS;
|
||||
if (sig->identity_src_offset == 0 || sig->identity_src_devblocks < 1) return ZUSE_DRIVE_NOT_HERS;
|
||||
|
||||
user_identity_seed_t idrec;
|
||||
if (read_devblock(dev, sig->identity_src_offset, (uint8_t *)&idrec) != 0) return ZUSE_DRIVE_NOT_HERS;
|
||||
/* Same magic -> version -> CRC-64 discipline as genesis_marker_read():
|
||||
* this record carries Zuse's private key (the seed), so a corrupt or
|
||||
* format-mismatched record must be refused, never loaded -- a bad CRC
|
||||
* could otherwise install a garbage seed as Zuse's identity. */
|
||||
if (idrec.magic != USER_IDENTITY_SEED_MAGIC) return ZUSE_DRIVE_NOT_HERS;
|
||||
if (idrec.version != USER_IDENTITY_SEED_VERSION) return ZUSE_DRIVE_NOT_HERS;
|
||||
uint64_t want_crc = compute_crc64((const uint8_t *)&idrec,
|
||||
offsetof(user_identity_seed_t, crc));
|
||||
if (want_crc != idrec.crc) return ZUSE_DRIVE_NOT_HERS;
|
||||
if (memcmp(idrec.pubkey, want, 32) != 0) return ZUSE_DRIVE_NOT_HERS; /* not Zuse's drive */
|
||||
|
||||
memcpy(seed, idrec.seed, 32);
|
||||
memcpy(pubkey, idrec.pubkey, 32);
|
||||
return ZUSE_DRIVE_HERS;
|
||||
}
|
||||
|
||||
/* The check, with no VM (split out 2026-10-26 so the v4 boot makes the same
|
||||
* one: docs/v4.0.0/plans/2026-10-26-engine-step4-identity-gate.md, D1). */
|
||||
zuse_drive_t capsule_zuse_boot_check(struct blkio_dev *dev,
|
||||
@@ -129,25 +159,18 @@ zuse_drive_t capsule_zuse_boot_check(struct blkio_dev *dev,
|
||||
|
||||
/* Marker present: genesis already happened, on some thumbdrive.
|
||||
* Only this drive if it is that drive. */
|
||||
if (sig_rc != HOMEBLOCKS_SIG_OK || !sig) return ZUSE_DRIVE_NOT_HERS;
|
||||
if (sig->identity_src_offset == 0 || sig->identity_src_devblocks < 1) return ZUSE_DRIVE_NOT_HERS;
|
||||
return capsule_zuse_boot_check_key(dev, sig_rc, sig, marker.zuse_pubkey, seed, pubkey);
|
||||
}
|
||||
|
||||
user_identity_seed_t idrec;
|
||||
if (read_devblock(dev, sig->identity_src_offset, (uint8_t *)&idrec) != 0) return ZUSE_DRIVE_NOT_HERS;
|
||||
/* Same magic -> version -> CRC-64 discipline as genesis_marker_read():
|
||||
* this record carries Zuse's private key (the seed), so a corrupt or
|
||||
* format-mismatched record must be refused, never loaded -- a bad CRC
|
||||
* could otherwise install a garbage seed as Zuse's identity. */
|
||||
if (idrec.magic != USER_IDENTITY_SEED_MAGIC) return ZUSE_DRIVE_NOT_HERS;
|
||||
if (idrec.version != USER_IDENTITY_SEED_VERSION) return ZUSE_DRIVE_NOT_HERS;
|
||||
uint64_t want_crc = compute_crc64((const uint8_t *)&idrec,
|
||||
offsetof(user_identity_seed_t, crc));
|
||||
if (want_crc != idrec.crc) return ZUSE_DRIVE_NOT_HERS;
|
||||
if (memcmp(idrec.pubkey, marker.zuse_pubkey, 32) != 0) return ZUSE_DRIVE_NOT_HERS; /* not Zuse's drive */
|
||||
|
||||
memcpy(seed, idrec.seed, 32);
|
||||
memcpy(pubkey, idrec.pubkey, 32);
|
||||
return ZUSE_DRIVE_HERS;
|
||||
/* The mint half of v3's genesis, with no VM (split out 2026-10-29: plan
|
||||
* 2026-10-29-stick-5, Task 1). */
|
||||
int capsule_zuse_boot_genesis_mint(struct blkio_dev *dev, uint8_t seed[32], uint8_t pubkey[32]) {
|
||||
MintResult r = capsule_mint_identity(dev, (VM *)0, "Zuse", "zuse",
|
||||
(const char *)0, (const char *)0,
|
||||
pubkey, seed,
|
||||
MINT_PERSONALITY_DEFAULT, /* Zuse is the superuser -- never restricted */
|
||||
1 /* the caller confirmed the drive BLANK */);
|
||||
return r == MINT_OK ? 0 : -1;
|
||||
}
|
||||
|
||||
int capsule_zuse_boot_root_pubkey(uint8_t pubkey[32]) {
|
||||
@@ -176,12 +199,7 @@ void capsule_zuse_boot_try_attach(struct blkio_dev *dev,
|
||||
which = capsule_zuse_boot_check(dev, sig_rc, sig, seed, pubkey);
|
||||
|
||||
if (which == ZUSE_DRIVE_GENESIS) {
|
||||
MintResult r = capsule_mint_identity(dev, (VM *)0, "Zuse", "zuse",
|
||||
(const char *)0, (const char *)0,
|
||||
pubkey, seed,
|
||||
MINT_PERSONALITY_DEFAULT, /* Zuse is the superuser -- never restricted */
|
||||
1 /* sig_rc already confirmed BLANK above */);
|
||||
if (r != MINT_OK) {
|
||||
if (capsule_zuse_boot_genesis_mint(dev, seed, pubkey) != 0) {
|
||||
console_println("Zuse: genesis mint failed");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* and Hera are the kernel's (ENGINE.md 2, Q1), so a drive that arrives is
|
||||
* given to the block subsystem here, and Zuse's session is kept here, for
|
||||
* the first node, Hera. The check that the drive is hers is v3's own
|
||||
* (capsule_zuse_boot_check()).
|
||||
* (capsule_zuse_boot_check_key(), against the genesis marker's key).
|
||||
*
|
||||
* Artemis and Zuse come from one disk, this system's stick
|
||||
* (docs/v4.0.0/STICK.md 4; plan 2026-10-27-stick-4-one-disk.md, Task 4): its
|
||||
@@ -16,9 +16,14 @@
|
||||
* identity drive always has been. No other drive is used on v4; drives of
|
||||
* users minted by this system's Zuse come with the users design after INSTALL.
|
||||
*
|
||||
* Genesis (plan 2026-10-29-stick-5, Task 1; STICK.md 6): a stick whose
|
||||
* Artemis fence has no marker and whose identity partition is blank mints its
|
||||
* own Zuse at its first boot -- the stick's proxy Zuse, full Zuse while no real
|
||||
* Zuse exists -- reads her back, then writes the version 2 marker
|
||||
* (sk_v4_marker.c) naming her.
|
||||
*
|
||||
* Not here (the plan's "not in this gate"): WIREBIND identities, EJECT,
|
||||
* ACL-ZUSE-BOOT, and genesis -- which writes Artemis's disk, and the v4 boot
|
||||
* does not write it yet (the stick's increment 5).
|
||||
* ACL-ZUSE-BOOT.
|
||||
*/
|
||||
#include "starkernel/v4/sk_v4_identity.h"
|
||||
#include "starkernel/console.h"
|
||||
@@ -33,6 +38,7 @@
|
||||
#include "starkernel/capsule_zuse_boot.h"
|
||||
#include "starkernel/kbd_input.h"
|
||||
#include "starkernel/gpt.h"
|
||||
#include "starkernel/v4/sk_v4_marker.h"
|
||||
#ifdef ARCH_AMD64
|
||||
#include "starkernel/ioapic.h"
|
||||
#include "starkernel/i8042.h"
|
||||
@@ -51,6 +57,12 @@ static uint8_t g_zuse_seed[32], g_zuse_pubkey[32];
|
||||
static uint8_t g_zuse_root_pubkey[32];
|
||||
static int g_zuse_root_known;
|
||||
static struct blkio_dev *g_zuse_dev;
|
||||
/* The genesis marker on the stick's Artemis fence (version 2: the proxy and
|
||||
* the real Zuse), read when the stick's Artemis partition attaches. */
|
||||
static sk_v4_marker_t g_marker;
|
||||
/* The proxy is recognised but a real Zuse exists: no session for the proxy
|
||||
* (STICK.md 6a; the fixed screen comes with the plan's Task 5). */
|
||||
static int g_proxy_fallback;
|
||||
|
||||
/* A drive in a USB slot: the raw disk; when it is this system's stick, its
|
||||
* StarshipOS identity and Artemis partitions as devices of their own; and
|
||||
@@ -76,7 +88,6 @@ static struct {
|
||||
static gpt_part_t g_gpt_parts[SK_V4_GPT_PARTS];
|
||||
|
||||
static uint64_t g_last_beat;
|
||||
static int g_said_no_genesis;
|
||||
static const BootDisk *g_boot_disk; /* the loader's: the disk it booted from */
|
||||
static int g_stick_in; /* a stick's Artemis partition is attached */
|
||||
|
||||
@@ -138,6 +149,68 @@ static int sk_v4_is_this_stick(unsigned nparts)
|
||||
return !g_stick_in;
|
||||
}
|
||||
|
||||
/* Zuse's session begins on @p dev: the console is hers, and the screen with
|
||||
* it (docs/v4.0.0/STICK.md 2). @p line says how she was found. */
|
||||
static void sk_v4_login(blkio_dev_t *dev, const uint8_t seed[32], const uint8_t pubkey[32],
|
||||
const char *line)
|
||||
{
|
||||
console_set_vm_name("Hera");
|
||||
console_set_user_prefix_provider(sk_v4_user_prefix);
|
||||
console_fb_mirror(1);
|
||||
console_fb_enable_ttf();
|
||||
console_println(line);
|
||||
if (!g_zuse_cert_installed) {
|
||||
memcpy(g_zuse_seed, seed, 32);
|
||||
memcpy(g_zuse_pubkey, pubkey, 32);
|
||||
g_zuse_cert_installed = 1;
|
||||
}
|
||||
memcpy(g_zuse_root_pubkey, pubkey, 32); /* as v3's install_and_activate() */
|
||||
g_zuse_root_known = 1;
|
||||
g_zuse_dev = dev;
|
||||
g_zuse_session = 1;
|
||||
}
|
||||
|
||||
/* Genesis on the stick (STICK.md 6): the proxy Zuse minted onto the blank
|
||||
* identity partition @p dev, read back, and only then named in the version 2
|
||||
* marker on @p art's fence. A failure anywhere leaves no marker, and the
|
||||
* system headless. Returns 1 when she is logged in. */
|
||||
static int sk_v4_genesis(blkio_dev_t *dev, blkio_dev_t *art)
|
||||
{
|
||||
uint8_t seed[32], pubkey[32], rseed[32], rpub[32];
|
||||
homeblocks_sig_t sig;
|
||||
homeblocks_sig_result_t sig_rc;
|
||||
uint32_t lbn, nblk;
|
||||
|
||||
/* Artemis takes the marker: its volume is formatted at build (STICK.md 4);
|
||||
* confirmed here only because its signature checked out on attach, and a
|
||||
* no-op on a volume already formatted */
|
||||
if (blk_get_device_range(art, &lbn, &nblk) != BLK_OK || blk_subsys_confirm_format(lbn) != BLK_OK) {
|
||||
console_println("Zuse: genesis mint failed");
|
||||
return 0;
|
||||
}
|
||||
if (capsule_zuse_boot_genesis_mint(dev, seed, pubkey) != 0) {
|
||||
console_println("Zuse: genesis mint failed");
|
||||
return 0;
|
||||
}
|
||||
/* read her back: what the marker will name must be on the stick */
|
||||
sig_rc = homeblocks_sig_check(dev, HOMEBLOCKS_SIG_START_FBLOCK, &sig);
|
||||
if (capsule_zuse_boot_check_key(dev, sig_rc, &sig, pubkey, rseed, rpub) != ZUSE_DRIVE_HERS ||
|
||||
memcmp(rseed, seed, 32) != 0) {
|
||||
console_println("Zuse: genesis mint failed -- not read back");
|
||||
return 0;
|
||||
}
|
||||
memset(&g_marker, 0, sizeof(g_marker));
|
||||
g_marker.present = 1;
|
||||
memcpy(g_marker.proxy, pubkey, 32);
|
||||
if (sk_v4_marker_write(&g_marker) != 0) {
|
||||
memset(&g_marker, 0, sizeof(g_marker));
|
||||
console_println("Zuse: genesis marker write failed -- headless");
|
||||
return 0;
|
||||
}
|
||||
sk_v4_login(dev, seed, pubkey, "Zuse: genesis minted onto attached thumbdrive");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* A drive that has arrived. This system's stick: its Artemis partition is
|
||||
* attached (the first disk slot, the block subsystem's), Zuse's public key is
|
||||
* read from its genesis marker, then its identity partition is attached and,
|
||||
@@ -189,8 +262,11 @@ static int sk_v4_drive_arrived(sk_v4_drive_t *d)
|
||||
d->art_used = &d->art;
|
||||
g_stick_in = 1;
|
||||
console_println("Artemis: the stick's partition attached");
|
||||
/* Zuse's public key, from the genesis marker on Artemis's fence */
|
||||
g_zuse_root_known = capsule_zuse_boot_root_pubkey(g_zuse_root_pubkey) == 0;
|
||||
/* the genesis marker on Artemis's fence: the proxy's key (and the real
|
||||
* Zuse's, once she is minted) */
|
||||
(void)sk_v4_marker_read(&g_marker);
|
||||
g_zuse_root_known = g_marker.present;
|
||||
if (g_marker.present) memcpy(g_zuse_root_pubkey, g_marker.proxy, 32);
|
||||
|
||||
/* then the identity partition, as an identity drive always has been */
|
||||
dev = &d->part;
|
||||
@@ -202,31 +278,18 @@ static int sk_v4_drive_arrived(sk_v4_drive_t *d)
|
||||
d->used = dev;
|
||||
if (g_zuse_session) return 1;
|
||||
|
||||
which = capsule_zuse_boot_check(dev, sig_rc, &sig, seed, pubkey);
|
||||
if (which == ZUSE_DRIVE_GENESIS) {
|
||||
if (!g_said_no_genesis) {
|
||||
console_println("Zuse: no genesis on this disk -- the system stays headless");
|
||||
g_said_no_genesis = 1;
|
||||
}
|
||||
/* no marker: a blank identity partition is the stick's first boot */
|
||||
if (!g_marker.present) {
|
||||
if (sig_rc == HOMEBLOCKS_SIG_BLANK) (void)sk_v4_genesis(dev, &d->art);
|
||||
return 1;
|
||||
}
|
||||
which = capsule_zuse_boot_check_key(dev, sig_rc, &sig, g_marker.proxy, seed, pubkey);
|
||||
if (which != ZUSE_DRIVE_HERS) return 1;
|
||||
|
||||
console_set_vm_name("Hera");
|
||||
console_set_user_prefix_provider(sk_v4_user_prefix);
|
||||
/* the screen is the console from here (docs/v4.0.0/STICK.md 2) */
|
||||
console_fb_mirror(1);
|
||||
console_fb_enable_ttf();
|
||||
console_println("Zuse: identity confirmed from attached thumbdrive");
|
||||
if (!g_zuse_cert_installed) {
|
||||
memcpy(g_zuse_seed, seed, 32);
|
||||
memcpy(g_zuse_pubkey, pubkey, 32);
|
||||
g_zuse_cert_installed = 1;
|
||||
if (g_marker.has_real) {
|
||||
g_proxy_fallback = 1; /* a real Zuse exists: the proxy gets no session */
|
||||
return 1;
|
||||
}
|
||||
memcpy(g_zuse_root_pubkey, pubkey, 32); /* as v3's install_and_activate() */
|
||||
g_zuse_root_known = 1;
|
||||
g_zuse_dev = dev;
|
||||
g_zuse_session = 1;
|
||||
sk_v4_login(dev, seed, pubkey, "Zuse: identity confirmed from attached thumbdrive");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -245,6 +308,8 @@ static void sk_v4_drive_left(sk_v4_drive_t *d)
|
||||
blk_subsys_detach_device(d->art_used);
|
||||
d->art_used = (blkio_dev_t *)0;
|
||||
g_stick_in = 0;
|
||||
g_proxy_fallback = 0;
|
||||
memset(&g_marker, 0, sizeof(g_marker));
|
||||
}
|
||||
if (!dev || dev != g_zuse_dev) return;
|
||||
g_zuse_session = 0;
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/* sk_v4_marker.c -- the genesis marker, version 2, for the v4 boot
|
||||
* (docs/v4.0.0/STICK.md 6, 6a; plan 2026-10-29-stick-5, Task 1).
|
||||
*
|
||||
* Version 1 (v3's, zuse_genesis_marker_t) holds one key; it reads here as
|
||||
* the proxy, with no real Zuse, so the minted pair logs in as it always has.
|
||||
* What is written is always version 2. v3 reads only version 1, and v3 never
|
||||
* runs from a stick (STICK.md 5.5), so v3 never meets a version 2 marker.
|
||||
*/
|
||||
#include "starkernel/v4/sk_v4_marker.h"
|
||||
#include "starkernel/zuse_genesis_marker.h"
|
||||
#include "block_subsystem.h" /* blk_meta_zone_read/write, compute_crc64 */
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
/* One 4 KiB devblock, read as either version */
|
||||
static union {
|
||||
uint8_t bytes[4096];
|
||||
zuse_genesis_marker_t v1;
|
||||
zuse_genesis_marker_v2_t v2;
|
||||
} g_buf;
|
||||
|
||||
int sk_v4_marker_read(sk_v4_marker_t *m)
|
||||
{
|
||||
memset(m, 0, sizeof(*m));
|
||||
if (blk_meta_zone_read(0, g_buf.bytes) != 0) return -1;
|
||||
if (g_buf.v1.magic != ZUSE_GENESIS_MARKER_MAGIC) return -1;
|
||||
|
||||
if (g_buf.v1.version == ZUSE_GENESIS_MARKER_VERSION) {
|
||||
if (compute_crc64(g_buf.bytes, offsetof(zuse_genesis_marker_t, crc)) != g_buf.v1.crc)
|
||||
return -1;
|
||||
memcpy(m->proxy, g_buf.v1.zuse_pubkey, 32);
|
||||
m->present = 1;
|
||||
return 0;
|
||||
}
|
||||
if (g_buf.v2.version == ZUSE_GENESIS_MARKER_VERSION_2) {
|
||||
if (compute_crc64(g_buf.bytes, offsetof(zuse_genesis_marker_v2_t, crc)) != g_buf.v2.crc)
|
||||
return -1;
|
||||
if (g_buf.v2.has_real > 1u) return -1;
|
||||
memcpy(m->proxy, g_buf.v2.proxy_pubkey, 32);
|
||||
m->has_real = (int)g_buf.v2.has_real;
|
||||
if (m->has_real) memcpy(m->real, g_buf.v2.real_pubkey, 32);
|
||||
m->present = 1;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sk_v4_marker_write(const sk_v4_marker_t *m)
|
||||
{
|
||||
memset(g_buf.bytes, 0, sizeof(g_buf.bytes));
|
||||
g_buf.v2.magic = ZUSE_GENESIS_MARKER_MAGIC;
|
||||
g_buf.v2.version = ZUSE_GENESIS_MARKER_VERSION_2;
|
||||
memcpy(g_buf.v2.proxy_pubkey, m->proxy, 32);
|
||||
if (m->has_real) {
|
||||
memcpy(g_buf.v2.real_pubkey, m->real, 32);
|
||||
g_buf.v2.has_real = 1u;
|
||||
}
|
||||
g_buf.v2.crc = compute_crc64(g_buf.bytes, offsetof(zuse_genesis_marker_v2_t, crc));
|
||||
return blk_meta_zone_write(0, g_buf.bytes) == 0 ? 0 : -1;
|
||||
}
|
||||
Reference in New Issue
Block a user