mirror of https://github.com/zcash/halo2.git
Merge pull request #589 from zcash/protocol-rule-links
halo2_gadgets: Add protocol rule links for the chip constraints
This commit is contained in:
commit
c0db68aa05
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"decompose-combined-lookup": "design/gadgets/decomposition.html#combined-lookup-expression",
|
||||
"decompose-short-lookup": "design/gadgets/decomposition.html#short-range-check",
|
||||
"decompose-short-range": "design/gadgets/decomposition.html#short-range-decomposition",
|
||||
"ecc-complete-addition": "design/gadgets/ecc/addition.html#complete-addition-constraints",
|
||||
"ecc-incomplete-addition": "design/gadgets/ecc/addition.html#incomplete-addition-constraints",
|
||||
"ecc-fixed-mul-base-canonicity": "design/gadgets/ecc/fixed-base-scalar-mul.html#base-field-element",
|
||||
"ecc-fixed-mul-coordinates": "design/gadgets/ecc/fixed-base-scalar-mul.html#constrain-coordinates",
|
||||
"ecc-fixed-mul-full-word": "design/gadgets/ecc/fixed-base-scalar-mul.html#full-width-scalar",
|
||||
"ecc-fixed-mul-load-base": "design/gadgets/ecc/fixed-base-scalar-mul.html#load-fixed-base",
|
||||
"ecc-fixed-mul-short-msb": "design/gadgets/ecc/fixed-base-scalar-mul.html#constrain-short-signed-msb",
|
||||
"ecc-fixed-mul-short-conditional-neg": "design/gadgets/ecc/fixed-base-scalar-mul.html#constrain-short-signed-conditional-neg",
|
||||
"ecc-var-mul-complete-gate": "design/gadgets/ecc/var-base-scalar-mul.html#complete-gate",
|
||||
"ecc-var-mul-incomplete-first-row": "design/gadgets/ecc/var-base-scalar-mul.html#incomplete-first-row-gate",
|
||||
"ecc-var-mul-incomplete-last-row": "design/gadgets/ecc/var-base-scalar-mul.html#incomplete-last-row-gate",
|
||||
"ecc-var-mul-incomplete-main-loop": "design/gadgets/ecc/var-base-scalar-mul.html#incomplete-main-loop-gate",
|
||||
"ecc-var-mul-lsb-gate": "design/gadgets/ecc/var-base-scalar-mul.html#lsb-gate",
|
||||
"ecc-var-mul-overflow": "design/gadgets/ecc/var-base-scalar-mul.html#overflow-check-constraints",
|
||||
"ecc-var-mul-witness-scalar": "design/gadgets/ecc/var-base-scalar-mul.html#witness-scalar",
|
||||
"ecc-witness-point": "design/gadgets/ecc/witnessing-points.html#points-including-the-identity",
|
||||
"ecc-witness-non-identity-point": "design/gadgets/ecc/witnessing-points.html#non-identity-points",
|
||||
"sinsemilla-constraints": "design/gadgets/sinsemilla.html#optimized-sinsemilla-gate",
|
||||
"sinsemilla-merkle-crh-bit-lengths": "design/gadgets/sinsemilla/merkle-crh.html#bit-length-constraints",
|
||||
"sinsemilla-merkle-crh-decomposition": "design/gadgets/sinsemilla/merkle-crh.html#decomposition-constraints"
|
||||
}
|
|
@ -41,7 +41,7 @@ So we get the constraints:
|
|||
and so cannot be used with arbitrary inputs.
|
||||
- $(y_r + y_q) \cdot (x_p - x_q) - (y_p - y_q) \cdot (x_q - x_r) = 0.$
|
||||
|
||||
### Constraints
|
||||
### Constraints <a name="incomplete-addition-constraints">
|
||||
|
||||
$$
|
||||
\begin{array}{|c|l|}
|
||||
|
@ -99,7 +99,7 @@ $\hspace{1em}
|
|||
\end{array}
|
||||
$
|
||||
|
||||
### Constraints
|
||||
### Constraints <a name="complete-addition-constraints">
|
||||
|
||||
$$
|
||||
\begin{array}{|c|lcl|l|}
|
||||
|
|
|
@ -91,7 +91,7 @@ $\mathsf{v^{old}}$ and $\mathsf{v^{new}}$ are each already constrained to $64$ b
|
|||
|
||||
Decompose the magnitude $m$ into three-bit windows, and range-constrain each window, using the [short range decomposition](../decomposition.md#short-range-decomposition) gadget in strict mode, with $W = 22, K = 3.$
|
||||
|
||||
We have two additional constraints:
|
||||
<a name="constrain-short-signed-msb"></a> We have two additional constraints:
|
||||
$$
|
||||
\begin{array}{|c|l|l|}
|
||||
\hline
|
||||
|
@ -147,7 +147,7 @@ Given a decomposed scalar $\alpha$ and a fixed base $B$, we compute $[\alpha]B$
|
|||
|
||||
> Note: complete addition is required in the final step to correctly map $[0]B$ to a representation of the point at infinity, $(0,0)$; and also to handle a corner case for which the last step is a doubling.
|
||||
|
||||
Constraints:
|
||||
<a name="constrain-coordinates"></a> Constraints:
|
||||
$$
|
||||
\begin{array}{|c|l|}
|
||||
\hline
|
||||
|
@ -163,7 +163,7 @@ where $b = 5$ (from the Pallas curve equation).
|
|||
### Signed short exponent
|
||||
Recall that the signed short exponent is witnessed as a $64-$bit magnitude $m$, and a sign $s \in {1, -1}.$ Using the above algorithm, we compute $P = [m] \mathcal{B}$. Then, to get the final result $P',$ we conditionally negate $P$ using $(x, y) \mapsto (x, s \cdot y)$.
|
||||
|
||||
Constraints:
|
||||
<a name="constrain-short-signed-conditional-neg"></a> Constraints:
|
||||
$$
|
||||
\begin{array}{|c|l|}
|
||||
\hline
|
||||
|
|
|
@ -177,7 +177,7 @@ $$
|
|||
|
||||
For each $hi$ and $lo$ half, we have three sets of gates. Note that $i$ is going from $255..=3$; $i$ is NOT indexing the rows.
|
||||
|
||||
#### $q_1 = 1$
|
||||
### $q_1 = 1$ <a name="incomplete-first-row-gate">
|
||||
This gate is only used on the first row (before the for loop). We check that $\lambda_1, \lambda_2$ are initialized to values consistent with the initial $y_A.$
|
||||
$$
|
||||
\begin{array}{|c|l|}
|
||||
|
@ -194,7 +194,7 @@ y_{A,n}^\text{witnessed} &\text{ is witnessed.}
|
|||
\end{aligned}
|
||||
$$
|
||||
|
||||
#### $q_2 = 1$
|
||||
### $q_2 = 1$ <a name="incomplete-main-loop-gate">
|
||||
This gate is used on all rows corresponding to the for loop except the last.
|
||||
|
||||
$$
|
||||
|
@ -218,7 +218,7 @@ y_{A,i-1} &= \frac{(\lambda_{1,i-1} + \lambda_{2,i-1}) \cdot (x_{A,i-1} - (\lamb
|
|||
\end{aligned}
|
||||
$$
|
||||
|
||||
#### $q_3 = 1$
|
||||
### $q_3 = 1$ <a name="incomplete-last-row-gate">
|
||||
This gate is used on the final iteration of the for loop, handling the special case where we check that the output $y_A$ has been witnessed correctly.
|
||||
$$
|
||||
\begin{array}{|c|l|}
|
||||
|
|
|
@ -89,6 +89,7 @@ impl Config {
|
|||
}
|
||||
|
||||
fn create_gate(&self, meta: &mut ConstraintSystem<pallas::Base>) {
|
||||
// https://p.z.cash/halo2-0.1:ecc-complete-addition
|
||||
meta.create_gate("complete addition", |meta| {
|
||||
let q_add = meta.query_selector(self.q_add);
|
||||
let x_p = meta.query_advice(self.x_p, Rotation::cur());
|
||||
|
|
|
@ -56,7 +56,8 @@ impl Config {
|
|||
}
|
||||
|
||||
fn create_gate(&self, meta: &mut ConstraintSystem<pallas::Base>) {
|
||||
meta.create_gate("incomplete addition gates", |meta| {
|
||||
// https://p.z.cash/halo2-0.1:ecc-incomplete-addition
|
||||
meta.create_gate("incomplete addition", |meta| {
|
||||
let q_add_incomplete = meta.query_selector(self.q_add_incomplete);
|
||||
let x_p = meta.query_advice(self.x_p, Rotation::cur());
|
||||
let y_p = meta.query_advice(self.y_p, Rotation::cur());
|
||||
|
|
|
@ -130,6 +130,7 @@ impl Config {
|
|||
|
||||
fn create_gate(&self, meta: &mut ConstraintSystem<pallas::Base>) {
|
||||
// If `lsb` is 0, (x, y) = (x_p, -y_p). If `lsb` is 1, (x, y) = (0,0).
|
||||
// https://p.z.cash/halo2-0.1:ecc-var-mul-lsb-gate?partial
|
||||
meta.create_gate("LSB check", |meta| {
|
||||
let q_mul_lsb = meta.query_selector(self.q_mul_lsb);
|
||||
|
||||
|
@ -317,6 +318,8 @@ impl Config {
|
|||
/// | x_p | y_p | acc_x | acc_y | complete addition | z_1 | q_mul_lsb = 1
|
||||
/// |base_x|base_y| res_x | res_y | | | | | | z_0 |
|
||||
/// ```
|
||||
///
|
||||
/// [Specification](https://p.z.cash/halo2-0.1:ecc-var-mul-lsb-gate?partial).
|
||||
fn process_lsb(
|
||||
&self,
|
||||
region: &mut Region<'_, pallas::Base>,
|
||||
|
@ -432,6 +435,7 @@ impl<F: FieldExt> Deref for Z<F> {
|
|||
}
|
||||
}
|
||||
|
||||
// https://p.z.cash/halo2-0.1:ecc-var-mul-witness-scalar?partial
|
||||
fn decompose_for_scalar_mul(scalar: Option<&pallas::Base>) -> Vec<Option<bool>> {
|
||||
construct_uint! {
|
||||
struct U256(4);
|
||||
|
|
|
@ -49,6 +49,7 @@ impl Config {
|
|||
// | y_p | z_{i + 1} |
|
||||
// | | base_y |
|
||||
// | | z_i |
|
||||
// https://p.z.cash/halo2-0.1:ecc-var-mul-complete-gate
|
||||
meta.create_gate(
|
||||
"Decompose scalar for complete bits of variable-base mul",
|
||||
|meta| {
|
||||
|
|
|
@ -116,6 +116,8 @@ impl<const NUM_BITS: usize> Config<NUM_BITS> {
|
|||
};
|
||||
|
||||
// Constraints used for q_mul_{2, 3} == 1
|
||||
// https://p.z.cash/halo2-0.1:ecc-var-mul-incomplete-main-loop?partial
|
||||
// https://p.z.cash/halo2-0.1:ecc-var-mul-incomplete-last-row?partial
|
||||
let for_loop = |meta: &mut VirtualCells<pallas::Base>,
|
||||
y_a_next: Expression<pallas::Base>| {
|
||||
let one = Expression::Constant(pallas::Base::one());
|
||||
|
@ -167,6 +169,7 @@ impl<const NUM_BITS: usize> Config<NUM_BITS> {
|
|||
};
|
||||
|
||||
// q_mul_1 == 1 checks
|
||||
// https://p.z.cash/halo2-0.1:ecc-var-mul-incomplete-first-row
|
||||
meta.create_gate("q_mul_1 == 1 checks", |meta| {
|
||||
let q_mul_1 = meta.query_selector(self.q_mul_1);
|
||||
|
||||
|
@ -176,6 +179,7 @@ impl<const NUM_BITS: usize> Config<NUM_BITS> {
|
|||
});
|
||||
|
||||
// q_mul_2 == 1 checks
|
||||
// https://p.z.cash/halo2-0.1:ecc-var-mul-incomplete-main-loop?partial
|
||||
meta.create_gate("q_mul_2 == 1 checks", |meta| {
|
||||
let q_mul_2 = meta.query_selector(self.q_mul_2);
|
||||
|
||||
|
@ -205,6 +209,7 @@ impl<const NUM_BITS: usize> Config<NUM_BITS> {
|
|||
});
|
||||
|
||||
// q_mul_3 == 1 checks
|
||||
// https://p.z.cash/halo2-0.1:ecc-var-mul-incomplete-last-row?partial
|
||||
meta.create_gate("q_mul_3 == 1 checks", |meta| {
|
||||
let q_mul_3 = meta.query_selector(self.q_mul_3);
|
||||
let y_a_final = meta.query_advice(self.double_and_add.lambda_1, Rotation::next());
|
||||
|
@ -293,6 +298,7 @@ impl<const NUM_BITS: usize> Config<NUM_BITS> {
|
|||
// Incomplete addition
|
||||
for (row, k) in bits.iter().enumerate() {
|
||||
// z_{i} = 2 * z_{i+1} + k_i
|
||||
// https://p.z.cash/halo2-0.1:ecc-var-mul-witness-scalar?partial
|
||||
let z_val = z
|
||||
.value()
|
||||
.zip(k.as_ref())
|
||||
|
|
|
@ -47,6 +47,7 @@ impl Config {
|
|||
}
|
||||
|
||||
fn create_gate(&self, meta: &mut ConstraintSystem<pallas::Base>) {
|
||||
// https://p.z.cash/halo2-0.1:ecc-var-mul-overflow
|
||||
meta.create_gate("overflow checks", |meta| {
|
||||
let q_mul_overflow = meta.query_selector(self.q_mul_overflow);
|
||||
|
||||
|
|
|
@ -131,6 +131,7 @@ impl<FixedPoints: super::FixedPoints<pallas::Affine>> Config<FixedPoints> {
|
|||
});
|
||||
}
|
||||
|
||||
/// [Specification](https://p.z.cash/halo2-0.1:ecc-fixed-mul-coordinates).
|
||||
#[allow(clippy::op_ref)]
|
||||
fn coords_check(
|
||||
&self,
|
||||
|
@ -196,6 +197,7 @@ impl<FixedPoints: super::FixedPoints<pallas::Affine>> Config<FixedPoints> {
|
|||
Ok((acc, mul_b))
|
||||
}
|
||||
|
||||
/// [Specification](https://p.z.cash/halo2-0.1:ecc-fixed-mul-load-base).
|
||||
fn assign_fixed_constants<F: FixedPoint<pallas::Affine>, const NUM_WINDOWS: usize>(
|
||||
&self,
|
||||
region: &mut Region<'_, pallas::Base>,
|
||||
|
|
|
@ -58,6 +58,7 @@ impl<Fixed: FixedPoints<pallas::Affine>> Config<Fixed> {
|
|||
|
||||
fn create_gate(&self, meta: &mut ConstraintSystem<pallas::Base>) {
|
||||
// Check that the base field element is canonical.
|
||||
// https://p.z.cash/halo2-0.1:ecc-fixed-mul-base-canonicity
|
||||
meta.create_gate("Canonicity checks", |meta| {
|
||||
let q_mul_fixed_base_field = meta.query_selector(self.q_mul_fixed_base_field);
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ impl<Fixed: FixedPoints<pallas::Affine>> Config<Fixed> {
|
|||
|
||||
fn create_gate(&self, meta: &mut ConstraintSystem<pallas::Base>) {
|
||||
// Check that each window `k` is within 3 bits
|
||||
// https://p.z.cash/halo2-0.1:ecc-fixed-mul-full-word
|
||||
meta.create_gate("Full-width fixed-base scalar mul", |meta| {
|
||||
let q_mul_fixed_full = meta.query_selector(self.q_mul_fixed_full);
|
||||
let window = meta.query_advice(self.super_config.window, Rotation::cur());
|
||||
|
|
|
@ -33,6 +33,9 @@ impl<Fixed: FixedPoints<pallas::Affine>> Config<Fixed> {
|
|||
}
|
||||
|
||||
fn create_gate(&self, meta: &mut ConstraintSystem<pallas::Base>) {
|
||||
// Gate contains the following constraints:
|
||||
// - https://p.z.cash/halo2-0.1:ecc-fixed-mul-short-msb
|
||||
// - https://p.z.cash/halo2-0.1:ecc-fixed-mul-short-conditional-neg
|
||||
meta.create_gate("Short fixed-base mul gate", |meta| {
|
||||
let q_mul_fixed_short = meta.query_selector(self.q_mul_fixed_short);
|
||||
let y_p = meta.query_advice(self.super_config.add_config.y_p, Rotation::cur());
|
||||
|
|
|
@ -53,6 +53,7 @@ impl Config {
|
|||
y.square() - (x.clone().square() * x) - Expression::Constant(pallas::Affine::b())
|
||||
};
|
||||
|
||||
// https://p.z.cash/halo2-0.1:ecc-witness-point
|
||||
meta.create_gate("witness point", |meta| {
|
||||
// Check that the point being witnessed is either:
|
||||
// - the identity, which is mapped to (0, 0) in affine coordinates; or
|
||||
|
@ -72,6 +73,7 @@ impl Config {
|
|||
]
|
||||
});
|
||||
|
||||
// https://p.z.cash/halo2-0.1:ecc-witness-non-identity-point
|
||||
meta.create_gate("witness non-identity point", |meta| {
|
||||
// Check that the point being witnessed is a valid curve point y^2 = x^3 + b,
|
||||
// where b = 5 in the Pallas equation
|
||||
|
|
|
@ -200,6 +200,7 @@ where
|
|||
};
|
||||
|
||||
// Check that the initial x_A, x_P, lambda_1, lambda_2 are consistent with y_Q.
|
||||
// https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial
|
||||
meta.create_gate("Initial y_Q", |meta| {
|
||||
let q_s4 = meta.query_selector(config.q_sinsemilla4);
|
||||
let y_q = meta.query_fixed(config.fixed_y_q, Rotation::cur());
|
||||
|
@ -213,6 +214,7 @@ where
|
|||
Constraints::with_selector(q_s4, Some(("init_y_q_check", init_y_q_check)))
|
||||
});
|
||||
|
||||
// https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial
|
||||
meta.create_gate("Sinsemilla gate", |meta| {
|
||||
let q_s1 = meta.query_selector(config.q_sinsemilla1);
|
||||
let q_s3 = config.q_s3(meta);
|
||||
|
|
|
@ -36,6 +36,7 @@ impl GeneratorTableConfig {
|
|||
config.generator_table.table_y,
|
||||
);
|
||||
|
||||
// https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial
|
||||
meta.lookup(|meta| {
|
||||
let q_s1 = meta.query_selector(config.q_sinsemilla1);
|
||||
let q_s2 = meta.query_fixed(config.q_sinsemilla2, Rotation::cur());
|
||||
|
|
|
@ -25,6 +25,7 @@ where
|
|||
Fixed: FixedPoints<pallas::Affine>,
|
||||
Commit: CommitDomains<pallas::Affine, Fixed, Hash>,
|
||||
{
|
||||
/// [Specification](https://p.z.cash/halo2-0.1:sinsemilla-constraints?partial).
|
||||
#[allow(non_snake_case)]
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub(super) fn hash_message(
|
||||
|
|
|
@ -150,11 +150,13 @@ where
|
|||
// b_2 has been constrained to be 5 bits outside this gate.
|
||||
let b_2 = meta.query_advice(advices[3], Rotation::next());
|
||||
// Constrain b_1 + 2^5 b_2 = z1_b
|
||||
// https://p.z.cash/halo2-0.1:sinsemilla-merkle-crh-bit-lengths?partial
|
||||
let b1_b2_check = z1_b.clone() - (b_1.clone() + b_2.clone() * two_pow_5);
|
||||
// Derive b_0 (constrained by SinsemillaHash to be 10 bits)
|
||||
let b_0 = b_whole - (z1_b * two_pow_10);
|
||||
|
||||
// Check that left = a_1 (240 bits) || b_0 (10 bits) || b_1 (5 bits)
|
||||
// https://p.z.cash/halo2-0.1:sinsemilla-merkle-crh-decomposition?partial
|
||||
let left_check = {
|
||||
let reconstructed = {
|
||||
let two_pow_240 = pallas::Base::from_u128(1 << 120).square();
|
||||
|
@ -166,6 +168,7 @@ where
|
|||
// Check that right = b_2 (5 bits) || c (250 bits)
|
||||
// The Orchard specification allows this representation to be non-canonical.
|
||||
// <https://zips.z.cash/protocol/protocol.pdf#merklepath>
|
||||
// https://p.z.cash/halo2-0.1:sinsemilla-merkle-crh-decomposition?partial
|
||||
let right_check = b_2 + c_whole * two_pow_5 - right_node;
|
||||
|
||||
Constraints::with_selector(
|
||||
|
@ -213,7 +216,6 @@ where
|
|||
) -> Result<Self::Var, Error> {
|
||||
let config = self.config().clone();
|
||||
|
||||
// <https://zips.z.cash/protocol/protocol.pdf#orchardmerklecrh>
|
||||
// We need to hash `l || left || right`, where `l` is a 10-bit value.
|
||||
// We allow `left` and `right` to be non-canonical 255-bit encodings.
|
||||
//
|
||||
|
@ -224,6 +226,8 @@ where
|
|||
//
|
||||
// We start by witnessing all of the individual pieces, and range-constraining the
|
||||
// short pieces b_1 and b_2.
|
||||
//
|
||||
// https://p.z.cash/halo2-0.1:sinsemilla-merkle-crh-bit-lengths?partial
|
||||
|
||||
// `a = a_0||a_1` = `l` || (bits 0..=239 of `left`)
|
||||
let a = MessagePiece::from_subpieces(
|
||||
|
@ -291,6 +295,8 @@ where
|
|||
// this map is the same as why Sinsemilla uses incomplete addition: this situation
|
||||
// yields a nontrivial discrete log relation, and by assumption it is hard to find
|
||||
// these.
|
||||
//
|
||||
// https://p.z.cash/proto:merkle-crh-orchard
|
||||
let (point, zs) = self.hash_to_point(
|
||||
layouter.namespace(|| format!("hash at l = {}", l)),
|
||||
Q,
|
||||
|
|
|
@ -84,6 +84,7 @@ impl<F: FieldExt + PrimeFieldBits, const WINDOW_NUM_BITS: usize>
|
|||
_marker: PhantomData,
|
||||
};
|
||||
|
||||
// https://p.z.cash/halo2-0.1:decompose-short-range
|
||||
meta.create_gate("range check", |meta| {
|
||||
let q_range_check = meta.query_selector(config.q_range_check);
|
||||
let z_cur = meta.query_advice(config.z, Rotation::cur());
|
||||
|
|
|
@ -96,6 +96,7 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize> LookupRangeCheckConfig<F, K>
|
|||
_marker: PhantomData,
|
||||
};
|
||||
|
||||
// https://p.z.cash/halo2-0.1:decompose-combined-lookup
|
||||
meta.lookup(|meta| {
|
||||
let q_lookup = meta.query_selector(config.q_lookup);
|
||||
let q_running = meta.query_selector(config.q_running);
|
||||
|
@ -130,6 +131,7 @@ impl<F: FieldExt + PrimeFieldBits, const K: usize> LookupRangeCheckConfig<F, K>
|
|||
});
|
||||
|
||||
// For short lookups, check that the word has been shifted by the correct number of bits.
|
||||
// https://p.z.cash/halo2-0.1:decompose-short-lookup
|
||||
meta.create_gate("Short lookup bitshift", |meta| {
|
||||
let q_bitshift = meta.query_selector(config.q_bitshift);
|
||||
let word = meta.query_advice(config.running_sum, Rotation::prev());
|
||||
|
|
Loading…
Reference in New Issue