Skip to content

Remove the GeneralHash trait#4085

Merged
apoelstra merged 8 commits intorust-bitcoin:masterfrom
tcharding:02-20-remove-general-hash
Mar 7, 2025
Merged

Remove the GeneralHash trait#4085
apoelstra merged 8 commits intorust-bitcoin:masterfrom
tcharding:02-20-remove-general-hash

Conversation

@tcharding
Copy link
Copy Markdown
Member

This is the done as part of #4051.

Requires some surgery on the Hmac and Hkdf types as well as a few other patches to maintain the logic that is currently provided by the trait. Final patch is a pure red diff - enjoy.

@github-actions github-actions bot added C-bitcoin PRs modifying the bitcoin crate C-hashes PRs modifying the hashes crate C-io PRs modifying the io crate test labels Feb 20, 2025
@github-actions
Copy link
Copy Markdown

🚨 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 Feb 20, 2025
@tcharding tcharding force-pushed the 02-20-remove-general-hash branch from 022a5c7 to 7038ca3 Compare February 20, 2025 03:04
@tcharding
Copy link
Copy Markdown
Member Author

tcharding commented Feb 20, 2025

In case its not obvious, the regression test in patch one is to prove that the change to hash_again in 82bb884 is correct.

@github-actions
Copy link
Copy Markdown

🚨 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.

@tcharding tcharding force-pushed the 02-20-remove-general-hash branch from 7038ca3 to caac660 Compare February 20, 2025 03:11
@github-actions
Copy link
Copy Markdown

🚨 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.

/// A hashing engine which bytes can be serialized into.
pub trait HashEngine: Clone {
/// The `Hash` type returned when finalizing this engine.
type Hash: Hash;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

If you're going to mess with the traits here it should be GeneralHash (but I think it shouldn't be required anyway).

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.

GeneralHash is folded into Hash and deleted here.

As for why do we need the bound -- I tried removing it and it broke the HmacEngine which wants to be able to finalize its inner engine (obtaining a HashEngine::Hash type) and then call .as_ref to convert it to bytes so that it can iterate over it and do some xor magic.

I think we should leave this be and revisit this in a followup, since it's a nontrivial change.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

IIRC I've originally suggested AsRef<[u8]> bound which should work for the vast majority of use cases (but I wouldn't mind also having Borrow, Copy and equality traits).

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Can we merge as is and follow up? I did try various things yesterday and couldn't get anything nicer to work.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I could be wrong because every experiment requires loads of boring changes but I definitely tried AsRef<[u8]> trait bound.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'm not really sure if we should merge it in this state. The code before was not horribly broken, so clean history has value and the changes I have in mind touch a significant chunk of code, I think.

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.

I think we should merge it. This gets rid of the GeneralHash trait and greatly reduces the amount of stuff we need to think about (we have two interacting traits, Hash and HashEngine, instead of three, and it seems like we're moving toward also getting rid of Hash.)

Even if this means that we have a series of big diffs, conceptually it'll be easier to follow removing the big GeneralHash trait in one go, then reducing or removing Hash in another go.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

OK, I think I'll be able to review properly tomorrow.

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.

Gonna queue this for merge.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Crap, so many things slipping by

@apoelstra
Copy link
Copy Markdown
Member

caac660 looks great! Started local CI but it might be many hours before it finishes, since today there are many 5+-commit PRs for some reason.

To do in followups:

  • Revisit whether we need the Hash bound on HmacEngine::Hash or whether something weaker (AsRef<Self::Bytes>, or, somehow, nothing)
  • Revisit the Bytes type and see if we can't replace it with an associated constant (I remember we couldn't before, but things have changed now)
  • Revisit which functions we should add to hmac and hkdf which are skipped in this PR since they're missing in the existing API

@Kixunil
Copy link
Copy Markdown
Collaborator

Kixunil commented Feb 20, 2025

  • Revisit the Bytes type and see if we can't replace it with an associated constant (I remember we couldn't before, but things have changed now)

I think it should be possible to remove it entirely.

@tcharding
Copy link
Copy Markdown
Member Author

Promoted to #4094

@apoelstra
Copy link
Copy Markdown
Member

I got 18 hours into this and was 1/3 done. I stopped the build to defragment my nix store and my btrfs extents and will restart in a bit.

The timing here is pretty bad ... I am using btrfs over SATA on a spinning disk drive for my Nix store. I have a new PCIe drive with ext4 which should be 10-1000x faster, but I can't cut over to it when I'm remote ... and I left town yesterday for a couple weeks. I shouldn't have kept procrastinating on it..

@tcharding
Copy link
Copy Markdown
Member Author

tcharding commented Feb 21, 2025

We can just queue up drafts on top of this for any hashes PRs till you are back home. I'm not stressing about hashes at the moment because amounts is taking so long.

@apoelstra
Copy link
Copy Markdown
Member

Compliing with features hex serde and nothing else seems to fail on one commit.

@apoelstra
Copy link
Copy Markdown
Member

In ed6fa5a (the very first commit):

Your new regression test doesn't compile (yet). If you cd into hashes/ on this commit and run cargo test --all-features it fails.

@tcharding
Copy link
Copy Markdown
Member Author

CI should not pass then, I'll investigate. Thanks

@apoelstra
Copy link
Copy Markdown
Member

@tcharding it does compile by the last commit, so I'm not too surprised that CI passes since it tests only the tip.

It looks like you added the regression then reordered the commits but didn't tweak it, or something.

@tcharding
Copy link
Copy Markdown
Member Author

tcharding commented Feb 23, 2025

Oh woops, cheers. Will fix.

@tcharding tcharding force-pushed the 02-20-remove-general-hash branch from caac660 to 820a1b7 Compare February 25, 2025 02:20
@github-actions
Copy link
Copy Markdown

🚨 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.

apoelstra
apoelstra previously approved these changes Feb 26, 2025
Copy link
Copy Markdown
Member

@apoelstra apoelstra left a comment

Choose a reason for hiding this comment

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

ACK 820a1b7; successfully ran local tests

Add a simple regression test prior to patching the
`sha256::Hash::hash_again` function.
Add an associated const `Hash` to the `HashEngine` trait. Also add a
`finalize` method that converts the engine to the associated hash.

For now just use the existent `from_engine` stuff. We can refactor
later.
We would like to do away with the `GeneralHash` trait. Currently we
bound `Hmac` and `HmacEngine` on it but this is unnecessary now that we
have added `HashEngine::finalize` and `HashEngine::Hash`.

Bound the `HmacEngine` on `HashEngine` (which has an associated `Hash`
type returned by `finilalize`).

Bound `Hmac` type on `T::Hash` where `T` is `HashEngine`.

Includes some minor shortening of local variable names around hmac
engine usage.

Note this means that `Hmac` no longer implements `GeneralHash`.
Add a standalone `hash` function that is a drop in replacement for
`GeneralHash::hash`. Do not add it to `hmac` - this is in parity with
the current code because `Hmac` does not implement `GeneralHash::hash`.

Use the new function in `bitcoin` removing all occurrences of
`GeneralHash` from `bitcoin`.

In `hashes` replace usage of `GeneralHash::hash` with the new `hash`
function.
 Add a standalone `hash_byte_chunks` function that is a drop in
 replacement for `GeneralHash::hash_byte_chunks`. Do not add it to
 `hmac` - this is in parity with the current code because `Hmac` does
 not implement `GeneralHash::hash_byte_chunks`.
We would like to remove the `GeneralHash` trait but we want to keep the
`hash_reader` functionality.

Add a stand alone function (when `hashes` is enabled) `hash_reader`.
Remove the extension trait.
This import is not needed. Interesting that the linter does not catch
it.
Now that we are able to unambiguously go from a hash engine to its
associated hash type there is no longer any need for the `GeneralHash`
trait.

Please note that IMO this concept of a general hash type as opposed to
one where one can hash arbitrary data still exists in the codebase - it
is implicitly in the `hash_newtype` macro.

Remove the `GeneralHash` trait.
@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 6, 2025

🚨 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.

@tcharding
Copy link
Copy Markdown
Member Author

Rebased. Also did a couple more changes making local variable more terse like I did already in other places before hand - I think.

@tcharding
Copy link
Copy Markdown
Member Author

Note to self: Soon as this lands rebase #4017.

Copy link
Copy Markdown
Collaborator

@Kixunil Kixunil left a comment

Choose a reason for hiding this comment

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

ACK 95ad91c

I'd strongly prefer to drop the commit adding the functions we want to deprecate but I'm not going to block the PR over it.

}
engine.finalize()
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I'd like to see this commit dropped if you can be bothered.

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.

I guess you mean 2b6ef31.

Let's promote this to an issue (or just a comment on #4205). I'm 8 hours into a 9-hour local CI run on this.

I agree it'd be better if this function hadn't existed to begin with, but we've gotta deprecate some copies anyway in #4205 so it won't be too bad to also delete this one.

Copy link
Copy Markdown
Collaborator

@Kixunil Kixunil Mar 7, 2025

Choose a reason for hiding this comment

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

OK, if the CI succeeds and no other problem will be found let's keep it. But it the PR will need to be modified please drop it.

LOL, didn't notice this was already 1h ago :D

mod benches {
use test::Bencher;

use crate::{hash160, GeneralHash as _, Hash as _, HashEngine};
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I believe that the reason linter doesn't catch it is that we're calling a function defined on it that's also inherent function and the linter doesn't know they behave the same.


fn from_engine(e: Self::Engine) -> Hash<$($gen),*> { Self::from_engine(e) }
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Th commit message: "concept of a general hash type as opposed to one where one can hash arbitrary data still exists in the codebase"

is funny, arbitrary data = general hash type, I think you meant "as opposed to hash that only hashes specific kinds of data". And yes, general hash type exists as a concept but its' expressed with HashEngine instead.

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.

In 95ad91c:

Agreed, the commit message should be improved. It's the last commit in the PR so it'd be cheap for me to re-run if @tcharding wants to change it. But IMO it's not a big enough deal to hold up the PR over.

@apoelstra apoelstra mentioned this pull request Mar 7, 2025
Copy link
Copy Markdown
Member

@apoelstra apoelstra left a comment

Choose a reason for hiding this comment

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

ACK 95ad91c; successfully ran local tests

@apoelstra apoelstra merged commit 5581c49 into rust-bitcoin:master Mar 7, 2025
24 checks passed
@tcharding tcharding deleted the 02-20-remove-general-hash branch March 9, 2025 21:59
Bashmunta added a commit to Bashmunta/rust-bitcoin that referenced this pull request Nov 29, 2025
The GeneralHash trait was removed (see CHANGELOG rust-bitcoin#4085), but internal_macros.rs
still referenced it in macro docs. Updated hash_trait_impls! and general_hash_type! documentation to reflect actual current requirements
apoelstra added a commit that referenced this pull request Dec 1, 2025
31a07f1 docs(hashes): replace deprecated GeneralHash references (Bashmunta)

Pull request description:

  The GeneralHash trait was removed (hashes/CHANGELOG.md #4085), but internal_macros.rs still referenced it in docs. Updated hash_trait_impls! and general_hash_type! documentation to reflect actual current requirements


ACKs for top commit:
  apoelstra:
    ACK 31a07f1; successfully ran local tests
  tcharding:
    ACK 31a07f1


Tree-SHA512: 8d407a05767f0209f447d0f3923aeb4f5528c144c6a234b35721412d9e50ba8b24a950ff09fadaf6603ce63c75ed14c1b85480caf516db08b879c4e6378c8cbf
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 C-hashes PRs modifying the hashes crate C-io PRs modifying the io crate test

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants