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

Parse arbitrary RLPs. #15

Conversation

tideofwords
Copy link

Decompose an arbitrary RLP into a list of items.

Additionally, fix two bugs in decompose_rlp_array_phase0() and decompose_rlp_array_phase1(), and add several tests.

) -> RlpPrefixParsed<F>{
let is_field = self.range.is_less_than(
ctx,
Existing(prefix),
Copy link
Contributor

@jonathanpwang jonathanpwang Jul 20, 2023

Choose a reason for hiding this comment

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

We did a rust trick so specifically for Existing you don't need to type it and it will auto-infer to add Existing(). This is true for all the functions below I believe.

Explanation: the function takes in any type that implements Into<QuantumCell<F>>. We implement Into<QuantumCell<F>> for AssignedValue<F>, and what Into does it auto-wrap it with Existing.

running_max_len += 1 + max_field_len_len + max_field_len;

// this is just print for debug
let mut prefix_idx_val = F::from(0u64);
Copy link
Contributor

Choose a reason for hiding this comment

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

this can be removed now?

self.range.check_less_than_safe(ctx, field_len, (max_field_len + 1) as u64);


let field_cells = witness_subarray(
Copy link
Contributor

Choose a reason for hiding this comment

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

Just a comment: this does not affect the circuit's soundness / completeness, since we always use the adjusted field_len for RLC constraint checks. But I agree it's nice to be consistent here.

}

rlc.load_rlc_cache((ctx_gate, ctx_rlc), self.gate(), bit_length(rlp_array.len() as u64));
rlc.load_rlc_cache((ctx_gate, ctx_rlc), self.gate(), bit_length(cml_max_len 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.

This is an optimization right?

In fact after looking into it, we only use rlc_cache in constrain_rlc_concat so it seems like taking the max of all field_witness.max_field_len would work?

Copy link
Author

Choose a reason for hiding this comment

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

This is not an optimization -- it fixes a bug. If rlp_array.len() is (much) shorter than the maximum length, it won't load enough powers of gamma, and the assertion at rlc.rs:334 will fail.

assert!(pow_bits <= self.gamma_pow_cached().len());

Yes, I think the max of all field_witness.max_field_len would work.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, we actually resize so rlp_array is always the max length. The max_length field is actually redundant.

We'll make this clearer by using a VarLenBytes struct soon.

}

// this is just print for debug
let mut prefix_idx_val = F::from(0u64);
Copy link
Contributor

Choose a reason for hiding this comment

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

please remove


if is_variable_len{
// If `prefix_idx >= rlp_len`, that means we are done
// Question: can we change this to an equality check?
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think so? since you need it to be true for every non-phantom item

Copy link
Author

Choose a reason for hiding this comment

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

Sorry -- I meant an inequality check!
I think if it's phantom, then you'll have equality prefix_idx == rlp_len, so we just have to check if they are equal or not (which is cheaper than a range check)...

// len if short or long
// 1 if literal
// 0 if phantom
item_len = self.gate().select(
Copy link
Contributor

Choose a reason for hiding this comment

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

this can also be changed to a mul

); // *** unconstrained
running_max_len += 1 + max_item_len_len + max_item_len;


Copy link
Contributor

@jonathanpwang jonathanpwang Jul 21, 2023

Choose a reason for hiding this comment

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

random comment: in the final version it would be nice if there was not as much whitespace (e.g., here - just one empty line separating). I understand that during development it was probably helpful for organization.

.chain([
(prefix, one, 1),
(len_trace.rlc_val, len_trace.len, len_trace.max_len),
// or should this be... len_trace.max_len here and below??
Copy link
Contributor

Choose a reason for hiding this comment

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

I agree with what you have below (re: comment)

@@ -394,6 +439,46 @@ mod rlp {
}
}

#[test] // fail
Copy link
Contributor

Choose a reason for hiding this comment

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

tests should always "pass"
if you want to test that the MockProver is failing, you can do MockProver::run(..).verify().is_err() to get a boolean for whether it didn't pass.

Copy link
Contributor

@jonathanpwang jonathanpwang left a comment

Choose a reason for hiding this comment

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

I left some comments, but overall the implementation looks good. Also thanks for adding all the comments - that's very helpful for documentation.

I'm not sure RlpOfRlp is the most appropriate naming, but I think that's because we should likely replace the current decompose_rlp_array with your decompose_rlp_of_rlp - the minor savings of the more specific decompose_rlp_array (array of only strings) is probably not worth the duplicate code.



#[derive(Clone, Debug)]
pub struct RlpItemWitness<F: ScalarField> { // EDITING HERE ********
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 any different from RlpFieldWitness? (I do agree RlpFieldWitness is a better name)

@jonathanpwang
Copy link
Contributor

Replaced by #24

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.

2 participants