-
Notifications
You must be signed in to change notification settings - Fork 68
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
Reduce the number of constraints in DeciderEthCircuit
#88
Reduce the number of constraints in DeciderEthCircuit
#88
Conversation
bdcdcf9
to
001c1c8
Compare
c91232e
to
0dbda97
Compare
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 is awesome! Thank you very much for this 🙌
You did many improvements! Not only the big improvement in the nonnative operations that drastically reduce the number of constraints in the DeciderEthCircuit
, but also the utils::gadgets look much better now, and even the changes in the CycleFold circuit make a lot of sense.
I've read the nonnative/* code, but I must say that I haven't cross-checked the logic with the referenced code and paper.
Left just two small suggestions, but overall LGTM!
P.S.: Also, thank you very much for the clear explanations in the PR message and also in all the comments along the code.
0dbda97
to
179bcd6
Compare
179bcd6
to
8a7c045
Compare
b648ddb
The major cost of
DeciderEthCircuit
is due to the non-native field operations inRelaxedR1CSGadget::check
.Let's first briefly see how field emulation is done.
First, we consider encoding arbitrary precision integers ($v$ into limbs $v_0, ..., v_{n - 1}$ that have a specific width (let's call it ideal width) $W$ , where $v_i \in [0, 2^W)$ for all $i$ .
Big{Int, Uint}
) in-circuit. We first split the valueThen, we can do operations in a limb-wise fashion. For example, multiplication of$u = u_0 + u_1 2^W = \{ u_0, u_1 \}$ and $v = v_0 + v_1 2^W = \{ v_0, v_1 \}$ results in $u_0 v_0 + (u_0 v_1 + u_1 v_0) 2^W + u_1 v_1 2^{2W} = \{ u_0 v_0, u_0 v_1 + u_1 v_0, u_1 v_1 \}$ . Note that the limb widths change after each operation, and they may reach the capacity of the underlying native field sometime. We can also observe that after some operations, the "weight" of the $i$ -th limb is still $2^{iW}$ , i.e., $x = x_0 + x_1 2^W + x_2 2^{2W} + \cdots$ for arbitrary $x$ .
To avoid limb overflow, we need to perform an operation called
align
before the limb widths reach the limit. Basically we can decompose the limbs into bits and recompose them into new limbs with ideal width, but this is super expensive.Now, for enforcing the equality between two non-native variables, it is incorrect to simply compare the limbs, as these variables might be the results of different operations and have different limb widths. An intuitive way to fix this is to align both of them (so that limbs in both of them have width$W$ ) and then check the aligned limbs, but this is sub-optimal. In fact, the equality can be checked in a more efficient way than calling two
align
s, according to xJsnark (although still pretty costly). SeeNonNativeUintVar::enforce_equal_unaligned
for details.In arkworks'$m$ after each operation. This, dubbed $x = q m + r$ , where $q$ is the quotient and $r$ is the remainder), but also $\sum x_i y_i$ .
NonNativeFieldVar
, we are not working on arbitrary integers, but on field elements. This means that we need to modulo the non-native field orderreduce
, not only involves theenforce_equal_unaligned
check (for ensuringrequires a non-native comparison (for ensuring$0 \le r < m$ )(arkworks doesn't check this, but I think this is needed for soundness), resulting in a lot of constraints, especially in our case where we need to computeThis PR reduces the number of constraints in
DeciderEthCircuit
by avoidingenforce_equal_unaligned
andreduce
when possible. This is done by:Although one may achieve the above by leveraging arkworks'
MulResultVar
, a customized structNonNativeUintVar
is introduced to:MulResultVar
s, so that we can computeWith this PR,
DeciderEthCircuit
(with check 7 disabled due to #80) now only costs9_547_318
constraints. Trusted setup and proof generation takes 90-100s on an i9-12900K, and the peak RAM usage is 20-30GB.