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

Added concatenated balance for nonzero constraint process #294

Merged
merged 8 commits into from
Jul 26, 2024

Conversation

sifnoc
Copy link
Member

@sifnoc sifnoc commented Jun 4, 2024

I added an additional advice column for the concatenated balance, which combines more than two balances into one with shifted positions. For example, consider the following total balances:

  • (A) 0x00000000000000000000000000000000000000000000000000000003FFFFFFF
  • (B) 0x00000000000000000000000000000000000000000000000000000002FFFFFFF
  • (C) 0x00000000000000000000000000000000000000000000000000000001FFFFFFF

The concatenated balance appears as:

  • (D) 0x00000000000003FFFFFFF00000000000002FFFFFFF00000000000001FFFFFFF
    There is an 84-bit shift between each balance.

Additionally, I introduced a constraint for the concatenated balances, formulated as ( D = (A << (84 * 2) ) + (B << 84) + C )

@sifnoc sifnoc requested a review from alxkzmn June 4, 2024 17:19
Comment on lines 41 to 44
for (i, balance) in self.balances.iter().rev().enumerate() {
// Shift bits: 1 for buffer; 19 is highest bit for two power of userbase; 64 is for the maximum range check limit
concatenated_balance += balance << ((1 + 19 + 64) * i);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it's better to have 19 as a constant or a generic and also add an assertion that the concatenated balance would not exceed the field bit size.

Comment on lines 104 to 118
let mut balances_expr = meta.query_advice(balances[N_CURRENCIES - 1], Rotation::cur());

// Base shift value for 84 bits.
let base_shift = Fp::from(1 << 63).mul(&Fp::from(1 << 21));

let mut current_shift = Expression::Constant(base_shift);

for i in (0..N_CURRENCIES - 1).rev() {
let balance = meta.query_advice(balances[i], Rotation::cur());
let shifted_balance = balance * current_shift.clone();
balances_expr = balances_expr + shifted_balance;

if i != 0 {
current_shift = current_shift * Expression::Constant(base_shift);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

This works because we know exactly that N_CURRENCIES=3, but will break if the prover changes the N_CURRENCIES. I think it's better to add an assertion about the parameter combination (i.e., would there be "overlap" between shifted values for the given N_USERS, N_CURRENCIES and max possible range of a balance) and also calculate the base_shift based on these parameters.

Copy link
Member Author

Choose a reason for hiding this comment

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

While adding the assertions you suggested, I noticed that the verification of proof generated with N_CURRENCIES = 2 failed. I still don't have any clue why it doesn't work with two currencies. Therefore, I have simply modified it to allow only 1 or 3 currencies with the assertion.

I believe I can remove contract and fix the backend as I did in PR #297 after merging PR #292.

@sifnoc sifnoc requested a review from alxkzmn July 18, 2024 11:38
));
}

// Define shift bits: 1 for buffer, bits for user base that not exceed 19, and 64 bits for the balances range check
Copy link
Contributor

Choose a reason for hiding this comment

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

Why 19?

Copy link
Member Author

Choose a reason for hiding this comment

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

Firstly, we can allocate 84 bits for each of the three currencies, totaling 252 bits, which does not exceed the modulus in the field.

The maximum user balance is $2^{64} - 1$, which is the maximum number that can be accommodated in the range check chip. After allocating 64 bits for the user balance, we are left with 20 bits.

We use one bit as a buffer to separate the total sum balance in the concatenated balance, leaving us with 19 bits at the end. That's why the user base shouldn't exceed $2^{19}$.

@sifnoc sifnoc merged commit b1fea0a into v3-direct-sumcheck Jul 26, 2024
2 checks passed
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