Skip to content

Protect Bip32 Numbers#3433

Open
jaoleal wants to merge 1 commit intorust-bitcoin:masterfrom
jaoleal:RevampBip32
Open

Protect Bip32 Numbers#3433
jaoleal wants to merge 1 commit intorust-bitcoin:masterfrom
jaoleal:RevampBip32

Conversation

@jaoleal
Copy link
Copy Markdown
Contributor

@jaoleal jaoleal commented Oct 1, 2024

Hi guys, im splitting all the features from #3036 into some PRs so we can merge it in the lib as i mentioned before closing it.

In this PR, I implemented changes to replace the use of "numbers" with "indexes" for clarity. After reviewing the discussions and the confusion surrounding the terminology, I opted for the term “index,” as it’s consistently used in Bip32. To distinguish the u32 inside the index, I introduced the term "index value," which has worked well in practice.

Another key update addresses how we handle hardened indexes when working with index values. I’ve made two constant methods, shifted_index() and unshifted_index(), to ensure proper manipulation of these values. In Bip32, was common to see the index being directly shifted in some cases and used raw in others, so this change helps standardize that behavior.

Most of the core changes are in bitcoin/src/bip32.rs

	We noticed the possibilities of invariants inside the bip32
module. This commit Wants to cover all possible invariants of the bip32
indexes changing the enums with value to newtypes that only could be
instantiated from its functionalities and constructors, especially while
dealing with hardened indexes. Hardened indexes automatically defines
its index while being casted, becoming infalibble to cast a Hardened
index from a u32 value and the inner value is arbitrarily exposed with
the accordingly value conversion, sucessfully covering cases with and
without hardening notation.

	Naming changed, while dealing with key indexes we replaced the
keyword and concept to "index" instead of number to better represent
its unique function.
@github-actions github-actions bot added C-bitcoin PRs modifying the bitcoin crate test labels Oct 1, 2024
@github-actions
Copy link
Copy Markdown

github-actions bot commented Oct 1, 2024

🚨 API BREAKING CHANGE DETECTED

To see the changes click details on "Check semver breaks / PR Semver - stable toolchain" job then expand "Run semver checker script" and scroll to the end of the section.

@github-actions github-actions bot added the API break This PR requires a version bump for the next release label Oct 1, 2024
@coveralls
Copy link
Copy Markdown

Pull Request Test Coverage Report for Build 11126557509

Details

  • 221 of 255 (86.67%) changed or added relevant lines in 4 files are covered.
  • 3 unchanged lines in 1 file lost coverage.
  • Overall coverage increased (+0.01%) to 82.589%

Changes Missing Coverage Covered Lines Changed/Added Lines %
bitcoin/src/psbt/mod.rs 9 10 90.0%
bitcoin/src/bip32.rs 209 242 86.36%
Files with Coverage Reduction New Missed Lines %
bitcoin/src/bip32.rs 3 84.45%
Totals Coverage Status
Change from base Build 11118652309: 0.01%
Covered Lines: 19112
Relevant Lines: 23141

💛 - Coveralls

@tcharding
Copy link
Copy Markdown
Member

Hey @jaoleal, thanks for tackling this. I don't know how to review this PR for a few reasons:

  1. The current bip32 module is really bad (public API and internal code)
  2. This PR is really big (over 500 lines of green)
  3. I don't know the final state you are trying to get to (this PR is labelled number 1)

Also, I don't know exactly how is the best way to approach revamping this module.

I definitely appreciate you working on this, the module sorely needs some love, but if I'm to have any hope of reviewing perhaps I can give you a few pointers:

  • Do a series of smaller PRs, you can put them all up at once, just have the later ones include the patches from the earlier ones and mark them as draft.
  • Also, be sure to separate out things that are really meaningful and hard to review (like how the top bit of hardened index is handled) from things that are easy to review (like renaming ChildNumber to ChildKeyIndex)

This is not easy work, and anything that involves bit twidling and invariants is non-trivial to review.

@jaoleal jaoleal changed the title Revamp Bip32 API #1 Protect and Rename Bip32 Indexes Oct 2, 2024
@jaoleal
Copy link
Copy Markdown
Contributor Author

jaoleal commented Oct 2, 2024

I understand your concern about the large diff size and appreciate your explanation.

Let me refactor my idea:

The extensive changes primarily stem from necessary renaming across the codebase and comprehensive documentation updates. While the diff appears substantial, the core functional changes are minimal, as evidenced by the small modifications to the examples demonstrating module usage.

I acknowledge that separating these changes into multiple commits might be preferable. However, the interdependencies between the refactoring steps make it REALLY HARD to create isolated, functional commits. The primary goal here is to enhance the module's robustness by transitioning from "enums with fields" to more secure "NewType structs with getters, setters, and constructors for each case."

This refactoring is crucial for improving the safety of key handling in Bip32, addressing potential vulnerabilities that could arise over time. The new design adheres to the principle of making it difficult for consumers to inadvertently misuse the API.

While this PR is part of a larger improvement effort (as discussed in #3036), it stands alone as a significant enhancement to the codebase's security. I've updated the PR title to better reflect its scope.

Looking ahead, I anticipate one more substantial PR implementing the NormalDerivationPath, which will build upon the security improvements introduced here.

@apoelstra
Copy link
Copy Markdown
Member

From BIP32:

Each extended key has 2^31 normal child keys, and 2^31 hardened child keys. Each of these child keys has an index. The normal child keys use indices 0 through 2^(31-1). The hardened child keys use indices 2^31 through 2^(32-1). To ease notation for hardened key indices, a number i_H represents i+2^31.

So my read is that an "index" is a integer between 0 and 2^32. A number, which may be normal or hardened, is an integer between 0 and 2^31, and which index it corresponds to depends on whether it is normal or hardened.

So the existing type name ChildNumber sounds like it's correct. The new terms "hardened index" and "normal index" you are introducing do not appear anywhere in BIP32.

@jaoleal
Copy link
Copy Markdown
Contributor Author

jaoleal commented Oct 3, 2024

I understand your point, but I believe this is a somewhat superficial topic.

I’ll explain my reasoning behind the decision to replace all mentions of "number" and simplify everything to "index."

"Number" ends up being a generic term that appears a lot throughout the codebase, often referring to entities that have no relation to any "number" that could have an index and be used for deriving keys. Based on this, I began removing abstractions that seemed to only complicate understanding. I turned "ChildNumber" to "ChildKeyIndex" based on this thought process:

"I have an extended key and I have the index of its child key, which contains a value that can be either Hardened or Normal."

Two other minor points were:

  • "Number" is rarely mentioned in this BIP, and even then, it’s not always referring to the same entity we’re discussing here. In other instances, it’s used to describe account numbers in BIP 32’s abstraction.

  • The term "index" is used throughout the BIP and, unlike "number," is never used to describe anything else. Even the letter "i" is used as a variable in the pseudocode.

It just felt more natural, but as I said, I think this is a somewhat superficial point.

Naming in Bitcoin is a whole field of study in itself. I see a lot of issues with naming conventions in Bitcoin and all the alternatives always seem far from the concept.

Anyway, that’s the reasoning. I just wanted to clarify so it doesn’t seem like a change without thought behind it, but you’re the maintainer @apoelstra , so it’s your call!

@apoelstra
Copy link
Copy Markdown
Member

apoelstra commented Oct 3, 2024

Anyway, that’s the reasoning. I just wanted to clarify so it doesn’t seem like a change without thought behind it,

For sure. I understand that you thought through the reasoning of this and are trying to simplify the concepts in the API. But I still want to stick with child number", since it's widely used, while "child index" less so, and the BIP seems to use these terms in slightly different ways (which correspond to the existing names).

Weirdly, if I search for "bip32 child number" online I get many instances of the phrase "index number" which I have never heard of.

The term "index" is used throughout the BIP and, unlike "number," is never used to describe anything else. Even the letter "i" is used as a variable in the pseudocode

The term "child number" is the explicit name given to a field of an xkey. The term "child index" does not appear, only "index" by itself. And "index" is nearly as generic a term as "number", and in the context of a software library, is likely to appear more often in non-bip32 contexts.

@jaoleal jaoleal changed the title Protect and Rename Bip32 Indexes Protect and Bip32 Numbers Oct 9, 2024
@jaoleal jaoleal changed the title Protect and Bip32 Numbers Protect Bip32 Numbers Oct 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

API break This PR requires a version bump for the next release C-bitcoin PRs modifying the bitcoin crate test

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants