It was too long, and `group::Curve::batch_normalize` panics if its
inputs are not the same length (which would be the case if a batch
included an output with an invalid `ephemeral_key`).
`rcv` was being used correctly outside the circuit to derive `cv_net`
but then `Circuit` was just storing 0. The `round_trip` test passed
because it uses `rcv = 0` everywhere.
The lookup running sum decomposition uses the same lookup table as
its short variant. These two lookup arguments have been merged.
Co-authored-by: Daira Hopwood <daira@jacaranda.org>
Co-authored-by: Jack Grigg <jack@electriccoin.co>
By rearranging the pieces in the gate, we remove a prev() query and
preserve proximity between pieces involved in the same constraint.
This commit also includes several minor fixes:
- use strict mode for decomposition of j in y-coordinate check;
- Name All Polynomial Constraints;
- remove point_repr() helper function;
- variable renaming and docfixes.
Co-authored-by: Jack Grigg <jack@electriccoin.co>
Instead of separately witnessing k_1 and equating it to z1_j, we
can directly make use of z1_j in the gate. This allows us to fit
the region into a 5 x 2 area, improving the layout.
Co-authored-by: Jack Grigg <jack@electriccoin.co>
Even though we only use the LSB of the y-coordinates as inputs to
the Sinsemilla hash, we still have to check that they are consistent
with the g_d and pk_d points that were passed in.
Co-authored-by: Daira Hopwood <daira@jacaranda.org>
Co-authored-by: Jack Grigg <jack@electriccoin.co>
Change the region layout to only use 9 advice columns instead of 10.
Also rename variables to match the book.
Co-authored-by: Jack Grigg <jack@electriccoin.co>
Previously, these two helpers were returning different outputs.
They have now been standardised to return only the full running
sum.
Note the z_0 is the original element being decomposed by the
helper.
- Placing the Poseidon `state` columns after the `partial_sbox` column
instead of before it causes them to line up with vast stretch of free
space, enabling the pad-and-add region to be layed out there.
- Using the `Region::assign_advice_from_constant` API to initialise the
Poseidon state removes fixed-column contention between that region and
fixed-base scalar multiplication, enabling it to also be layed out
within the free space.
- If https://github.com/zcash/halo2/issues/334 were implemented then
this region would disappear.
- The overflow check in variable-base scalar mul is also moved into the
columns with free space.
Previously, the short_lookup_bitshift fixed column was a non-binary
selector that both provided a constant value and toggled a gate.
Now, the constant value is copied in from the global constants API,
and the toggle is handled by a q_lookup_bitshift selector.
Previously, l_plus_1 was a non-binary fixed column, used to
1. provide the value of l + 1; and
2. toggle the decomposition gate.
Now, the value is copied in from the global constants column, and
the toggle is handled by a binary q_decompose selector.
Previously, fixed_y_q was a non-binary selector that both loaded
the y_Q value and toggled the y_Q gate.
Now, the gate is toggled by a q_s4 simple selector, while the value
is loaded into a separate fixed column.
The Action circuit only used standard PLONK in one place. Since it
used non-binary selectors, it cannot be optimised by the halo2
selector optimisations. We now replace it with a custom gate which
uses a binary selector.
The Sinsemilla chip witnesses message pieces in individual regions, and
then copies them into the `hash_piece` region to initialize the running
sum. Previously these occured in the same column, but we can reduce the
utilized rows of the Action circuit by moving these into a less-used
column.
If https://github.com/zcash/halo2/issues/334 is implemented, this change
would be unnecessary, as the witnessed message piece regions would never
be assigned into the circuit.
We were configuring multiple instances of this across all of the advice
columns, in order to spread their assignments. However, we are actually
more constrained by columns than rows, and we have comparatively few
rows of range check logic required for the Action circuit.
We now use a single LookupRangeCheckConfig for the entire circuit. The
reduction in lookup arguments and fixed columns cuts the proof size in
half (now at 6048 bytes when using `floor_planner::V1`).
Co-authored-by: therealyingtong <yingtong@z.cash>
- Move Poseidon into the right-hand advice columns. The Action circuit
has 33 Sinsemilla invocations with 510-bit inputs (the 32 Merkle path
hashes, and Commit^ivk). Poseidon fits within the row count of one of
these invocations, so we can run it in parallel with these.
- Share fixed columns between ECC and Poseidon chips. Poseidon requires
four advice columns, while ECC incomplete addition requires six, so we
could choose to configure them in parallel. However, we only use a
single Poseidon invocation, and we have the rows to accomodate it
serially with fixed-base scalar mul. Sharing the ECC chip's 8 Lagrange
coefficient fixed columns instead reduces the proof size.
- We position Poseidon in the right-most 6 fixed columns, anticipating
a further optimisation to Sinsemilla that will occupy the left-most
2 fixed columns.
The Action Circuit configuration uses 10 advice columns. It contains:
- a single EccConfig (10 advice columns);
- two SinsemillaConfigs (5 advice columns each);
- two MerkleConfigs (5 advice columns each);
- a PoseidonConfig, (4 advice columns);
- a PLONKConfig for standard PLONK operations (3 advice columns);
and some infrastructure to handle public inputs (subject to change
at the time of commit).
The 5-column configs are placed side-by-side in the circuit to
optimize space usage.
Gate creation is delegated to the configure() function of each
respective Chip.
The Default Circuit sets all fields to None. This is used as a
placeholder in src/builder.rs.
The circuit in the Circuit::round_trip() test has been filled in.
This was previously creating an extra advice column. Instead, we
should pass in all required advice columns as inputs.
Co-authored-by: Jack Grigg <jack@electriccoin.co>
- `halo2::plonk::{create_proof, verify_proof}` now take instance columns
as slices of values.
- `halo2::plonk::Permutation` has been replaced by a global permutation,
to which columns can be added with `ConstraintSystem::enable_equality`.
- The introduction of blinding rows means that various tests now require
larger circuit parameters.
The coordinate check for an element decomposed using a running sum
is enforced by mul_fixed::Config::running_sum_coords_gate().
Co-authored-by: Jack Grigg <jack@electriccoin.co>
Selectors previously used in the witness_scalar_* APIs, such as
q_scalar_fixed and q_scalar_fixed_short, are now removed. The
remaining selectors have been renamed for clarity.
The coordinates check for scalars decomposed using a running sum
has been moved into the mul_fixed.rs file, instead of being
duplicated in both mul_fixed::base_field_elem and mul_fixed::short.
The decompose_scalar_fixed() method is now only used in
mul_fixed::full_width, and has been moved there.
These are now provided as inputs to the witness_decompose() and
copy_decompose() methods. This allows us to reuse the same config
for different word/window lengths, avoiding a duplicate constraint
creation.
Co-authored-by: Jack Grigg <jack@electriccoin.co>
In the Orchard protocol, only the NullifierK fixed base in used in
scalar multiplication with a base field element.
The mul_fixed_base_field_elem() API does not have to accept fixed
bases other than NullifierK; conversely, NullifierK does not have
to work with the full-width mul_fixed() API.
This decomposes a field element into K-bit windows using a
running sum. Each step of the running sum is range-constrained.
In strict mode, the final output of the running sum is constrained
to be zero.
This helper asserts K <= 3.
The mul_fixed regions use complete addition on the last window,
and incomplete addition on all other windows. However, the complete
addition does not depend on any offsets in the incomplete addition
region, and can be separated into a disjoint region. Since incomplete
addition uses only four advice columns, while complete addition uses
nine, separating the regions would allow the layouter to optimise
their placement.
Co-authored-by: Jack Grigg <jack@electriccoin.co>
We can use the three-bit existing running sum decomposition to
constrain alpha_0 to be within 130 bits. This removes the need for
a 10-bit lookup decomposition of alpha_0.
Co-authored-by: Daira Hopwood <daira@jacaranda.org>
The differences between the final iteration and prior iterations are:
- The final iteration does not constrain (x_T, y_T) to propagate down.
- The final iteration constrains an assigned y_A output instead of a
derived y_A from the next iteration's variables.
We also swap the init_y constraint to match the book.
Co-authored-by: therealyingtong <yingtong@z.cash>
At certain points in the circuit, we need to constrain cells in
advice columns to equal a fixed constant. Instead of defining a
new fixed column for each constant, we pass around a single
shared by all chips, that is included in the permutation over all
advice columns.
This lets us load all needed constants into a single column and
directly constrain advice cells with an equality constraint.
On the LSB of the scalar, we assign a point (x,y) = (x_p, -y_p)
if LSB = 0, and (0,0) otherwise. This if/else condition must be
enforced.
Co-authored-by: Sean Bowe <ewillbefull@gmail.com>
Using these in `OrchardFixedBases::{generator, u}` instead of the
`impl From<OrchardFixedBasesFull> for OrchardFixedBase` means we avoid
computing the Lagrange coefficients for the generator (which were then
immediately dropped).
This decreases proving time in the Action circuit by 53%.
In Orchard nullifier derivation, we multiply the fixed base
K^Orchard by a value encoded as a base field element. This commit
introduces an API that allows using a base field element as the
"scalar" in fixed-base scalar multiplication.
The API currently assumes that the base field element is output by
another instruction (i.e. there is no instruction to directly
witness it).
The magnitude of the short signed scalar must be 64 bits. We decompose
the magnitude into 22 3-bit windows and check that each window is in
the 3-bit range.
However, since the first 21 windows have already accounted for 63 bits,
the last window is constrained to be a single bit.
Simplify the canonicity check for variable-base scalar multiplication,
by range-checking the low 130 bits rather than the low 127 bits.
Signed-off-by: Daira Hopwood <daira@jacaranda.org>
Co-authored-by: ying tong <yingtong@z.cash>
Fixed-base scalar mul makes use of the add_incomplete and add
instructions internally. The full-width and short signed share
some common logic, which is captured in chip::mul_fixed.rs.
The signed short variant introduces additional logic to handle
the scalar's sign. This is done in the submodule mul_fixed::short.
A scalar used in fixed-base scalar mul needs to be decomposed into
windows to use with the fixed-base window table. Both full-width
and short signed scalars share some logic (captured in the function
decompose_scalar_fixed()).
A short signed scalar introduces additional logic: its magnitude is
decomposed, and its sign is separately witnessed. This is handled
in the submodule witness_scalar_fixed::short.
This uses the complete addition instruction internally. The module
is split up into mul::incomplete.rs and mul::complete.rs, where
mul::incomplete handles the incomplete additions used in the
starting rounds of the variable-base scalar mul algorithm, and
mul::complete handles the complete additions in the final rounds.
Incomplete additions are broken into "hi" and "lo" halves and
processed on the same rows across different columns. This is an
optimization to make full use of the advice columns in this
instruction.
- document that find_zs_and_us is not meant to be used anywhere
- use F::zero() instead of F::default() in constants/util.rs
- use personalisations from constants in spec.rs
This has three const generic parameters: PATH_LENGTH, K, MAX_WORDS.
PATH_LENGTH is the length of the Merkle path being hashed. K and
MAX_WORDS parameterize the internal Sinsemilla instance used in
hashing the path.
These instructions were not making any assignments; instead, they
were calling through to witness_message_piece_field().
This PR also renames the witness_message_piece_field() instruction
to witness_message_piece().
Also introduce a "strict" mode for the full-length lookup, where
"true" requires the field element to be within num_words * K bits,
whereas "false" does not.