-
Notifications
You must be signed in to change notification settings - Fork 60
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
base: main
Are you sure you want to change the base?
Add keccak transcript #27
Conversation
There was a problem hiding this 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!
Hi @arnaucube Thanks for your feedbacks! I outdated all of your feedbacks right now. |
src/transcript/keccak.rs
Outdated
fn get_challenge(&mut self) -> C::ScalarField { | ||
let mut output = [0u8; 32]; | ||
self.sponge.clone().finalize(&mut output); | ||
self.sponge.update(&[output[0]]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we re-initialize the sponge here? I saw other impls just drops the inputs after absorbing them.
See:
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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]]);
There was a problem hiding this 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>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
phantom: PhantomData, | |
_marker: PhantomData, |
fn new(config: &Self::TranscriptConfig) -> Self { | ||
let _ = config; |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 Poseidon's CRH
evaluate
method:
https://github.com/arkworks-rs/crypto-primitives/tree/1e4f16cddba8d18f4eb219fa33ac25b2c852f198/src/crh/poseidon/mod.rs#L28 - in Sha256 CRH
evaluate
method:
https://github.com/arkworks-rs/crypto-primitives/tree/1e4f16cddba8d18f4eb219fa33ac25b2c852f198/src/crh/sha256/mod.rs#L34
In our case for this Keccak256, we could do something like is done in the last link of sha256, something like:
fn new(config: &Self::TranscriptConfig) -> Self { | |
let _ = config; | |
fn new(_config: &Self::TranscriptConfig) -> Self { |
p.serialize_compressed(&mut serialized).unwrap(); | ||
self.sponge.update(&(serialized)) |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
phantom: PhantomData<C>, | |
_marker: PhantomData<C>, |
let sponge = Shake256::default(); | ||
Self { | ||
sponge, | ||
phantom: PhantomData, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
phantom: PhantomData, | |
_marker: PhantomData, |
fn absorb_point(&mut self, p: &C) { | ||
let mut serialized = vec![]; | ||
p.serialize_compressed(&mut serialized).unwrap(); | ||
self.sponge.update(&(serialized)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ditto as with keccak.
fn get_challenge_nbits(&mut self, nbits: usize) -> Vec<bool> { | ||
// TODO | ||
// should call finalize() then slice the output to n bit challenge | ||
vec![] | ||
} |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// 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.
Hey @0xvon how is this going? Can we help you with anything? |
f21957b
to
d5c1e5f
Compare
issue
#14
what i do
fn get_challenge_nbits()
KeccakTranscriptVar
comments
fn get_challenge_nbits()
andKeccakTranscriptVar
because they are currently not called by anywhere. Please let me know if we should include this scope on this PR.how to review
$ cargo test