Skip to content
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

feat: poseidon port #180

Merged
merged 29 commits into from
Sep 23, 2024
Merged

feat: poseidon port #180

merged 29 commits into from
Sep 23, 2024

Conversation

iammadab
Copy link
Contributor

@iammadab iammadab commented Sep 2, 2024

Latest Benchmarks

Old Poseidon

  • 2 to 1 hash: 4.4820 µs
  • 60 to 1 hash: 23.615 µs

Poseidon Port (before changing x.square() to x * x)

  • 2 to 1 hash: 1.5236 µs
  • 60 to 1 hash: 12.114 µs

Poseidon Port (current)

  • 2 to 1 hash: 1.3905 µs
  • 60 to 1 hash: 11.177 µs

Plonky2 Poseidon

  • 2 to 1 hash: 1.0108 µs
  • 60 to 1 hash: 8.1342 µs

@kunxian-xia kunxian-xia added mpcs enhancement New feature or request labels Sep 3, 2024
@iammadab iammadab marked this pull request as ready for review September 9, 2024 07:17
@kunxian-xia kunxian-xia requested a review from naure September 10, 2024 08:46
@iammadab
Copy link
Contributor Author

iammadab commented Sep 10, 2024

Underlying field benchmarks

plonky add time: [316.34 ps 319.03 ps 323.61 ps]
ceno add time: [316.63 ps 317.28 ps 317.96 ps]

plonky mul time: [315.96 ps 319.49 ps 326.42 ps]
ceno mul time: [316.42 ps 319.67 ps 325.48 ps]

plonky square time: [315.50 ps 316.08 ps 316.72 ps]
ceno square time: [318.17 ps 320.28 ps 323.67 ps]

Rough field op count estimate (for one permutation)

  • N_ADD: 251
  • N_MUL: 357
  • N_SQUARE: 236

@iammadab
Copy link
Contributor Author

Changing x.square() to x * x improves our time from

2 to 1 hash: 1.5236 µs
60 to 1 hash: 12.114 µs

to:

2 to 1 hash: 1.3905 µs
60 to 1 hash: 11.177 µs

@naure naure requested a review from bgillesp September 10, 2024 17:42
@bgillesp
Copy link
Collaborator

Hi there, I'm giving this PR a look today and tomorrow. A couple questions:

  • Is this code based on a previous implementation of Poseidon, and if so where?
  • Are the constants newly generated or imported?

@iammadab
Copy link
Contributor Author

Hi there, I'm giving this PR a look today and tomorrow. A couple questions:

  • Is this code based on a previous implementation of Poseidon, and if so where?
  • Are the constants newly generated or imported?

Hi @bgillesp, the port comes from plonky2 https://github.com/0xPolygonZero/plonky2/blob/main/plonky2/src/hash/poseidon.rs

Copy link
Collaborator

@bgillesp bgillesp left a comment

Choose a reason for hiding this comment

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

Looks solid to me! I made sure to compare with the Plonky2 source material fairly carefully, and none of the suggested changes are correctness issues.

poseidon/src/poseidon.rs Outdated Show resolved Hide resolved
poseidon/Cargo.toml Outdated Show resolved Hide resolved
poseidon/src/poseidon_goldilocks.rs Show resolved Hide resolved
poseidon/src/poseidon_goldilocks.rs Show resolved Hide resolved
poseidon/benches/hashing.rs Outdated Show resolved Hide resolved
poseidon/src/poseidon_hash.rs Outdated Show resolved Hide resolved
poseidon/src/poseidon.rs Outdated Show resolved Hide resolved
poseidon/src/poseidon.rs Outdated Show resolved Hide resolved
pub trait AdaptedField: SmallField {
const ORDER: u64;

fn from_noncanonical_u96(n_lo: u64, n_hi: u32) -> Self;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Consider changing this function signature to use a tuple input instead of two separate input parameters -- this is the convention used in similar functions in Plonky2 (including reduce_u160 and add_u160_u128 imported just above this), and will make the interfaces more consistent. Something like

fn from_noncanonical_u96((n_lo, n_hi): (u64, u32)) -> Self;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This didn't work, cannot use patterns under trait definition, getting the following error: error[E0642]: patterns aren't allowed in functions without bodies

Copy link
Collaborator

Choose a reason for hiding this comment

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

Totally right, I guess the syntax here should just be

fn from_noncanonical_u96(n: (u64, u32)) -> Self;

Looks like there are only three references to this declaration so far in poseidon.rs and poseidon_goldilocks.rs that would need to be updated if you're okay with change in the function signature.

poseidon/src/poseidon.rs Show resolved Hide resolved
@iammadab iammadab requested a review from bgillesp September 18, 2024 06:55
@iammadab
Copy link
Contributor Author

@bgillesp resolved all comments except for tuple input in the function signature, please have a look again.

Copy link
Collaborator

@bgillesp bgillesp left a comment

Choose a reason for hiding this comment

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

Revisions look good to me! Take a look at the alternate syntax I mentioned for the from_noncanonical_u96 signature in AdaptedField, but aside from that the PR seems ready to go.

I might also take a quick look now to see if I can hunt down anything that might explain the performance difference between the Plonky2 Poseidon benchmarks and this port.

@bgillesp
Copy link
Collaborator

Initial look at the benchmarks is a bit mystifying: broke down the parts of the permutation bench into full rounds and partial rounds, and both of these are slower in the Ceno port. Further benchmarked the parts of a full round -- the round constant update, the monomial S-box, and the MDS matrix transform -- and strangely, at this level the performance difference vanished.

Probably would be worth applying some more in-depth analysis tools to the respective Poseidon::full_rounds functions to see what is going on. If I have time soon I might give it a look, but I don't have a ton of background in this level of optimization if there's anyone else who already knows the right tools.

Copy link
Collaborator

@bgillesp bgillesp left a comment

Choose a reason for hiding this comment

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

Changing review status to Approve now, though it would be nice to know what is causing the performance regression -- perhaps we can make an issue if it turns out to be difficult to resolve.

@kunxian-xia
Copy link
Collaborator

@iammadab Can you resolve the merge conflict so that we can merge it ?

@dreamATD dreamATD merged commit c011e49 into master Sep 23, 2024
6 checks passed
@dreamATD dreamATD deleted the feat/poseidon branch September 23, 2024 08:19
hero78119 pushed a commit that referenced this pull request Sep 30, 2024
Latest Benchmarks

Old Poseidon
- 2 to 1 hash: 4.4820 µs 
- 60 to 1 hash: 23.615 µs

Poseidon Port (before changing x.square() to x * x)
- 2 to 1 hash:  1.5236 µs
- 60 to 1 hash: 12.114 µs

Poseidon Port (current)
- 2 to 1 hash: 1.3905 µs
- 60 to 1 hash: 11.177 µs

Plonky2 Poseidon
- 2 to 1 hash: 1.0108 µs 
- 60 to 1 hash: 8.1342 µs
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request mpcs
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

4 participants