Skip to content

Conversation

@jparr721
Copy link

Howdy gents.

Tobias and I have had some initial luck with getting libFuzzer integrated and want to spend some time looking at this further (i.e. a more comprehensive test harness, etc). We wanted to solicit your feedback as this would be a lot of work, and if there's no hope of it ever merging we might consider some other approaches.

@jparr721 jparr721 requested review from alxiong and mrain as code owners May 13, 2025 19:20
@alxiong
Copy link
Contributor

alxiong commented May 14, 2025

I'm highly supportive on this effort. I'd say add fuzzing in CI as well (maybe as a weekly cron job as it runs for a very long time).

@alxiong alxiong changed the title [Proposal] Integrate Fuzzing into Jellyfish test: Integrate Fuzzing into Jellyfish May 14, 2025
@alxiong
Copy link
Contributor

alxiong commented May 14, 2025

okay, i fixed the rayon iterator issue in CI. but wasm32 target build will fail. I feel like including fuzz as a workspace crate is causing too much trouble, may i suggest we remove it?
instead run fuzz by cd fuzz && cargo fuzz run xxx?
we can document this in README or add a justfile for it?

wdyt?

@mrain
Copy link
Contributor

mrain commented May 14, 2025

okay, i fixed the rayon iterator issue in CI. but wasm32 target build will fail. I feel like including fuzz as a workspace crate is causing too much trouble, may i suggest we remove it? instead run fuzz by cd fuzz && cargo fuzz run xxx? we can document this in README or add a justfile for it?

wdyt?

That's a good idea. We don't mean to export it.

Also don't forget to update the nix env

@jparr721
Copy link
Author

Yeah I think adding as a crate was a "oh my god I will do anything to make this work" type of decision. Let me swap that out and get CI, then @0xkato and I will keep adding tests

@jparr721
Copy link
Author

CI fixed. @0xkato to take over adding tests, I will circle back

if let Ok(input) = ExtensionAttackInput::arbitrary(&mut u) {
let forged_val = F::from(input.forged_val);
let attack_pos = input.attack_pos;
let forged_pos = attack_pos * 3 + 2;
Copy link
Contributor

Choose a reason for hiding this comment

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

instead of using hardcoded value, let's either add explanatory code doc on top of this whole function or name const arity = 3

especially explain the digest_leaf computation on H(0 || pos || val) where 0 is leaf_node_domain_separator... to help readers understand why +2

let squeezed = RescueCRHF::<F>::sponge_no_padding(&data, 1).unwrap();
let val = squeezed[0];

let elems = vec![val; attack_pos as usize + 1];
Copy link
Contributor

Choose a reason for hiding this comment

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

should we:

  1. construct this leaves vector with Vec::with_capacity(next_multiple_of(attack_pos, arity))
  2. only mutate the attack_pos to be the val
  3. add some sanity check on the constructed mt's height, num_leaves etc.

Comment on lines +29 to +33
if let Some(random_lookup) = (0..input.elems.len())
.into_iter()
.collect::<Vec<_>>()
.choose(&mut thread_rng())
.cloned()
Copy link
Contributor

Choose a reason for hiding this comment

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

is this an overly-complicated way of doing rng.gen_range(0..len)?

.cloned()
{
let commitment = mt.commitment();
if let jf_merkle_tree::LookupResult::Ok(elem, proof) = mt.lookup(random_lookup as u64) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Q1: i can't think of a reason why the result here won't be LookupResult::Ok, we didn't prune it or explicitly forget it.
Q2: putting it behind if let indicate that we want to skip the failure cases? should we panic in those case instead. I think we should ? to panic.


#[derive(Arbitrary, Debug)]
struct MerkleTreeArbitraryInput {
// height: usize,
Copy link
Contributor

Choose a reason for hiding this comment

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

why not?

Comment on lines +22 to +26
if let Some(random_lookup) = (0..input_elems_len)
.into_iter()
.collect::<Vec<_>>()
.choose(&mut rand::rng())
.cloned()
Copy link
Contributor

Choose a reason for hiding this comment

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

same here, why not rand::rng().random_rang()?

return;
}

let elems: Vec<Fr254> = input.elems.iter().map(|x| Fr254::from(*x)).collect();
Copy link
Contributor

Choose a reason for hiding this comment

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

importing ark_std::UniformRand, then you can invoke Fr254::rand(&mut rng) which will produce a uniform field element (256bits) rather than converting from a single limb u64.

we can use arbitrary input's as seed to a SeedableRng which is further used to generate a random field element if Arbtrary doesn't work well with Fr::rand() api.

Copy link
Contributor

Choose a reason for hiding this comment

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

so what are we testing here? just universal tree construction? or maybe this is just WIP?

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.

5 participants