Wip encrypted backup#2
Open
pythcoiner wants to merge 21 commits into
Open
Conversation
ea61634 to
dfadaa3
Compare
Replace magic 0x80000000 literals with named constants for BIP32 hardened/unhardened child derivation.
Extract ParseKeyPathElement() as a shared helper in util/bip32 that parses a single BIP32 key path element (e.g. "0", "0'", "0h"). Both ParseHDKeypath() and the descriptor parser's ParseKeyPathNum() now delegate to it, eliminating duplicated parsing logic.
Add helper methods to AEADChaCha20Poly1305 for converting between
the internal Nonce96 type ({uint32_t, uint64_t}) and a 12-byte
array representation (big-endian).
RFC8439 defines the nonce as 96 opaque bits, but our implementation
splits it. These helpers make it convenient to work with byte-based
nonce representations.
BIP-380 specifies that descriptors can use either ' or h as the hardened indicator. ParseHDKeypath only supported the former. This prepares for using ParseHDKeypath with paths extracted from descriptors which typically use 'h' for shell-escaping convenience. Co-authored-by: Sjors Provoost <sjors@sprovoost.nl>
Introduces WalletDescriptorInfo struct and DescriptorInfoToUniValue() helper to avoid code duplication when serializing descriptor metadata to UniValue. Refactors listdescriptors RPC to use the new helper. Co-authored-by: Sjors Provoost <sjors@sprovoost.nl>
Add functions for normalizing public keys to x-only format as specified in BIP-xxxx (Bitcoin Encrypted Backup). These primitives form the foundation for the encryption scheme. Functions added: - NormalizeToXOnly(): Convert CPubKey or CExtPubKey to 32-byte x-only format - IsNUMSPoint(): Check if a key is the BIP341 unspendable NUMS point - ExtractKeysFromDescriptor(): Extract and normalize all keys from a descriptor Includes test vectors from the BIP specification. Co-authored-by: Sjors Provoost <sjors@sprovoost.nl>
Add functions to compute the decryption secret and individual secrets as specified in BIP-xxxx. The decryption secret is derived from sorted public keys, and individual secrets allow any keyholder to decrypt. Functions added: - ComputeDecryptionSecret(): Hash sorted keys to derive decryption secret - ComputeIndividualSecret(): Hash a single key to derive its individual secret - ComputeAllIndividualSecrets(): Compute XOR'd secrets for all keys Includes test vectors from the BIP specification. Co-authored-by: Sjors Provoost <sjors@sprovoost.nl>
Add functions for encoding/decoding derivation paths as specified in BIP-xxxx: - ParseDerivationPath: parse m/44'/0'/0' style strings - EncodeDerivationPaths: encode to binary format (count + path lengths + BE child indices) - DecodeDerivationPaths: decode from binary format Includes test vectors from the BIP specification. Co-authored-by: Sjors Provoost <sjors@sprovoost.nl>
Add functions for encoding/decoding individual secrets as specified in BIP-xxxx:
- EncodeIndividualSecrets: encode sorted secrets to binary format
- DecodeIndividualSecrets: decode from binary format
Individual secrets allow any keyholder to derive the decryption secret using:
decryption_secret = ci XOR sha256("BIP_XXXX_INDIVIDUAL_SECRET" || pi)
Includes test vectors from the BIP specification.
Co-authored-by: Sjors Provoost <sjors@sprovoost.nl>
Add functions for encoding/decoding content type metadata as specified in BIP-xxxx: - EncodeContent: encode BIP_NUMBER or VENDOR_SPECIFIC content types - DecodeContent: decode content type from binary format Content types define what kind of data is in the encrypted payload: - BIP_NUMBER: references a BIP specification (e.g., 380 for descriptors) - VENDOR_SPECIFIC: application-defined content with length prefix Includes test vectors from the BIP specification. Co-authored-by: Sjors Provoost <sjors@sprovoost.nl>
Add the AEAD primitives used to encrypt and decrypt the backup payload: - EncryptChaCha20Poly1305: encrypt with ChaCha20-Poly1305 AEAD - DecryptChaCha20Poly1305: decrypt and verify the authentication tag These wrap AEADChaCha20Poly1305 from src/crypto/, exposing a uint8_t interface keyed on the BIP-xxxx 32-byte secret and 12-byte nonce.
Add the EncryptedBackup struct and the binary/base64 wire encoding: - EncodeEncryptedBackup: encode to binary format - EncodeEncryptedBackupBase64: encode to base64 string - DecodeEncryptedBackup: decode from binary format - DecodeEncryptedBackupBase64: decode from base64 string The format uses 6-byte magic "BIPXXX", version byte, derivation paths, individual secrets (ci values for key recovery), encryption algorithm identifier, nonce, and CompactSize-prefixed ciphertext.
Add the high-level API tying the primitives together: - CreateEncryptedBackup: create a backup from a descriptor and plaintext - DecryptBackupWithKey: attempt decryption using a single public key - DecryptBackupWithDescriptor: try all keys from a descriptor Decryption reconstructs the per-key share via si = sha256(tag || pi) and recovers the decryption secret as s = ci XOR si for each candidate ci in the backup, then attempts AEAD decryption. Co-authored-by: Sjors Provoost <sjors@sprovoost.nl>
Stateless RPC that takes a descriptor string and returns a base64- encoded BIP-XXXX encrypted backup. The encryption key is derived from the public keys in the descriptor. No wallet is needed.
Stateless RPC that takes a base64-encoded BIP-XXXX encrypted backup and an extended public key (xpub/tpub), then returns the decrypted descriptor string. No wallet is needed.
Decrypt a BIP-XXXX encrypted backup and import the descriptor into the loaded wallet. Requires -rpcwallet. Takes a base64 backup and an extended public key (xpub/tpub).
Stateless command that takes a descriptor string via -descriptor and encrypts it using the BIP-XXXX encrypted backup format. The plaintext is the raw descriptor string bytes. Output is base64 to stdout by default, or raw binary to -backupfile. No wallet file is loaded — the encryption key is derived from the public keys in the descriptor itself. Co-authored-by: Sjors Provoost <sjors@sprovoost.nl>
Stateless command that takes an encrypted backup (base64 on stdin or raw binary via -backupfile) and a -pubkey (xpub/tpub), then outputs the decrypted descriptor string to stdout. No wallet file is loaded. Co-authored-by: Sjors Provoost <sjors@sprovoost.nl>
Decrypt an encrypted backup and import the descriptor into an existing wallet file. Requires -wallet, -pubkey, and backup data (base64 on stdin or raw binary via -backupfile). Also extracts ReadBackupFromArgsOrStdin() helper to avoid duplicating the backup-reading logic across decrypt/import/inspect commands.
Co-authored-by: Sjors Provoost <sjors@sprovoost.nl>
dfadaa3 to
10fa834
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.