Skip to content

Split Hash trait#1555

Closed
Kixunil wants to merge 1 commit intorust-bitcoin:masterfrom
Kixunil:split-hash-traits
Closed

Split Hash trait#1555
Kixunil wants to merge 1 commit intorust-bitcoin:masterfrom
Kixunil:split-hash-traits

Conversation

@Kixunil
Copy link
Copy Markdown
Collaborator

@Kixunil Kixunil commented Jan 14, 2023

The Hash trait requires for the hash type to support hashing arbitrary data. This is not great, since hash newtypes usually hash specific data. Hashing arbitrary data into newtypes is usually a bug or misunderstanding of the API.

This change separates methods performing hashing of arbitrary data to a separate RawHash trait and provides a few helpers to make usage easier:

  • adds a private engine() method to the hash newtype
  • adds finalize() method to HashEngine
  • adds hashes::hash function

Additionally, because of visibility issues, this moves many hash newtypes from the dedicated hash_types module to the modules that produce said hashes.

Closes #1481

This doesn't implement the trick to allow it to compile yet, will do later.

@tcharding
Copy link
Copy Markdown
Member

Concept ACK

@apoelstra
Copy link
Copy Markdown
Member

concept ACK from me too. As a PR this could be split up into multiple commits. I guess in the bitcoin_hashes README we should add a blurb explaining that the "standard" way to use this is to define newtypes for the actual hashes in your project, and implement constructors for those which use raw hashes internally.

But we should also provide top-level functions in that library for directly producing all the raw hashes, because that's often what people want when they just need to one-off hash some data.

@tcharding
Copy link
Copy Markdown
Member

Whats the status of this @Kixunil?

@Kixunil
Copy link
Copy Markdown
Collaborator Author

Kixunil commented Oct 24, 2023

This got burned by the dependency hole but since ranged versions fixes it I'd like to take a look at this soon.

The `Hash` trait requires for the hash type to support hashing arbitrary
data. This is not great, since hash newtypes usually hash specific data.
Hashing arbitrary data into newtypes is usually a bug or
misunderstanding of the API.

This change separates methods performing hashing of arbitrary data to a
separate `RawHash` trait and provides a few helpers to make usage
easier:

* adds a *private* `engine()` method to the hash newtype
* adds `finalize()` method to `HashEngine`
* adds `hashes::hash` function

Additionally, because of visibility issues, this moves many hash
newtypes from the dedicated `hash_types` module to the modules that
produce said hashes.

Closes rust-bitcoin#1481
@Kixunil
Copy link
Copy Markdown
Collaborator Author

Kixunil commented Nov 16, 2023

Pushed broken version because a) I have to run and would be shame to lose so much work, b) the dependency hole is not fixed

@tcharding
Copy link
Copy Markdown
Member

Yeah the dependency hole is fixed, took me a few minutes to remember what we did. We have to bump the version of hashes to 0.14.0 in this patch, then it builds fine. (Its just the ThirtyTwoByteHash trait that was causing problems before, nothing else is used from secp so secp can be on a different version of hashes to the one depended on by bitcoin.)

Comment on lines +56 to +65
hash_newtype! {
/// Filter hash, as defined in BIP-157
pub struct FilterHash(sha256d::Hash);

/// Filter header, as defined in BIP-157
pub struct FilterHeader(sha256d::Hash);
}

crate::hash_types::impl_hashencode!(FilterHash);
crate::hash_types::impl_hashencode!(FilterHeader);
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.

This stuff is done in #2178

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Yes, and it's effectively required for this PR because the fields are private. (Well, I could call from_raw_hash everywhere but that's annoying.) We can merge yours first if you like - it could make the changes easier to understand. I will just have to check if our PRs don't disagree about some moves. As a rule of thumb, the types should be placed wherever they are constructed by hashing the bytes.

}

/// Trait which applies to general-purpose hashes that may hash arbitrary data.
pub trait RawHash: Hash {
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.

Perhaps we should put all_zeros on Hash not on RawHash since it is only used for Bitcoin specific hashes which implement Hash?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Only some hashes actually use all-zero values (besides maybe tests). From what I remember, TxId (in coinbase prev outs) and BlockHash (in genesis block). Only having it on hashes which actually do so is best IMO.

I will try to check how disruptive would it be to remove it from the trait completely.

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.

Even better. We could even add an AllZeros trait.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Unless an algorithm uses all_zeros I don't want any more traits. I actually want RawHash to be duplicated as inherent methods on all our raw hashes since it's very annoying to have to import the trait. (We need RawHash because of merkle trees.)

@Kixunil
Copy link
Copy Markdown
Collaborator Author

Kixunil commented Nov 17, 2023

nothing else is used from secp

It is - there's from_hashed_data which uses the Hash (now RawHash) trait.

so secp can be on a different version of hashes to the one depended on by bitcoin

This may be true regardless because I don't see from_hashed_data being called in bitcoin.

@tcharding
Copy link
Copy Markdown
Member

I'm not disagreeing with you on the technicalities but I got this branch building locally using the version bump.

@tcharding tcharding mentioned this pull request Feb 22, 2024
tcharding added a commit to tcharding/rust-bitcoin that referenced this pull request Feb 22, 2024
This is Kix's work from rust-bitcoin#1555, picking it up to help out. I've just
rebased it.

The `Hash` trait requires for the hash type to support hashing arbitrary
data. This is not great, since hash newtypes usually hash specific data.
Hashing arbitrary data into newtypes is usually a bug or
misunderstanding of the API.

This change separates methods performing hashing of arbitrary data to a separate RawHash trait and provides a few helpers to make usage easier:

- Add a private `engine()` method to the hash newtype
- Add a `finalize()` method to `HashEngine`
- Add a `hashes::hash` function

Moves `TxMerkleNode` hash to the `merkle_tree` module because that is
where implement the custom hashing and need access to its private inner
hash.

Closes rust-bitcoin#1481

Co-developed-by: Martin Habovstiak <martin.habovstiak@gmail.com>
@tcharding
Copy link
Copy Markdown
Member

Closing as stale. Did not look at the changes but the hashes traits had a lot of work over the last year.

@tcharding tcharding closed this Mar 4, 2026
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.

Split Hash trait in two

3 participants