Domain-separated signatures + dogfood the deploy signer - #17

Merged
HarryR merged 3 commits into
mainfrom
domain-separated-sigs
Jul 9, 2026
Merged

Domain-separated signatures + dogfood the deploy signer#17
HarryR merged 3 commits into
mainfrom
domain-separated-sigs

Conversation

@HarryR

Copy link
Copy Markdown
Collaborator

What

Bind every ed25519 signature in the chain to its exact role. Signatures are now over a fixed 64-byte preimage sha256(domain_tag) || sha256(message), where the tag names one of the six contexts (2 hops x {payload, args, manifest}): lockboot.v1.stage1.uki / .stage1.args / .stage1.manifest / .stage2.payload / .stage2.args / .stage2.manifest. A signature minted for one context is structurally invalid in every other.

Alongside: stop signing with openssl in the test Makefile and dogfood the real deploy signer, folding in key generation.

Changes

  • crates/ed25519-sign: Domain enum (all six roles) + tag(); sign()/verify() take a Domain and operate on the preimage (callers still pass the raw message). pem_from_seed / pubkey_b64_from_seed promoted to pub. Tests: domain-separation rejection + a golden known-answer vector stage0's verifier pins against.
  • crates/stage1, crates/mkuki: verify/sign sites pass their role.
  • crates/deploy: new keygen (random ed25519 key via /dev/urandom, no getrandom/libc) and low-level sign --domain; create threads the right Domain into each artifact.
  • Makefile: release key + every signature now via lockboot-deploy (no openssl).

Verification

  • make test-chain-x86_64 SIGN=1 / SIGN=1 MANIFEST=1 / SIGN=1 SIGN_ARGS=1 all pass against the domain-aware stage0 harness: both hops verify and all six domains round-trip across the repo boundary.

Pairs with lockboot/stage0#8; the shared golden vector guarantees both repos' framing agree.

🤖 Generated with Claude Code

HarryRand others added 2 commits July 9, 2026 09:05
Every ed25519 signature in the chain was over raw bytes with no role tag, so
a signature minted for one of the six contexts (2 hops x {payload, args,
manifest}) was structurally valid in another wherever those bytes were
accepted. Bind each signature to its exact role by signing a fixed 64-byte
preimage sha256(domain_tag) || sha256(message).
ed25519-sign gains a Domain enum covering all six roles, with tags of the form
lockboot.v1.<stage>.<kind>; sign()/verify() take a Domain and operate on the
preimage (callers still pass the raw message; the fn hashes it). pem_from_seed
and pubkey_b64_from_seed are promoted to pub for keygen. Tests add
domain-separation rejection and a golden known-answer vector that stage0's
independent verifier pins against. The stage1 verifier and mkuki pass their
roles (stage2.payload / .args / .manifest, stage1.uki).
deploy gains keygen (random ed25519 key via /dev/urandom, no getrandom/libc)
and a low-level sign --domain subcommand; create threads the right Domain into
each signed artifact. The test Makefile stops shelling out to openssl and
dogfoods lockboot-deploy for the release key and every signature, so the real
signing and domain-separation code paths are exercised.
make test-chain-x86_64 SIGN=1 / SIGN=1 MANIFEST=1 / SIGN=1 SIGN_ARGS=1 all
pass against the domain-aware stage0 harness: both hops verify and all six
domains round-trip across the repo boundary.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Dockerfile baked a global ENV RUSTFLAGS applying the static-link flags to
every target uniformly, including the host, where +crt-static makes proc-macro
dylibs impossible to build. stage1 already has a self-sufficient
.cargo/config.toml with per-target rustflags (musl static, gnu host rust-lld),
so the env var only masked them. Remove it.
The env was overriding the config rustflags, so with it gone cargo now applies
the per-target rustflags. Paired with the shared workspace config dropping its
duplicate musl rustflags (cargo concatenates rustflags across config files), the
stage1 and stage2 binaries and the measured linux.efi UKI hash identically
before and after, and the full chain still passes SIGN=1 / MANIFEST=1 /
SIGN_ARGS=1.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Release-prep hygiene over the domain-separation + rustflags changes, no logic:
- Dockerfile.build: collapse the 3-line comment narrating the removed ENV
RUSTFLAGS to a one-line statement of the rule.
- Makefile: drop "instead of shelling out to openssl" from the deploy-bin note.
- README: drop the trailing "There is no openssl in the signing path" sentence.
- deploy: random_seed doc drops the removed-dep enumeration (getrandom/libc/rand),
keeping the reason (no C toolchain on the host).
- ed25519-sign: drop the "(no hex dep)" aside on the golden vector.
Kept the openssl-genpkey PEM-format note: it documents a live interop property,
not a removed dependency. deploy + ed25519-sign compile clean (comment-only).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@HarryR
HarryR merged commit 9540d14 into mainJul 9, 2026
4 checks passed
@HarryR
HarryR deleted the domain-separated-sigs branch July 9, 2026 18:19
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@HarryR
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Domain-separated signatures + dogfood the deploy signer - #17

Merged
HarryR merged 3 commits into
mainfrom
domain-separated-sigs
Jul 9, 2026
Merged

Domain-separated signatures + dogfood the deploy signer#17
HarryR merged 3 commits into
mainfrom
domain-separated-sigs

Conversation

@HarryR

Copy link
Copy Markdown
Collaborator

What

Bind every ed25519 signature in the chain to its exact role. Signatures are now over a fixed 64-byte preimage sha256(domain_tag) || sha256(message), where the tag names one of the six contexts (2 hops x {payload, args, manifest}): lockboot.v1.stage1.uki / .stage1.args / .stage1.manifest / .stage2.payload / .stage2.args / .stage2.manifest. A signature minted for one context is structurally invalid in every other.

Alongside: stop signing with openssl in the test Makefile and dogfood the real deploy signer, folding in key generation.

Changes

  • crates/ed25519-sign: Domain enum (all six roles) + tag(); sign()/verify() take a Domain and operate on the preimage (callers still pass the raw message). pem_from_seed / pubkey_b64_from_seed promoted to pub. Tests: domain-separation rejection + a golden known-answer vector stage0's verifier pins against.
  • crates/stage1, crates/mkuki: verify/sign sites pass their role.
  • crates/deploy: new keygen (random ed25519 key via /dev/urandom, no getrandom/libc) and low-level sign --domain; create threads the right Domain into each artifact.
  • Makefile: release key + every signature now via lockboot-deploy (no openssl).

Verification

  • make test-chain-x86_64 SIGN=1 / SIGN=1 MANIFEST=1 / SIGN=1 SIGN_ARGS=1 all pass against the domain-aware stage0 harness: both hops verify and all six domains round-trip across the repo boundary.

Pairs with lockboot/stage0#8; the shared golden vector guarantees both repos' framing agree.

🤖 Generated with Claude Code

HarryRand others added 2 commits July 9, 2026 09:05
Every ed25519 signature in the chain was over raw bytes with no role tag, so
a signature minted for one of the six contexts (2 hops x {payload, args,
manifest}) was structurally valid in another wherever those bytes were
accepted. Bind each signature to its exact role by signing a fixed 64-byte
preimage sha256(domain_tag) || sha256(message).
ed25519-sign gains a Domain enum covering all six roles, with tags of the form
lockboot.v1.<stage>.<kind>; sign()/verify() take a Domain and operate on the
preimage (callers still pass the raw message; the fn hashes it). pem_from_seed
and pubkey_b64_from_seed are promoted to pub for keygen. Tests add
domain-separation rejection and a golden known-answer vector that stage0's
independent verifier pins against. The stage1 verifier and mkuki pass their
roles (stage2.payload / .args / .manifest, stage1.uki).
deploy gains keygen (random ed25519 key via /dev/urandom, no getrandom/libc)
and a low-level sign --domain subcommand; create threads the right Domain into
each signed artifact. The test Makefile stops shelling out to openssl and
dogfoods lockboot-deploy for the release key and every signature, so the real
signing and domain-separation code paths are exercised.
make test-chain-x86_64 SIGN=1 / SIGN=1 MANIFEST=1 / SIGN=1 SIGN_ARGS=1 all
pass against the domain-aware stage0 harness: both hops verify and all six
domains round-trip across the repo boundary.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Dockerfile baked a global ENV RUSTFLAGS applying the static-link flags to
every target uniformly, including the host, where +crt-static makes proc-macro
dylibs impossible to build. stage1 already has a self-sufficient
.cargo/config.toml with per-target rustflags (musl static, gnu host rust-lld),
so the env var only masked them. Remove it.
The env was overriding the config rustflags, so with it gone cargo now applies
the per-target rustflags. Paired with the shared workspace config dropping its
duplicate musl rustflags (cargo concatenates rustflags across config files), the
stage1 and stage2 binaries and the measured linux.efi UKI hash identically
before and after, and the full chain still passes SIGN=1 / MANIFEST=1 /
SIGN_ARGS=1.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Release-prep hygiene over the domain-separation + rustflags changes, no logic:
- Dockerfile.build: collapse the 3-line comment narrating the removed ENV
RUSTFLAGS to a one-line statement of the rule.
- Makefile: drop "instead of shelling out to openssl" from the deploy-bin note.
- README: drop the trailing "There is no openssl in the signing path" sentence.
- deploy: random_seed doc drops the removed-dep enumeration (getrandom/libc/rand),
keeping the reason (no C toolchain on the host).
- ed25519-sign: drop the "(no hex dep)" aside on the golden vector.
Kept the openssl-genpkey PEM-format note: it documents a live interop property,
not a removed dependency. deploy + ed25519-sign compile clean (comment-only).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@HarryR
HarryR merged commit 9540d14 into mainJul 9, 2026
4 checks passed
@HarryR
HarryR deleted the domain-separated-sigs branch July 9, 2026 18:19
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@HarryR
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Domain-separated signatures + dogfood the deploy signer - #17

Merged
HarryR merged 3 commits into
mainfrom
domain-separated-sigs
Jul 9, 2026
Merged

Domain-separated signatures + dogfood the deploy signer#17
HarryR merged 3 commits into
mainfrom
domain-separated-sigs

Conversation

@HarryR

Copy link
Copy Markdown
Collaborator

What

Bind every ed25519 signature in the chain to its exact role. Signatures are now over a fixed 64-byte preimage sha256(domain_tag) || sha256(message), where the tag names one of the six contexts (2 hops x {payload, args, manifest}): lockboot.v1.stage1.uki / .stage1.args / .stage1.manifest / .stage2.payload / .stage2.args / .stage2.manifest. A signature minted for one context is structurally invalid in every other.

Alongside: stop signing with openssl in the test Makefile and dogfood the real deploy signer, folding in key generation.

Changes

  • crates/ed25519-sign: Domain enum (all six roles) + tag(); sign()/verify() take a Domain and operate on the preimage (callers still pass the raw message). pem_from_seed / pubkey_b64_from_seed promoted to pub. Tests: domain-separation rejection + a golden known-answer vector stage0's verifier pins against.
  • crates/stage1, crates/mkuki: verify/sign sites pass their role.
  • crates/deploy: new keygen (random ed25519 key via /dev/urandom, no getrandom/libc) and low-level sign --domain; create threads the right Domain into each artifact.
  • Makefile: release key + every signature now via lockboot-deploy (no openssl).

Verification

  • make test-chain-x86_64 SIGN=1 / SIGN=1 MANIFEST=1 / SIGN=1 SIGN_ARGS=1 all pass against the domain-aware stage0 harness: both hops verify and all six domains round-trip across the repo boundary.

Pairs with lockboot/stage0#8; the shared golden vector guarantees both repos' framing agree.

🤖 Generated with Claude Code

HarryRand others added 2 commits July 9, 2026 09:05
Every ed25519 signature in the chain was over raw bytes with no role tag, so
a signature minted for one of the six contexts (2 hops x {payload, args,
manifest}) was structurally valid in another wherever those bytes were
accepted. Bind each signature to its exact role by signing a fixed 64-byte
preimage sha256(domain_tag) || sha256(message).
ed25519-sign gains a Domain enum covering all six roles, with tags of the form
lockboot.v1.<stage>.<kind>; sign()/verify() take a Domain and operate on the
preimage (callers still pass the raw message; the fn hashes it). pem_from_seed
and pubkey_b64_from_seed are promoted to pub for keygen. Tests add
domain-separation rejection and a golden known-answer vector that stage0's
independent verifier pins against. The stage1 verifier and mkuki pass their
roles (stage2.payload / .args / .manifest, stage1.uki).
deploy gains keygen (random ed25519 key via /dev/urandom, no getrandom/libc)
and a low-level sign --domain subcommand; create threads the right Domain into
each signed artifact. The test Makefile stops shelling out to openssl and
dogfoods lockboot-deploy for the release key and every signature, so the real
signing and domain-separation code paths are exercised.
make test-chain-x86_64 SIGN=1 / SIGN=1 MANIFEST=1 / SIGN=1 SIGN_ARGS=1 all
pass against the domain-aware stage0 harness: both hops verify and all six
domains round-trip across the repo boundary.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Dockerfile baked a global ENV RUSTFLAGS applying the static-link flags to
every target uniformly, including the host, where +crt-static makes proc-macro
dylibs impossible to build. stage1 already has a self-sufficient
.cargo/config.toml with per-target rustflags (musl static, gnu host rust-lld),
so the env var only masked them. Remove it.
The env was overriding the config rustflags, so with it gone cargo now applies
the per-target rustflags. Paired with the shared workspace config dropping its
duplicate musl rustflags (cargo concatenates rustflags across config files), the
stage1 and stage2 binaries and the measured linux.efi UKI hash identically
before and after, and the full chain still passes SIGN=1 / MANIFEST=1 /
SIGN_ARGS=1.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Release-prep hygiene over the domain-separation + rustflags changes, no logic:
- Dockerfile.build: collapse the 3-line comment narrating the removed ENV
RUSTFLAGS to a one-line statement of the rule.
- Makefile: drop "instead of shelling out to openssl" from the deploy-bin note.
- README: drop the trailing "There is no openssl in the signing path" sentence.
- deploy: random_seed doc drops the removed-dep enumeration (getrandom/libc/rand),
keeping the reason (no C toolchain on the host).
- ed25519-sign: drop the "(no hex dep)" aside on the golden vector.
Kept the openssl-genpkey PEM-format note: it documents a live interop property,
not a removed dependency. deploy + ed25519-sign compile clean (comment-only).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@HarryR
HarryR merged commit 9540d14 into mainJul 9, 2026
4 checks passed
@HarryR
HarryR deleted the domain-separated-sigs branch July 9, 2026 18:19
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@HarryR
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Domain-separated signatures + dogfood the deploy signer - #17

Merged
HarryR merged 3 commits into
mainfrom
domain-separated-sigs
Jul 9, 2026
Merged

Domain-separated signatures + dogfood the deploy signer#17
HarryR merged 3 commits into
mainfrom
domain-separated-sigs

Conversation

@HarryR

Copy link
Copy Markdown
Collaborator

What

Bind every ed25519 signature in the chain to its exact role. Signatures are now over a fixed 64-byte preimage sha256(domain_tag) || sha256(message), where the tag names one of the six contexts (2 hops x {payload, args, manifest}): lockboot.v1.stage1.uki / .stage1.args / .stage1.manifest / .stage2.payload / .stage2.args / .stage2.manifest. A signature minted for one context is structurally invalid in every other.

Alongside: stop signing with openssl in the test Makefile and dogfood the real deploy signer, folding in key generation.

Changes

  • crates/ed25519-sign: Domain enum (all six roles) + tag(); sign()/verify() take a Domain and operate on the preimage (callers still pass the raw message). pem_from_seed / pubkey_b64_from_seed promoted to pub. Tests: domain-separation rejection + a golden known-answer vector stage0's verifier pins against.
  • crates/stage1, crates/mkuki: verify/sign sites pass their role.
  • crates/deploy: new keygen (random ed25519 key via /dev/urandom, no getrandom/libc) and low-level sign --domain; create threads the right Domain into each artifact.
  • Makefile: release key + every signature now via lockboot-deploy (no openssl).

Verification

  • make test-chain-x86_64 SIGN=1 / SIGN=1 MANIFEST=1 / SIGN=1 SIGN_ARGS=1 all pass against the domain-aware stage0 harness: both hops verify and all six domains round-trip across the repo boundary.

Pairs with lockboot/stage0#8; the shared golden vector guarantees both repos' framing agree.

🤖 Generated with Claude Code

HarryRand others added 2 commits July 9, 2026 09:05
Every ed25519 signature in the chain was over raw bytes with no role tag, so
a signature minted for one of the six contexts (2 hops x {payload, args,
manifest}) was structurally valid in another wherever those bytes were
accepted. Bind each signature to its exact role by signing a fixed 64-byte
preimage sha256(domain_tag) || sha256(message).
ed25519-sign gains a Domain enum covering all six roles, with tags of the form
lockboot.v1.<stage>.<kind>; sign()/verify() take a Domain and operate on the
preimage (callers still pass the raw message; the fn hashes it). pem_from_seed
and pubkey_b64_from_seed are promoted to pub for keygen. Tests add
domain-separation rejection and a golden known-answer vector that stage0's
independent verifier pins against. The stage1 verifier and mkuki pass their
roles (stage2.payload / .args / .manifest, stage1.uki).
deploy gains keygen (random ed25519 key via /dev/urandom, no getrandom/libc)
and a low-level sign --domain subcommand; create threads the right Domain into
each signed artifact. The test Makefile stops shelling out to openssl and
dogfoods lockboot-deploy for the release key and every signature, so the real
signing and domain-separation code paths are exercised.
make test-chain-x86_64 SIGN=1 / SIGN=1 MANIFEST=1 / SIGN=1 SIGN_ARGS=1 all
pass against the domain-aware stage0 harness: both hops verify and all six
domains round-trip across the repo boundary.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Dockerfile baked a global ENV RUSTFLAGS applying the static-link flags to
every target uniformly, including the host, where +crt-static makes proc-macro
dylibs impossible to build. stage1 already has a self-sufficient
.cargo/config.toml with per-target rustflags (musl static, gnu host rust-lld),
so the env var only masked them. Remove it.
The env was overriding the config rustflags, so with it gone cargo now applies
the per-target rustflags. Paired with the shared workspace config dropping its
duplicate musl rustflags (cargo concatenates rustflags across config files), the
stage1 and stage2 binaries and the measured linux.efi UKI hash identically
before and after, and the full chain still passes SIGN=1 / MANIFEST=1 /
SIGN_ARGS=1.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Release-prep hygiene over the domain-separation + rustflags changes, no logic:
- Dockerfile.build: collapse the 3-line comment narrating the removed ENV
RUSTFLAGS to a one-line statement of the rule.
- Makefile: drop "instead of shelling out to openssl" from the deploy-bin note.
- README: drop the trailing "There is no openssl in the signing path" sentence.
- deploy: random_seed doc drops the removed-dep enumeration (getrandom/libc/rand),
keeping the reason (no C toolchain on the host).
- ed25519-sign: drop the "(no hex dep)" aside on the golden vector.
Kept the openssl-genpkey PEM-format note: it documents a live interop property,
not a removed dependency. deploy + ed25519-sign compile clean (comment-only).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@HarryR
HarryR merged commit 9540d14 into mainJul 9, 2026
4 checks passed
@HarryR
HarryR deleted the domain-separated-sigs branch July 9, 2026 18:19
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@HarryR
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Domain-separated signatures + dogfood the deploy signer - #17

Merged
HarryR merged 3 commits into
mainfrom
domain-separated-sigs
Jul 9, 2026
Merged

Domain-separated signatures + dogfood the deploy signer#17
HarryR merged 3 commits into
mainfrom
domain-separated-sigs

Conversation

@HarryR

Copy link
Copy Markdown
Collaborator

What

Bind every ed25519 signature in the chain to its exact role. Signatures are now over a fixed 64-byte preimage sha256(domain_tag) || sha256(message), where the tag names one of the six contexts (2 hops x {payload, args, manifest}): lockboot.v1.stage1.uki / .stage1.args / .stage1.manifest / .stage2.payload / .stage2.args / .stage2.manifest. A signature minted for one context is structurally invalid in every other.

Alongside: stop signing with openssl in the test Makefile and dogfood the real deploy signer, folding in key generation.

Changes

  • crates/ed25519-sign: Domain enum (all six roles) + tag(); sign()/verify() take a Domain and operate on the preimage (callers still pass the raw message). pem_from_seed / pubkey_b64_from_seed promoted to pub. Tests: domain-separation rejection + a golden known-answer vector stage0's verifier pins against.
  • crates/stage1, crates/mkuki: verify/sign sites pass their role.
  • crates/deploy: new keygen (random ed25519 key via /dev/urandom, no getrandom/libc) and low-level sign --domain; create threads the right Domain into each artifact.
  • Makefile: release key + every signature now via lockboot-deploy (no openssl).

Verification

  • make test-chain-x86_64 SIGN=1 / SIGN=1 MANIFEST=1 / SIGN=1 SIGN_ARGS=1 all pass against the domain-aware stage0 harness: both hops verify and all six domains round-trip across the repo boundary.

Pairs with lockboot/stage0#8; the shared golden vector guarantees both repos' framing agree.

🤖 Generated with Claude Code

HarryRand others added 2 commits July 9, 2026 09:05
Every ed25519 signature in the chain was over raw bytes with no role tag, so
a signature minted for one of the six contexts (2 hops x {payload, args,
manifest}) was structurally valid in another wherever those bytes were
accepted. Bind each signature to its exact role by signing a fixed 64-byte
preimage sha256(domain_tag) || sha256(message).
ed25519-sign gains a Domain enum covering all six roles, with tags of the form
lockboot.v1.<stage>.<kind>; sign()/verify() take a Domain and operate on the
preimage (callers still pass the raw message; the fn hashes it). pem_from_seed
and pubkey_b64_from_seed are promoted to pub for keygen. Tests add
domain-separation rejection and a golden known-answer vector that stage0's
independent verifier pins against. The stage1 verifier and mkuki pass their
roles (stage2.payload / .args / .manifest, stage1.uki).
deploy gains keygen (random ed25519 key via /dev/urandom, no getrandom/libc)
and a low-level sign --domain subcommand; create threads the right Domain into
each signed artifact. The test Makefile stops shelling out to openssl and
dogfoods lockboot-deploy for the release key and every signature, so the real
signing and domain-separation code paths are exercised.
make test-chain-x86_64 SIGN=1 / SIGN=1 MANIFEST=1 / SIGN=1 SIGN_ARGS=1 all
pass against the domain-aware stage0 harness: both hops verify and all six
domains round-trip across the repo boundary.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Dockerfile baked a global ENV RUSTFLAGS applying the static-link flags to
every target uniformly, including the host, where +crt-static makes proc-macro
dylibs impossible to build. stage1 already has a self-sufficient
.cargo/config.toml with per-target rustflags (musl static, gnu host rust-lld),
so the env var only masked them. Remove it.
The env was overriding the config rustflags, so with it gone cargo now applies
the per-target rustflags. Paired with the shared workspace config dropping its
duplicate musl rustflags (cargo concatenates rustflags across config files), the
stage1 and stage2 binaries and the measured linux.efi UKI hash identically
before and after, and the full chain still passes SIGN=1 / MANIFEST=1 /
SIGN_ARGS=1.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Release-prep hygiene over the domain-separation + rustflags changes, no logic:
- Dockerfile.build: collapse the 3-line comment narrating the removed ENV
RUSTFLAGS to a one-line statement of the rule.
- Makefile: drop "instead of shelling out to openssl" from the deploy-bin note.
- README: drop the trailing "There is no openssl in the signing path" sentence.
- deploy: random_seed doc drops the removed-dep enumeration (getrandom/libc/rand),
keeping the reason (no C toolchain on the host).
- ed25519-sign: drop the "(no hex dep)" aside on the golden vector.
Kept the openssl-genpkey PEM-format note: it documents a live interop property,
not a removed dependency. deploy + ed25519-sign compile clean (comment-only).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@HarryR
HarryR merged commit 9540d14 into mainJul 9, 2026
4 checks passed
@HarryR
HarryR deleted the domain-separated-sigs branch July 9, 2026 18:19
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@HarryR
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Domain-separated signatures + dogfood the deploy signer - #17

Merged
HarryR merged 3 commits into
mainfrom
domain-separated-sigs
Jul 9, 2026
Merged

Domain-separated signatures + dogfood the deploy signer#17
HarryR merged 3 commits into
mainfrom
domain-separated-sigs

Conversation

@HarryR

Copy link
Copy Markdown
Collaborator

What

Bind every ed25519 signature in the chain to its exact role. Signatures are now over a fixed 64-byte preimage sha256(domain_tag) || sha256(message), where the tag names one of the six contexts (2 hops x {payload, args, manifest}): lockboot.v1.stage1.uki / .stage1.args / .stage1.manifest / .stage2.payload / .stage2.args / .stage2.manifest. A signature minted for one context is structurally invalid in every other.

Alongside: stop signing with openssl in the test Makefile and dogfood the real deploy signer, folding in key generation.

Changes

  • crates/ed25519-sign: Domain enum (all six roles) + tag(); sign()/verify() take a Domain and operate on the preimage (callers still pass the raw message). pem_from_seed / pubkey_b64_from_seed promoted to pub. Tests: domain-separation rejection + a golden known-answer vector stage0's verifier pins against.
  • crates/stage1, crates/mkuki: verify/sign sites pass their role.
  • crates/deploy: new keygen (random ed25519 key via /dev/urandom, no getrandom/libc) and low-level sign --domain; create threads the right Domain into each artifact.
  • Makefile: release key + every signature now via lockboot-deploy (no openssl).

Verification

  • make test-chain-x86_64 SIGN=1 / SIGN=1 MANIFEST=1 / SIGN=1 SIGN_ARGS=1 all pass against the domain-aware stage0 harness: both hops verify and all six domains round-trip across the repo boundary.

Pairs with lockboot/stage0#8; the shared golden vector guarantees both repos' framing agree.

🤖 Generated with Claude Code

HarryRand others added 2 commits July 9, 2026 09:05
Every ed25519 signature in the chain was over raw bytes with no role tag, so
a signature minted for one of the six contexts (2 hops x {payload, args,
manifest}) was structurally valid in another wherever those bytes were
accepted. Bind each signature to its exact role by signing a fixed 64-byte
preimage sha256(domain_tag) || sha256(message).
ed25519-sign gains a Domain enum covering all six roles, with tags of the form
lockboot.v1.<stage>.<kind>; sign()/verify() take a Domain and operate on the
preimage (callers still pass the raw message; the fn hashes it). pem_from_seed
and pubkey_b64_from_seed are promoted to pub for keygen. Tests add
domain-separation rejection and a golden known-answer vector that stage0's
independent verifier pins against. The stage1 verifier and mkuki pass their
roles (stage2.payload / .args / .manifest, stage1.uki).
deploy gains keygen (random ed25519 key via /dev/urandom, no getrandom/libc)
and a low-level sign --domain subcommand; create threads the right Domain into
each signed artifact. The test Makefile stops shelling out to openssl and
dogfoods lockboot-deploy for the release key and every signature, so the real
signing and domain-separation code paths are exercised.
make test-chain-x86_64 SIGN=1 / SIGN=1 MANIFEST=1 / SIGN=1 SIGN_ARGS=1 all
pass against the domain-aware stage0 harness: both hops verify and all six
domains round-trip across the repo boundary.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Dockerfile baked a global ENV RUSTFLAGS applying the static-link flags to
every target uniformly, including the host, where +crt-static makes proc-macro
dylibs impossible to build. stage1 already has a self-sufficient
.cargo/config.toml with per-target rustflags (musl static, gnu host rust-lld),
so the env var only masked them. Remove it.
The env was overriding the config rustflags, so with it gone cargo now applies
the per-target rustflags. Paired with the shared workspace config dropping its
duplicate musl rustflags (cargo concatenates rustflags across config files), the
stage1 and stage2 binaries and the measured linux.efi UKI hash identically
before and after, and the full chain still passes SIGN=1 / MANIFEST=1 /
SIGN_ARGS=1.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Release-prep hygiene over the domain-separation + rustflags changes, no logic:
- Dockerfile.build: collapse the 3-line comment narrating the removed ENV
RUSTFLAGS to a one-line statement of the rule.
- Makefile: drop "instead of shelling out to openssl" from the deploy-bin note.
- README: drop the trailing "There is no openssl in the signing path" sentence.
- deploy: random_seed doc drops the removed-dep enumeration (getrandom/libc/rand),
keeping the reason (no C toolchain on the host).
- ed25519-sign: drop the "(no hex dep)" aside on the golden vector.
Kept the openssl-genpkey PEM-format note: it documents a live interop property,
not a removed dependency. deploy + ed25519-sign compile clean (comment-only).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@HarryR
HarryR merged commit 9540d14 into mainJul 9, 2026
4 checks passed
@HarryR
HarryR deleted the domain-separated-sigs branch July 9, 2026 18:19
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@HarryR
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Domain-separated signatures + dogfood the deploy signer - #17

Merged
HarryR merged 3 commits into
mainfrom
domain-separated-sigs
Jul 9, 2026
Merged

Domain-separated signatures + dogfood the deploy signer#17
HarryR merged 3 commits into
mainfrom
domain-separated-sigs

Conversation

@HarryR

Copy link
Copy Markdown
Collaborator

What

Bind every ed25519 signature in the chain to its exact role. Signatures are now over a fixed 64-byte preimage sha256(domain_tag) || sha256(message), where the tag names one of the six contexts (2 hops x {payload, args, manifest}): lockboot.v1.stage1.uki / .stage1.args / .stage1.manifest / .stage2.payload / .stage2.args / .stage2.manifest. A signature minted for one context is structurally invalid in every other.

Alongside: stop signing with openssl in the test Makefile and dogfood the real deploy signer, folding in key generation.

Changes

  • crates/ed25519-sign: Domain enum (all six roles) + tag(); sign()/verify() take a Domain and operate on the preimage (callers still pass the raw message). pem_from_seed / pubkey_b64_from_seed promoted to pub. Tests: domain-separation rejection + a golden known-answer vector stage0's verifier pins against.
  • crates/stage1, crates/mkuki: verify/sign sites pass their role.
  • crates/deploy: new keygen (random ed25519 key via /dev/urandom, no getrandom/libc) and low-level sign --domain; create threads the right Domain into each artifact.
  • Makefile: release key + every signature now via lockboot-deploy (no openssl).

Verification

  • make test-chain-x86_64 SIGN=1 / SIGN=1 MANIFEST=1 / SIGN=1 SIGN_ARGS=1 all pass against the domain-aware stage0 harness: both hops verify and all six domains round-trip across the repo boundary.

Pairs with lockboot/stage0#8; the shared golden vector guarantees both repos' framing agree.

🤖 Generated with Claude Code

HarryRand others added 2 commits July 9, 2026 09:05
Every ed25519 signature in the chain was over raw bytes with no role tag, so
a signature minted for one of the six contexts (2 hops x {payload, args,
manifest}) was structurally valid in another wherever those bytes were
accepted. Bind each signature to its exact role by signing a fixed 64-byte
preimage sha256(domain_tag) || sha256(message).
ed25519-sign gains a Domain enum covering all six roles, with tags of the form
lockboot.v1.<stage>.<kind>; sign()/verify() take a Domain and operate on the
preimage (callers still pass the raw message; the fn hashes it). pem_from_seed
and pubkey_b64_from_seed are promoted to pub for keygen. Tests add
domain-separation rejection and a golden known-answer vector that stage0's
independent verifier pins against. The stage1 verifier and mkuki pass their
roles (stage2.payload / .args / .manifest, stage1.uki).
deploy gains keygen (random ed25519 key via /dev/urandom, no getrandom/libc)
and a low-level sign --domain subcommand; create threads the right Domain into
each signed artifact. The test Makefile stops shelling out to openssl and
dogfoods lockboot-deploy for the release key and every signature, so the real
signing and domain-separation code paths are exercised.
make test-chain-x86_64 SIGN=1 / SIGN=1 MANIFEST=1 / SIGN=1 SIGN_ARGS=1 all
pass against the domain-aware stage0 harness: both hops verify and all six
domains round-trip across the repo boundary.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Dockerfile baked a global ENV RUSTFLAGS applying the static-link flags to
every target uniformly, including the host, where +crt-static makes proc-macro
dylibs impossible to build. stage1 already has a self-sufficient
.cargo/config.toml with per-target rustflags (musl static, gnu host rust-lld),
so the env var only masked them. Remove it.
The env was overriding the config rustflags, so with it gone cargo now applies
the per-target rustflags. Paired with the shared workspace config dropping its
duplicate musl rustflags (cargo concatenates rustflags across config files), the
stage1 and stage2 binaries and the measured linux.efi UKI hash identically
before and after, and the full chain still passes SIGN=1 / MANIFEST=1 /
SIGN_ARGS=1.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Release-prep hygiene over the domain-separation + rustflags changes, no logic:
- Dockerfile.build: collapse the 3-line comment narrating the removed ENV
RUSTFLAGS to a one-line statement of the rule.
- Makefile: drop "instead of shelling out to openssl" from the deploy-bin note.
- README: drop the trailing "There is no openssl in the signing path" sentence.
- deploy: random_seed doc drops the removed-dep enumeration (getrandom/libc/rand),
keeping the reason (no C toolchain on the host).
- ed25519-sign: drop the "(no hex dep)" aside on the golden vector.
Kept the openssl-genpkey PEM-format note: it documents a live interop property,
not a removed dependency. deploy + ed25519-sign compile clean (comment-only).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@HarryR
HarryR merged commit 9540d14 into mainJul 9, 2026
4 checks passed
@HarryR
HarryR deleted the domain-separated-sigs branch July 9, 2026 18:19
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@HarryR
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Domain-separated signatures + dogfood the deploy signer - #17

Merged
HarryR merged 3 commits into
mainfrom
domain-separated-sigs
Jul 9, 2026
Merged

Domain-separated signatures + dogfood the deploy signer#17
HarryR merged 3 commits into
mainfrom
domain-separated-sigs

Conversation

@HarryR

Copy link
Copy Markdown
Collaborator

What

Bind every ed25519 signature in the chain to its exact role. Signatures are now over a fixed 64-byte preimage sha256(domain_tag) || sha256(message), where the tag names one of the six contexts (2 hops x {payload, args, manifest}): lockboot.v1.stage1.uki / .stage1.args / .stage1.manifest / .stage2.payload / .stage2.args / .stage2.manifest. A signature minted for one context is structurally invalid in every other.

Alongside: stop signing with openssl in the test Makefile and dogfood the real deploy signer, folding in key generation.

Changes

  • crates/ed25519-sign: Domain enum (all six roles) + tag(); sign()/verify() take a Domain and operate on the preimage (callers still pass the raw message). pem_from_seed / pubkey_b64_from_seed promoted to pub. Tests: domain-separation rejection + a golden known-answer vector stage0's verifier pins against.
  • crates/stage1, crates/mkuki: verify/sign sites pass their role.
  • crates/deploy: new keygen (random ed25519 key via /dev/urandom, no getrandom/libc) and low-level sign --domain; create threads the right Domain into each artifact.
  • Makefile: release key + every signature now via lockboot-deploy (no openssl).

Verification

  • make test-chain-x86_64 SIGN=1 / SIGN=1 MANIFEST=1 / SIGN=1 SIGN_ARGS=1 all pass against the domain-aware stage0 harness: both hops verify and all six domains round-trip across the repo boundary.

Pairs with lockboot/stage0#8; the shared golden vector guarantees both repos' framing agree.

🤖 Generated with Claude Code

HarryRand others added 2 commits July 9, 2026 09:05
Every ed25519 signature in the chain was over raw bytes with no role tag, so
a signature minted for one of the six contexts (2 hops x {payload, args,
manifest}) was structurally valid in another wherever those bytes were
accepted. Bind each signature to its exact role by signing a fixed 64-byte
preimage sha256(domain_tag) || sha256(message).
ed25519-sign gains a Domain enum covering all six roles, with tags of the form
lockboot.v1.<stage>.<kind>; sign()/verify() take a Domain and operate on the
preimage (callers still pass the raw message; the fn hashes it). pem_from_seed
and pubkey_b64_from_seed are promoted to pub for keygen. Tests add
domain-separation rejection and a golden known-answer vector that stage0's
independent verifier pins against. The stage1 verifier and mkuki pass their
roles (stage2.payload / .args / .manifest, stage1.uki).
deploy gains keygen (random ed25519 key via /dev/urandom, no getrandom/libc)
and a low-level sign --domain subcommand; create threads the right Domain into
each signed artifact. The test Makefile stops shelling out to openssl and
dogfoods lockboot-deploy for the release key and every signature, so the real
signing and domain-separation code paths are exercised.
make test-chain-x86_64 SIGN=1 / SIGN=1 MANIFEST=1 / SIGN=1 SIGN_ARGS=1 all
pass against the domain-aware stage0 harness: both hops verify and all six
domains round-trip across the repo boundary.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Dockerfile baked a global ENV RUSTFLAGS applying the static-link flags to
every target uniformly, including the host, where +crt-static makes proc-macro
dylibs impossible to build. stage1 already has a self-sufficient
.cargo/config.toml with per-target rustflags (musl static, gnu host rust-lld),
so the env var only masked them. Remove it.
The env was overriding the config rustflags, so with it gone cargo now applies
the per-target rustflags. Paired with the shared workspace config dropping its
duplicate musl rustflags (cargo concatenates rustflags across config files), the
stage1 and stage2 binaries and the measured linux.efi UKI hash identically
before and after, and the full chain still passes SIGN=1 / MANIFEST=1 /
SIGN_ARGS=1.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Release-prep hygiene over the domain-separation + rustflags changes, no logic:
- Dockerfile.build: collapse the 3-line comment narrating the removed ENV
RUSTFLAGS to a one-line statement of the rule.
- Makefile: drop "instead of shelling out to openssl" from the deploy-bin note.
- README: drop the trailing "There is no openssl in the signing path" sentence.
- deploy: random_seed doc drops the removed-dep enumeration (getrandom/libc/rand),
keeping the reason (no C toolchain on the host).
- ed25519-sign: drop the "(no hex dep)" aside on the golden vector.
Kept the openssl-genpkey PEM-format note: it documents a live interop property,
not a removed dependency. deploy + ed25519-sign compile clean (comment-only).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@HarryR
HarryR merged commit 9540d14 into mainJul 9, 2026
4 checks passed
@HarryR
HarryR deleted the domain-separated-sigs branch July 9, 2026 18:19
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@HarryR