Skip to content

key: validate BIP32 seed length in CExtKey::SetSeed#35320

Open
muhahahmad68 wants to merge 1 commit into
bitcoin:masterfrom
muhahahmad68:bip32-setseed-length-validation
Open

key: validate BIP32 seed length in CExtKey::SetSeed#35320
muhahahmad68 wants to merge 1 commit into
bitcoin:masterfrom
muhahahmad68:bip32-setseed-length-validation

Conversation

@muhahahmad68

@muhahahmad68 muhahahmad68 commented May 19, 2026

Copy link
Copy Markdown

BIP32 specifies that the seed must be between 128 and 512 bits (16 to 64 bytes). CExtKey::SetSeed currently accepts any length, which could result in weak master keys being generated.
Add an Assert at the start of SetSeed to enforce the valid seed length range as a programming invariant. The existing BIP32 test vectors already provide sufficient coverage of valid seed lengths.

To test:

cmake --build build -j --target test_bitcoin
./build/bin/test_bitcoin --run_test=bip32_tests

Fixes #35308

@DrahtBot

DrahtBot commented May 19, 2026

Copy link
Copy Markdown
Contributor

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Code Coverage & Benchmarks

For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/35320.

Reviews

See the guideline for information on the review process.

Type Reviewers
ACK sedited

If your review is incorrectly listed, please copy-paste <!--meta-tag:bot-skip--> into the comment that the bot should ignore.

@ViniciusCestarii

Copy link
Copy Markdown
Contributor

Two things:

  1. I believe return is the wrong failure handling. Silently returning leaves the CExtKey in an uninitialized/partial state with no way for the caller to detect the rejection. Since passing an out-of-spec seed is a programming error with no safe recovery, Assert(seed.size() >= 16 && seed.size() <= 64) is more appropriate because it makes the contract explicit and terminates loudly on violation rather than silently producing a broken object.

  2. The tests belongs in src/test/bip32_tests.cpp. That file already exercises CExtKey::SetSeed directly and is the natural home for BIP32 seed validation tests.

@muhahahmad68

Copy link
Copy Markdown
Author

Two things:

  1. I believe return is the wrong failure handling. Silently returning leaves the CExtKey in an uninitialized/partial state with no way for the caller to detect the rejection. Since passing an out-of-spec seed is a programming error with no safe recovery, Assert(seed.size() >= 16 && seed.size() <= 64) is more appropriate because it makes the contract explicit and terminates loudly on violation rather than silently producing a broken object.
  2. The tests belongs in src/test/bip32_tests.cpp. That file already exercises CExtKey::SetSeed directly and is the natural home for BIP32 seed validation tests.

Yeah, very much agree!.

Checked it out - I'll move the tests.

@muhahahmad68 muhahahmad68 force-pushed the bip32-setseed-length-validation branch from 53544a3 to d46735f Compare May 21, 2026 17:58
@quapka

quapka commented May 22, 2026

Copy link
Copy Markdown
  1. nit: I believe that swapping the ordering would improve readability, Assert(16 <= seed.size() && seed.size() <= 64)

  2. The commit message needs to be updated as well to match the proposed functionality, it still mentions the early return.

  3. The tests are lacking, especially since they do not test arguably the most problematic part which are short seeds. The BOOST_CHECK_THROW (or its variants, I am not familiar with Boost) could be used to test too short and too long seeds.

Comment thread src/test/bip32_tests.cpp Outdated
BOOST_CHECK(!pubkey_parent.Derive(pubkey_child, 0));
}

BOOST_AUTO_TEST_CASE(extkey_setseed_bip32_length)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What is the purpose of this test? The fixed test vectors already handle these cases.

@muhahahmad68

Copy link
Copy Markdown
Author

Thanks for the feedback @quapka, @achow101
The added test cases were handled already with the test vectors.
For invalid test cases, Assert calls assertion_fail which aborts, seems BOOST_CHECK_THROW and its variant can't catch it. I don't know if adding a fuzz test seem like a good option

@achow101

Copy link
Copy Markdown
Member

Assertions enforce invariants and are there to reveal programming bugs outside of tests. This does not need any new tests.

@muhahahmad68

muhahahmad68 commented May 28, 2026

Copy link
Copy Markdown
Author

Assertions enforce invariants and are there to reveal programming bugs outside of tests. This does not need any new tests.

Got it

BIP32 specifies that seed must be between 128 and 512 bits
(16 to 64 bytes). CExtKey::SetSeed currently accepts any length,
including empty seeds, which could lead to weak master keys.

Add an Assert at the start of SetSeed to enforce the valid seed
length range.

Fixes bitcoin#35308
@muhahahmad68 muhahahmad68 force-pushed the bip32-setseed-length-validation branch from d46735f to 2cf9d79 Compare May 28, 2026 21:43
@muhahahmad68

Copy link
Copy Markdown
Author

Removed the test case per @achow101 feedback, the existing BIP32 test vectors provide sufficient coverage and Assert is there to enforce the invariant, not to be tested directly. Updated the commit to only include the Assert in key.cpp.

@sedited sedited left a comment

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.

ACK 2cf9d79

I guess since the seed a fixed length anyway, we could instead just pass the length through in the span.

Sign up for free to 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.

BIP32: CExtKey::SetSeed missing validation of seed bit-length

6 participants