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

Add keccak transcript #27

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

grandchildrice
Copy link

@grandchildrice grandchildrice commented Sep 21, 2023

issue

#14

what i do

  • Add Keccak Transcript using 2 libraries (tiny-keccak and SHA3)
    • impl minimal functions
    • impl fn get_challenge_nbits()
    • impl KeccakTranscriptVar
  • Test it on Pedersen Circuit
  • Measure the performance
  • Decide which to use

comments

  • I didn't impl fn get_challenge_nbits() and KeccakTranscriptVar because they are currently not called by anywhere. Please let me know if we should include this scope on this PR.
  • After deciding which library to use, delete the rest and then we can merge it.

how to review

$ cargo test

Copy link
Collaborator

@arnaucube arnaucube left a comment

Choose a reason for hiding this comment

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

Thanks for contribuiting ^^

I don't have much time now (currently OOO), but leaving some comments as a first high level pass.

Also, thanks a lot for providing the two versions (tiny_keccak & sha3 libs). I don't have strong opinions on which one to use and haven't checked what other projects are using (having Ethereum's EVM compatibility in mind), but probably @CPerezz & @han0110 have more thoughts on this.
Again, thanks for this PR!

src/pedersen.rs Outdated Show resolved Hide resolved
src/transcript/keccak.rs Outdated Show resolved Hide resolved
src/transcript/keccak.rs Outdated Show resolved Hide resolved
src/transcript/sha3.rs Outdated Show resolved Hide resolved
src/transcript/sha3.rs Outdated Show resolved Hide resolved
@grandchildrice
Copy link
Author

Hi @arnaucube Thanks for your feedbacks! I outdated all of your feedbacks right now.

fn get_challenge(&mut self) -> C::ScalarField {
let mut output = [0u8; 32];
self.sponge.clone().finalize(&mut output);
self.sponge.update(&[output[0]]);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Copy link
Author

Choose a reason for hiding this comment

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

@han0110 Thanks for pointing out!

You mean we don't need to call absorb() (or update()) after squeeze() here, right?

I just checked, and it seems that since finalize() on tiny-keccak/SHA3 does not update the original sponge, thus we no need to call absorb() afterwards as you mentioned.

I have pushed a fix and new tests which can make sure that. ✅ 0685d37

Copy link
Collaborator

Choose a reason for hiding this comment

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

hmm not really, I mean we should re-initialize self.sponge after we've called finalize, otherwise next time we call get_challenge it's equal to hashing all the previous thing again, for evm verifier it seems inefficient.

so it would look like:

         let mut output = [0u8; 32];
-        self.sponge.clone().finalize(&mut output);
+        std::mem::replace(&mut self.sponge, Keccak::v256()).finalize(&mut output);
         self.sponge.update(&[output[0]]);

@arnaucube arnaucube requested a review from CPerezz October 11, 2023 09:16
@arnaucube
Copy link
Collaborator

@CPerezz @han0110 what are your thoughts between going with tiny-keccak or sha3?

Copy link
Member

@CPerezz CPerezz left a comment

Choose a reason for hiding this comment

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

Also @arnaucube. I don't have any preferences. The only thing that I'd make sure we address is checking exactly what to use here. If Sha2_256 or Sha3_256 or Shake256.

Aside from that, some nits that require addressing.

/// KecccakTranscript implements the Transcript trait using the Keccak hash
pub struct KeccakTranscript<C: CurveGroup> {
sponge: Keccak,
phantom: PhantomData<C>,
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
phantom: PhantomData<C>,
_marker: PhantomData<C>,

This is how usually PhantomData is set inside of structs in rust.

let sponge = Keccak::v256();
Self {
sponge,
phantom: PhantomData,
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
phantom: PhantomData,
_marker: PhantomData,

Comment on lines +19 to +20
fn new(config: &Self::TranscriptConfig) -> Self {
let _ = config;
Copy link
Member

Choose a reason for hiding this comment

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

If we're going to drop the config, why getting it as a parameter in first place?

Copy link
Collaborator

@arnaucube arnaucube Oct 12, 2023

Choose a reason for hiding this comment

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

This comes from the Transcript trait, which in cases like Poseidon needs the config. For Keccak is not used, but needed in the function signature to fit with the Transcript trait, so happy with the most rust-style approach.

What I see that is done in other similar arkworks cases is for example:

In our case for this Keccak256, we could do something like is done in the last link of sha256, something like:

Suggested change
fn new(config: &Self::TranscriptConfig) -> Self {
let _ = config;
fn new(_config: &Self::TranscriptConfig) -> Self {

Comment on lines +38 to +39
p.serialize_compressed(&mut serialized).unwrap();
self.sponge.update(&(serialized))
Copy link
Member

Choose a reason for hiding this comment

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

We need to make sure that the point is encoded as [bytes_x, bytes_y].flatten() format. If we're doing any size-optimizations like just storing one coordinate and the sign of the other, simulating the transcript inside of a SNARK (if we needed it at any point) wouldn't work.

Copy link
Collaborator

@arnaucube arnaucube Oct 12, 2023

Choose a reason for hiding this comment

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

Regarding simulating the transcript inside a SNARK, I currently think (=I might be wrong) that we will not need it for the Keccak transcript as mentioned in this comment, since the keccak transcript is intended to be used only in non-circuit cases (eg. in Nova's main transcript), but not in-circuit (eg. HyperNova's SumCheck transcript, where we would use for example Poseidon's Transcript to later reproduce it in-circuit) (more details in the original comment itself).

C::ScalarField::from_le_bytes_mod_order(&[output[0]])
}
fn get_challenge_nbits(&mut self, nbits: usize) -> Vec<bool> {
// TODO
Copy link
Member

Choose a reason for hiding this comment

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

This should be addressed.

/// SHA3Transcript implements the Transcript trait using the Keccak hash
pub struct SHA3Transcript<C: CurveGroup> {
sponge: Shake256,
phantom: PhantomData<C>,
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
phantom: PhantomData<C>,
_marker: PhantomData<C>,

let sponge = Shake256::default();
Self {
sponge,
phantom: PhantomData,
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
phantom: PhantomData,
_marker: PhantomData,

Comment on lines +36 to +40
fn absorb_point(&mut self, p: &C) {
let mut serialized = vec![];
p.serialize_compressed(&mut serialized).unwrap();
self.sponge.update(&(serialized))
}
Copy link
Member

Choose a reason for hiding this comment

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

ditto as with keccak.

Comment on lines +45 to +49
fn get_challenge_nbits(&mut self, nbits: usize) -> Vec<bool> {
// TODO
// should call finalize() then slice the output to n bit challenge
vec![]
}
Copy link
Member

Choose a reason for hiding this comment

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

ditto as with keccak

};
use ark_std::UniformRand;

/// WARNING the method poseidon_test_config is for tests only
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
/// WARNING the method poseidon_test_config is for tests only
/// WARNING the method `sha3_256_test_config` is for tests only

Use sha3 or whatever is decided at the end. But this is definitely not Poseidon.

@CPerezz
Copy link
Member

CPerezz commented Oct 23, 2023

Hey @0xvon how is this going? Can we help you with anything?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants