Skip to content

bip-85: add example use for age key derivation - #2174

Open
dmonakhov wants to merge 1 commit into
bitcoin:masterfrom
dmonakhov:bip-85-age-example
Open

bip-85: add example use for age key derivation#2174
dmonakhov wants to merge 1 commit into
bitcoin:masterfrom
dmonakhov:bip-85-age-example

Conversation

@dmonakhov

@dmonakhov dmonakhov commented May 23, 2026

Copy link
Copy Markdown

Motivation

age is a widely-deployed file-encryption format. Both its classic (X25519, since 2021)
and post-quantum (X-Wing / HPKE-MLKEM768-X25519, age v1.3.0+ Dec 2024) identity types take a 32-byte uniform seed as the secret-key material — which is precisely what BIP-85's HEX application at num_bytes=32 already returns.

This PR adds a brief example-use subsection at the end of the HEX application section, documenting how to interpret the existing 32-byte HEX output as an age identity. No new application number, no normative MUSTs added, no changes required in existing implementations — the HEX application already produces exactly what age consumes; this PR just records the connection in the spec.

Documenting this gives users a single backup story: the same BIP-39 mnemonic that already secures their Bitcoin wallets can deterministically produce age identities, with no additional key-rotation infrastructure on top of what they already do.

It also unblocks downstream hardware-wallet firmware integration maintainers of firmware projects accept "implement this BIP-85 use case" much more readily than "implement a convention from a third-party repo." A spec-blessed convention turns the conversation from a bespoke contribution into a standards-conformance issue.

What changes

A new ====<code>age</code> file encryption keys==== subsection at
the end of the ===HEX=== section in bip-0085.mediawiki.

The subsection:

  • Describes the bech32 encoding for both classic and PQ age identities + their corresponding recipients.
  • Adds a worked test vector using the same master xprv as the existing HEX test vector, so a reader can derive both side-by-side from one master.

Scope

This amendment is intentionally minimal:

  • No new application number — reuses the existing HEX
    application (128169').
  • No normative MUSTs added beyond what BIP-85 already says
    about the HEX application.
  • No changes required in existing implementations
    (bipsea, bip85-js, ethankosakovsky/bip85).

Possible follow-ups (not in this PR):

  • A dedicated AGE subsection paralleling the existing RSA-GPG subsection, with full worked examples for each flavour and an optional index-partition recommendation (e.g. [0, 1000) for PQ identities, [1000, 2000) for classic identities, to avoid producing the same 32 bytes under two different HRPs when the same master is used for both flavours).
  • A dedicated application number for age (e.g. 0x616765' = hex-pack of ASCII "age"), with independent paths per flavour.

These are noted only to clarify that this PR deliberately picks the minimal form; they can be raised separately if there is appetite.

Implementations

Per review, the spec text does not link a reference implementation.
A follow-up PR extending bipsea
with age derivation is planned.

Open question

Should the subsection also include the index-range partition guidance ([0, 1000) for PQ identities, [1000, 2000) for classic identities) to avoid producing the same 32 bytes under two different HRPs when both flavours are derived from one master? Including it would be useful guidance; excluding it keeps the amendment maximally minimal. Open to reviewer preference.


cc @ethankosakovsky @akarve — original BIP-85 authors per the
BIP header. Happy to revise based on review feedback.

@kwest3170-wq

This comment was marked as off-topic.

Comment thread bip-0085.mediawiki Outdated

====Example use: age key derivation====

The 32-byte output at <code>m/83696968'/128169'/32'/{index}'</code> is uniformly random and is suitable as the private-key seed for the [https://age-encryption.org/v1 age] file-encryption format. For classic age identities, bech32-encode the 32 bytes with HRP <code>AGE-SECRET-KEY-</code>; the corresponding recipient is the bech32 encoding (HRP <code>age</code>) of <code>X25519(seed, BASEPOINT)</code>. For post-quantum age identities (age v1.3.0+, Dec 2024), the same 32 bytes are a valid X-Wing seed; bech32-encode with HRP <code>AGE-SECRET-KEY-PQ-</code>. X-Wing internally SHAKE256-expands the seed into ML-KEM-768 and X25519 components, and the recipient is the bech32 encoding (HRP <code>age1pq</code>) of the X-Wing encapsulation key. A reference implementation is [https://github.com/dmonakhov/age-keygen-det age-keygen-det].

@akarve akarve May 24, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few requests for this section:

  1. Please insert newlines every ~80-90 chars so this file reads well in a terminal
  2. The Dec 2024 date is probably TMI, version makes sense but dates generally don't age well
  3. You say "uniformly random" but the point is "cryptographically random"
  4. Consider breaking most of the above into a small table for readability and using standard nomenclature like || for concat, etc.

Example: please check the math and semantics (assume what's here is wrong), but to give you the idea:

flavor role HRP bytes encoded in data encoded string
classic identity AGE-SECRET-KEY- seed (32 B) AGE-SECRET-KEY- || 1 || AG7WK…UKUMWQ || WNNT4U
classic recipient age X25519(seed, G) (32 B) age || 1 || m0hhzx…256wslq || mdz8e9
PQ (X-Wing) identity AGE-SECRET-KEY-PQ- seed (32 B, same bytes) AGE-SECRET-KEY-PQ- || 1 || AG7WK…UKUMWQ || 5AN2M5
PQ (X-Wing) recipient age1pq XWing.pk(seed) (≈1216 B) age1pq || 1 || (~1950 chars) || (6 chars)

And then define your terms below, G, etc.

@dmonakhov dmonakhov Jun 2, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please insert newlines every ~80-90 chars so this file reads well in a terminal
The Dec 2024 date is probably TMI, version makes sense but dates generally don't age well
You say "uniformly random" but the point is "cryptographically random"

Ack. fixed with new version.

please check the math and semantics (assume what's here is wrong),

Oh.. thank you very much for pointing this. Indeed original test vectors was not correct, shame on me.
Please see updated version. test vectors are now correct.

Comment thread bip-0085.mediawiki Outdated
@jonatack jonatack added Proposed BIP modification PR by non-owner to update BIP content Pending acceptance This BIP modification requires sign-off by the champion of the BIP being modified labels May 24, 2026
Comment thread bip-0085.mediawiki Outdated
OUTPUT
* DERIVED ENTROPY=492db4698cf3b73a5a24998aa3e9d7fa96275d85724a91e71aa2d645442f878555d078fd1f1f67e368976f04137b1f7a0d19232136ca50c44614af72b5582a5c

====Example use: age key derivation====

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
====Example use: age key derivation====
====<code>age</code> file encryption keys====

Comment thread bip-0085.mediawiki Outdated
Comment thread bip-0085.mediawiki Outdated
@jonatack jonatack added the PR Author action required Needs updates, has unaddressed review comments, or is otherwise waiting for PR author label May 25, 2026
@dmonakhov
dmonakhov force-pushed the bip-85-age-example branch from 6cb352d to 943f1d9 Compare June 2, 2026 07:40
@jonatack jonatack removed the PR Author action required Needs updates, has unaddressed review comments, or is otherwise waiting for PR author label Jun 2, 2026
Comment thread bip-0085.mediawiki Outdated
@akarve

akarve commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Mostly looks good. Left one and line comment. For the PR description please delete the test vectors as they might have diverged and distract from the PR contents.

@murchandamus murchandamus added the PR Author action required Needs updates, has unaddressed review comments, or is otherwise waiting for PR author label Jul 20, 2026
Documents the connection between BIP-85's HEX application output
at num_bytes=32 and the private-key seed format used by the age
file-encryption format (https://age-encryption.org/v1) for both
the classic X25519 identity (since age v1.0) and the
post-quantum X-Wing identity (age v1.3.0+, Dec 2024).

No new application number, no normative MUSTs added, no changes
required in existing implementations. The amendment is purely
documentational: a single subsection appended at the end of the
HEX section.

A test vector is added using the same master xprv as the
existing HEX test vector in the same section, with both classic
and post-quantum outputs. The PQ recipient (a ~1959-character
bech32 string encoding the 1216-byte X-Wing public key) is
included as a SHA-256 hash inline; the full string is in the
reference implementation's test data.

Reference implementation: https://github.com/dmonakhov/age-keygen-det
- single-binary Go tool, BSD-3-Clause
- cross-validates byte-for-byte against stock age-keygen -y in
  CI for both flavours
@dmonakhov

Copy link
Copy Markdown
Author

Mostly looks good. Left one and line comment. For the PR description please delete the test vectors as they might have diverged and distract from the PR contents.

Done. please see PR updated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Pending acceptance This BIP modification requires sign-off by the champion of the BIP being modified PR Author action required Needs updates, has unaddressed review comments, or is otherwise waiting for PR author Proposed BIP modification PR by non-owner to update BIP content

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants