keyfunc: deterministic keys, age encryption and child mnemonics from one mnemonic (spec) #1

Closed
clawbot wants to merge 6 commits from clawbot/hacks:bip85ssh into master
First-time contributor

Spec only, for review. Nothing else is on the branch; implementation starts after the spec is approved.

keyfunc/README.md specifies a command-line tool that derives keys from a BIP-39 mnemonic, so the same mnemonic, kind and index always give the same key and nothing is ever stored. It uses git.eeqj.de/sneak/secret/pkg/bip85 and follows the steps of that repository's agehd package. No vendor id in the path; application numbers are spelled the way BIP-85 spells RSA: SSH 838372, age 657169; child mnemonics use BIP-85's own mnemonic application 39.

Commands: keyfunc ssh pub|priv|install|to for ed25519 keys (install appends the public line on a host if absent, to runs the system ssh with the key served from an in-process agent, never on disk); keyfunc age pub|priv|encrypt|decrypt for age identities and for encrypting to and decrypting with them, the derived identity always among the recipients; keyfunc mnemonic for a child mnemonic of 12, 18 or 24 words.

The mnemonic is never a command-line argument: a shell command given by flag or environment, the mnemonic in the environment, or a no-echo prompt.

Model: fable-5-1

Spec only, for review. Nothing else is on the branch; implementation starts after the spec is approved. `keyfunc/README.md` specifies a command-line tool that derives keys from a BIP-39 mnemonic, so the same mnemonic, kind and index always give the same key and nothing is ever stored. It uses `git.eeqj.de/sneak/secret/pkg/bip85` and follows the steps of that repository's `agehd` package. No vendor id in the path; application numbers are spelled the way BIP-85 spells RSA: SSH `838372`, age `657169`; child mnemonics use BIP-85's own mnemonic application `39`. Commands: `keyfunc ssh pub|priv|install|to` for ed25519 keys (`install` appends the public line on a host if absent, `to` runs the system `ssh` with the key served from an in-process agent, never on disk); `keyfunc age pub|priv|encrypt|decrypt` for age identities and for encrypting to and decrypting with them, the derived identity always among the recipients; `keyfunc mnemonic` for a child mnemonic of 12, 18 or 24 words. The mnemonic is never a command-line argument: a shell command given by flag or environment, the mnemonic in the environment, or a no-echo prompt. Model: fable-5-1
clawbot added 1 commit 2026-09-06 16:19:54 +02:00
README for a new tool that derives ed25519 SSH key pairs from a BIP-39
mnemonic or xprv, using pkg/bip85 from sneak/secret with the same steps
as agehd. Path m/83696968'/592366788'/1822331379'/n'. Four commands:
pub, priv, install, ssh. The README is the spec; the code follows in
later commits.

Model: fable-5-1
Author
First-time contributor

Decisions the task left open; the reading I am taking for each, unless told otherwise:

  1. priv output comment: the OpenSSH private key carries a comment field; I write the same comment as pub (bip85ssh/<n>, or --comment).
  2. ssh command: the in-process agent holds only the derived key, and IdentityAgent replaces the user's own agent for that run, so the user's other keys are not offered. -o IdentityAgent=... is placed before the user's arguments, so a later -o IdentityAgent from the user wins.
  3. install: the remote side is a short sh script run over ssh; the key line is fed to it on standard input rather than placed in the remote command line, so it does not appear in the remote process list.
  4. Mnemonic passphrase: always empty, as in agehd; no flag for it.

Model: fable-5-1

Decisions the task left open; the reading I am taking for each, unless told otherwise: 1. `priv` output comment: the OpenSSH private key carries a comment field; I write the same comment as `pub` (`bip85ssh/<n>`, or `--comment`). 2. `ssh` command: the in-process agent holds only the derived key, and `IdentityAgent` replaces the user's own agent for that run, so the user's other keys are not offered. `-o IdentityAgent=...` is placed before the user's arguments, so a later `-o IdentityAgent` from the user wins. 3. `install`: the remote side is a short `sh` script run over `ssh`; the key line is fed to it on standard input rather than placed in the remote command line, so it does not appear in the remote process list. 4. Mnemonic passphrase: always empty, as in `agehd`; no flag for it. Model: fable-5-1
clawbot added 1 commit 2026-09-06 16:30:45 +02:00
The tool will cover more key types than SSH, so the directory, module
and binary become bip85keys and the commands are grouped by type:
"bip85keys ssh pub|priv|install|ssh" now, "bip85keys age pub|priv"
planned. The README states the age derivation (agehd's path in
sneak/secret) and that adding a type is one package plus one
subcommand. The SSH application id and everything else stay as before.

Model: fable-5-1
clawbot changed title from bip85ssh: deterministic SSH keys from BIP-85 entropy to bip85keys: deterministic key pairs from BIP-85 entropy, SSH first (spec) 2026-09-06 16:31:12 +02:00
Author
First-time contributor

Amended per sneak: mnemonic only, no xprv. The mnemonic now comes from, in order, --mnemonic-command (a shell command whose output is the mnemonic, for example secret get foo), BIP85KEYS_MNEMONIC_COMMAND, BIP85KEYS_MNEMONIC, or a no-echo prompt. One reading: the file flag is gone, since --mnemonic-command 'cat path' covers it; say the word and it comes back. Still spec only, waiting for approval.

Model: fable-5-1

Amended per sneak: mnemonic only, no xprv. The mnemonic now comes from, in order, `--mnemonic-command` (a shell command whose output is the mnemonic, for example `secret get foo`), `BIP85KEYS_MNEMONIC_COMMAND`, `BIP85KEYS_MNEMONIC`, or a no-echo prompt. One reading: the file flag is gone, since `--mnemonic-command 'cat path'` covers it; say the word and it comes back. Still spec only, waiting for approval. Model: fable-5-1
clawbot added 1 commit 2026-09-06 16:35:32 +02:00
Per sneak: no xprv input. The mnemonic comes from a shell command given
as a flag or an environment variable (for example `secret get foo`),
from an environment variable holding it, or from a no-echo prompt. The
file flag is dropped since the command covers it.

Model: fable-5-1
Author
First-time contributor

Amended per sneak: no vendor id in the path, since this is meant as a standard others can adopt. Path is m/83696968'/<app>'/<n>', with application numbers spelled the way BIP-85 spells RSA (828365 = R S A): SSH 838372, age 657169. ssh ssh is now ssh to. Test vectors recomputed for the new path with the secret package. secret derives age keys at a vendor-specific path today; matching this standard is a change there. The tool's name is still open; ten proposals are with sneak.

Model: fable-5-1

Amended per sneak: no vendor id in the path, since this is meant as a standard others can adopt. Path is `m/83696968'/<app>'/<n>'`, with application numbers spelled the way BIP-85 spells RSA (828365 = R S A): SSH `838372`, age `657169`. `ssh ssh` is now `ssh to`. Test vectors recomputed for the new path with the `secret` package. `secret` derives age keys at a vendor-specific path today; matching this standard is a change there. The tool's name is still open; ten proposals are with sneak. Model: fable-5-1
clawbot added 1 commit 2026-09-07 00:06:30 +02:00
Per sneak: the path carries no vendor id, since this is meant as a
standard others can follow. Application numbers follow BIP-85's own
spelling for RSA: SSH is 838372, age is 657169. The ssh subcommand that
runs the system ssh is now "to". Test vectors recomputed for the new
path. secret's age keys move to this path in a change there.

Model: fable-5-1
clawbot changed title from bip85keys: deterministic key pairs from BIP-85 entropy, SSH first (spec) to keyfunc: deterministic key pairs from a mnemonic, SSH first (spec) 2026-09-07 15:29:04 +02:00
clawbot added 1 commit 2026-09-07 15:29:05 +02:00
The name says what the tool is: a key is a function of the mnemonic and
an index, computed when asked for and stored nowhere. Directory, module,
binary and environment variables take it.

Model: fable-5-1
clawbot changed title from keyfunc: deterministic key pairs from a mnemonic, SSH first (spec) to keyfunc: deterministic keys, age encryption and child mnemonics from one mnemonic (spec) 2026-09-07 16:16:31 +02:00
clawbot added 1 commit 2026-09-07 16:16:32 +02:00
Per sneak. The age commands derive the identity at the generic path and
encrypt or decrypt with it, always including the identity's own
recipient. The mnemonic command derives child mnemonics through BIP-85's
own mnemonic application.

Model: fable-5-1
Author
First-time contributor

Closing: sneak approved the specification and moved the tool to its own repository, https://git.eeqj.de/sneak/keyfunc, where the README on main is this spec and the 0.1.0 work runs on next (https://git.eeqj.de/sneak/keyfunc/milestone/28).

Model: fable-5-1

Closing: sneak approved the specification and moved the tool to its own repository, https://git.eeqj.de/sneak/keyfunc, where the README on main is this spec and the 0.1.0 work runs on next (https://git.eeqj.de/sneak/keyfunc/milestone/28). Model: fable-5-1
clawbot closed this pull request 2026-09-07 16:28:32 +02:00

Pull request closed

Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/hacks#1