Skip to content

Use Iterator<Item = u8> instead of Expander #1317

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 23 commits into
base: master
Choose a base branch
from

Conversation

carloskiki
Copy link
Contributor

Discussed in #1295.

Changes

  • Expander trait removed in favor of Iterator.
  • ExpandMsgXmd and ExpandMsgXof stop generating bytes after having reached len_in_bytes.
  • ExpandMsgXmd and ExpandMsgXof are themselves the "expanders", instead of having an Expander associated type.

Regression

On small workloads (len_in_bytes < 256), both xmd and xof expanders are ~ 20% slower with Iterator than with Expander. On the largest workloads (len_in_bytes = 4k), xmd is 50% slower and xof is 100% slower with iterator. I think ExpandMsgXof could be made equally as fast if XofReader allowed a method that generates an Iterator over its inner buffer, just like how ExpandMsgXmd is implemented. I also think that adding bound checks (like there should have been) on Expander would cause similar slow downs on small workloads.

Metrics

small (frequent use case):

expand_xmd              time:   [168.61 ns 168.68 ns 168.76 ns]

expand_xmd_iter         time:   [226.10 ns 226.51 ns 227.08 ns]

expand_xof              time:   [489.15 ns 490.44 ns 492.19 ns]

expand_xof_iter         time:   [532.37 ns 532.61 ns 532.92 ns]

large:

expand_xmd              time:   [12.074 µs 12.078 µs 12.083 µs]

expand_xmd_iter         time:   [18.433 µs 18.440 µs 18.449 µs]

expand_xof              time:   [7.0494 µs 7.0514 µs 7.0538 µs]

expand_xof_iter         time:   [15.713 µs 15.718 µs 15.725 µs]

I did not include the benchmarks in the PR because I did not want to add criterion as a dev-dependency. Let me know if you want me to add them.

I let the maintainers decide whether this regression is worth it.

tarcieri and others added 4 commits July 20, 2025 14:02
make hash_to_field output an array

use primitive array instead of `hybrid_array::Array`

fix: all uses of hash_to_field in other crates
Copy link
Contributor

@daxpedda daxpedda left a comment

Choose a reason for hiding this comment

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

I'm not terribly concerned about the slowdown. Overall executing the whole hash2curve operation is quite expensive compared to the Expander part, I would assume.

However I'm uncertain now what we are trying to achieve here. We are getting rid of a trait in favor of worse performance and improving the feedback (returning None when we are done).

In hindsight, what we want to model is the Read API. This would be an accurate representation to whats going on there. Unfortunately the Read trait isn't available on no_std.

I will make a PR to propose an alternative, then we can do a comparison and see what we get.

Comment on lines -54 to -55
let ell = u8::try_from(usize::from(len_in_bytes.get()).div_ceil(b_in_bytes))
.expect("should never pass the previous check");
Copy link
Contributor

Choose a reason for hiding this comment

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

Lets turn this into a debug_assert!.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think the logic here is succinct enough to not need a dbg assert. Since len_in_bytes <= 255 * b_in_bytes, len_in_bytes / b_in_bytes <= 255.

Copy link
Contributor

Choose a reason for hiding this comment

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

Seems fine to me!

@daxpedda
Copy link
Contributor

See #1318.

carloskiki and others added 7 commits July 20, 2025 17:38
Co-authored-by: daxpedda <daxpedda@gmail.com>
Co-authored-by: daxpedda <daxpedda@gmail.com>
Co-authored-by: daxpedda <daxpedda@gmail.com>
Co-authored-by: daxpedda <daxpedda@gmail.com>
@carloskiki
Copy link
Contributor Author

#1318 raises the concern that the ExpandMsg trait now requires a lifetime parameter. I could change that by returning an opaque impl Iterator<Item = u8> + use<'dst>, or use an associated type as before if desired.

@daxpedda
Copy link
Contributor

#1318 raises the concern that the ExpandMsg trait now requires a lifetime parameter. I could change that by returning an opaque impl Iterator<Item = u8> + use<'dst>, or use an associated type as before if desired.

Yes please, removing that lifetime from ExpandMsg made it a whole lot easier to use that trait in more complicated generic setups downstream.

@carloskiki
Copy link
Contributor Author

The trait no longer has an input lifetime, it has an associated type Expanded, analogous to the current Expander.

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.

3 participants