note_commit: Decompose q_canon into two binary selectors.

Previously, q_canon was a non-binary fixed column that was set to
either {1, 2}. It has been decomposed into two binary selectors.
This commit is contained in:
therealyingtong 2021-07-24 00:46:12 +08:00
parent 76c73531c8
commit 7af1ae5b52
1 changed files with 35 additions and 63 deletions

View File

@ -1,7 +1,7 @@
use group::GroupEncoding; use group::GroupEncoding;
use halo2::{ use halo2::{
circuit::Layouter, circuit::Layouter,
plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed}, plonk::{Advice, Column, ConstraintSystem, Error, Expression, Selector},
poly::Rotation, poly::Rotation,
}; };
use pasta_curves::{ use pasta_curves::{
@ -36,27 +36,13 @@ use super::{
- v is a 64-bit value; - v is a 64-bit value;
- rho is a base field element (255 bits); and - rho is a base field element (255 bits); and
- psi is a base field element (255 bits). - psi is a base field element (255 bits).
All bit ranges are inclusive.
a (250 bits) = bits 0..=249 of x(g_d)
b (10 bits) = b_0 || b_1 || b_2 || b_3
= (bits 250..=253 of x(g_d)) || (bit 254 of x(g_d)) || ( bit of g_d) || (bits 0..=3 of pk_d)
c (250 bits) = bits 4..=253 of pk_d
d (60 bits) = d_0 || d_1 || d_2 || d_3
= (bit 254 of x(pk_d)) || ( bit of pk_d) || (0..=7 of v) || (8..=57 of v)
e (10 bits) = e_0 || e_1
= (bits 58..=63 of v) || (bits 0..=3 of rho)
f (250 bits) = bits 4..=253 inclusive of rho
g (250 bits) = g_0 || g_1 || g_2
= (bit 254 of rho) || (bits 0..=8 of psi) || (bits 9..=248 of psi)
h (10 bits) = h_0 || h_1 || h_2
= (bits 249..=253 of psi) || (bit 254 of psi) || 4 zero bits
*/ */
#[allow(non_snake_case)] #[allow(non_snake_case)]
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct NoteCommitConfig { pub struct NoteCommitConfig {
q_canon: Column<Fixed>, q_canon_1: Selector,
q_canon_2: Selector,
advices: [Column<Advice>; 10], advices: [Column<Advice>; 10],
sinsemilla_config: SinsemillaConfig, sinsemilla_config: SinsemillaConfig,
} }
@ -69,10 +55,12 @@ impl NoteCommitConfig {
advices: [Column<Advice>; 10], advices: [Column<Advice>; 10],
sinsemilla_config: SinsemillaConfig, sinsemilla_config: SinsemillaConfig,
) -> Self { ) -> Self {
let q_canon = meta.fixed_column(); let q_canon_1 = meta.selector();
let q_canon_2 = meta.selector();
let config = Self { let config = Self {
q_canon, q_canon_1,
q_canon_2,
advices, advices,
sinsemilla_config, sinsemilla_config,
}; };
@ -93,6 +81,8 @@ impl NoteCommitConfig {
meta.create_gate("NoteCommit decomposition check", |meta| { meta.create_gate("NoteCommit decomposition check", |meta| {
/* /*
All bit ranges are inclusive.
a (250 bits) = bits 0..=249 of x(g_d) a (250 bits) = bits 0..=249 of x(g_d)
b (10 bits) = b_0 || b_1 || b_2 || b_3 b (10 bits) = b_0 || b_1 || b_2 || b_3
= (bits 250..=253 of x(g_d)) || (bit 254 of x(g_d)) || ( bit of g_d) || (bits 0..=3 of pk_d) = (bits 250..=253 of x(g_d)) || (bit 254 of x(g_d)) || ( bit of g_d) || (bits 0..=3 of pk_d)
@ -107,14 +97,14 @@ impl NoteCommitConfig {
h (10 bits) = h_0 || h_1 || h_2 h (10 bits) = h_0 || h_1 || h_2
= (bits 249..=253 of psi) || (bit 254 of psi) || 4 zero bits = (bits 249..=253 of psi) || (bit 254 of psi) || 4 zero bits
| A_0 | A_1 | A_2 | A_3 | A_4 | A_5 | A_6 | A_7 | A_8 | A_9 | q_canon | | A_0 | A_1 | A_2 | A_3 | A_4 | A_5 | A_6 | A_7 | A_8 | A_9 | q_canon_1 | q_canon_2 |
------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| a_prime | b3_c_prime | e1_f_prime | g1_g2_prime | a | b | b_2 | b_3 | c | d | | | a_prime | b3_c_prime | e1_f_prime | g1_g2_prime | a | b | b_2 | b_3 | c | d | 0 | 0 |
| d_1 | d_2 | z1_d | e | e_0 | e_1 | f | g | g_1 | h | 1 | | d_1 | d_2 | z1_d | e | e_0 | e_1 | f | g | g_1 | h | 1 | 0 |
| h_0 | h_1 | x(g_d) | x(pk_d) | value | b_0 | b_1 | d_0 | g_0 | z1_g | 2 | | h_0 | h_1 | x(g_d) | x(pk_d) | value | b_0 | b_1 | d_0 | g_0 | z1_g | 0 | 1 |
|a_prime_decomposition|b3_c_prime_decomposition|e1_f_prime_decomposition|g1_g2_prime_decomposition| z13_a | z13_c | z13_f | z13_g | psi | rho | | |a_prime_decomposition|b3_c_prime_decomposition|e1_f_prime_decomposition|g1_g2_prime_decomposition| z13_a | z13_c | z13_f | z13_g | psi | rho | 0 | 0 |
q_canon_is_one checks that: q_canon_1 checks that:
- piece decomposition: - piece decomposition:
- b = b_0 + (2^4) b_1 + (2^5) b_2 + (2^6) b_3 - b = b_0 + (2^4) b_1 + (2^5) b_2 + (2^6) b_3
- b_1 is boolean - b_1 is boolean
@ -137,11 +127,7 @@ impl NoteCommitConfig {
- e1_f_prime = e_1 + (2^4)g + 2^140 - t_P - e1_f_prime = e_1 + (2^4)g + 2^140 - t_P
- g1_g2_prime = g_1 + (2^9) g_2 + 2^140 - t_P - g1_g2_prime = g_1 + (2^9) g_2 + 2^140 - t_P
*/ */
let q_canon_is_one = { let q_canon_1 = meta.query_selector(config.q_canon_1);
let two = Expression::Constant(pallas::Base::from_u64(2));
let q_canon = meta.query_fixed(config.q_canon, Rotation::cur());
q_canon.clone() * (two - q_canon)
};
// Offset prev // Offset prev
let a_prime = meta.query_advice(config.advices[0], Rotation::prev()); let a_prime = meta.query_advice(config.advices[0], Rotation::prev());
@ -282,7 +268,7 @@ impl NoteCommitConfig {
.chain(Some(("gd_x_check", gd_x_check))) .chain(Some(("gd_x_check", gd_x_check)))
.chain(Some(("pkd_x_check", pkd_x_check))) .chain(Some(("pkd_x_check", pkd_x_check)))
.chain(Some(("value_check", value_check))) .chain(Some(("value_check", value_check)))
.map(move |(name, poly)| (name, q_canon_is_one.clone() * poly)) .map(move |(name, poly)| (name, q_canon_1.clone() * poly))
}); });
meta.create_gate("Canonicity checks", |meta| { meta.create_gate("Canonicity checks", |meta| {
@ -301,15 +287,15 @@ impl NoteCommitConfig {
h (10 bits) = h_0 || h_1 || h_2 h (10 bits) = h_0 || h_1 || h_2
= (bits 249..=253 of psi) || (bit 254 of psi) || 4 zero bits = (bits 249..=253 of psi) || (bit 254 of psi) || 4 zero bits
| A_0 | A_1 | A_2 | A_3 | A_4 | A_5 | A_6 | A_7 | A_8 | A_9 | q_canon | | A_0 | A_1 | A_2 | A_3 | A_4 | A_5 | A_6 | A_7 | A_8 | A_9 | q_canon_1 | q_canon_2 |
------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| a_prime | b3_c_prime | e1_f_prime | g1_g2_prime | a | b | b_2 | b_3 | c | d | | | a_prime | b3_c_prime | e1_f_prime | g1_g2_prime | a | b | b_2 | b_3 | c | d | 0 | 0 |
| d_1 | d_2 | z1_d | e | e_0 | e_1 | f | g | g_1 | h | 1 | | d_1 | d_2 | z1_d | e | e_0 | e_1 | f | g | g_1 | h | 1 | 0 |
| h_0 | h_1 | x(g_d) | x(pk_d) | value | b_0 | b_1 | d_0 | g_0 | z1_g | 2 | | h_0 | h_1 | x(g_d) | x(pk_d) | value | b_0 | b_1 | d_0 | g_0 | z1_g | 0 | 1 |
|a_prime_decomposition|b3_c_prime_decomposition|e1_f_prime_decomposition|g1_g2_prime_decomposition| z13_a | z13_c | z13_f | z13_g | psi | rho | | |a_prime_decomposition|b3_c_prime_decomposition|e1_f_prime_decomposition|g1_g2_prime_decomposition| z13_a | z13_c | z13_f | z13_g | psi | rho | 0 | 0 |
*/ */
// q_canon_is_two checks that: // q_canon_2 checks that:
// - field element decomposition: // - field element decomposition:
// - rho = e_1 + (2^4) g + (2^254) h_0 // - rho = e_1 + (2^4) g + (2^254) h_0
// - psi = h_1 + (2^9) i + (2^249) j_0 + (2^254) j_1 // - psi = h_1 + (2^9) i + (2^249) j_0 + (2^254) j_1
@ -324,11 +310,7 @@ impl NoteCommitConfig {
// - j_1 = 0 => j_0 = 0 // - j_1 = 0 => j_0 = 0
// && g1_g2_prime_decomposition = 0 // && g1_g2_prime_decomposition = 0
let q_canon_is_two = { let q_canon_2 = meta.query_selector(config.q_canon_2);
let one = Expression::Constant(pallas::Base::one());
let q_canon = meta.query_fixed(config.q_canon, Rotation::cur());
q_canon.clone() * (one - q_canon)
};
// Offset prev // Offset prev
let e_1 = meta.query_advice(config.advices[5], Rotation::prev()); let e_1 = meta.query_advice(config.advices[5], Rotation::prev());
@ -411,7 +393,7 @@ impl NoteCommitConfig {
.chain(pkd_x_canonicity_checks) .chain(pkd_x_canonicity_checks)
.chain(rho_canonicity_checks) .chain(rho_canonicity_checks)
.chain(psi_canonicity_checks) .chain(psi_canonicity_checks)
.map(move |poly| q_canon_is_two.clone() * poly) .map(move |poly| q_canon_2.clone() * poly)
}); });
config config
@ -861,30 +843,20 @@ impl NoteCommitConfig {
The pieces are witnessed in the below configuration, such that no gate has to query an The pieces are witnessed in the below configuration, such that no gate has to query an
offset greater than +/- 1 from its relative row. offset greater than +/- 1 from its relative row.
| A_0 | A_1 | A_2 | A_3 | A_4 | A_5 | A_6 | A_7 | A_8 | A_9 | q_canon | | A_0 | A_1 | A_2 | A_3 | A_4 | A_5 | A_6 | A_7 | A_8 | A_9 | q_canon_1 | q_canon_2 |
------------------------------------------------------------------------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| a_prime | b3_c_prime | e1_f_prime | g1_g2_prime | a | b | b_2 | b_3 | c | d | | | a_prime | b3_c_prime | e1_f_prime | g1_g2_prime | a | b | b_2 | b_3 | c | d | 0 | 0 |
| d_1 | d_2 | z1_d | e | e_0 | e_1 | f | g | g_1 | h | 1 | | d_1 | d_2 | z1_d | e | e_0 | e_1 | f | g | g_1 | h | 1 | 0 |
| h_0 | h_1 | x(g_d) | x(pk_d) | value | b_0 | b_1 | d_0 | g_0 | z1_g | 2 | | h_0 | h_1 | x(g_d) | x(pk_d) | value | b_0 | b_1 | d_0 | g_0 | z1_g | 0 | 1 |
|a_prime_decomposition|b3_c_prime_decomposition|e1_f_prime_decomposition|g1_g2_prime_decomposition| z13_a | z13_c | z13_f | z13_g | psi | rho | | |a_prime_decomposition|b3_c_prime_decomposition|e1_f_prime_decomposition|g1_g2_prime_decomposition| z13_a | z13_c | z13_f | z13_g | psi | rho | 0 | 0 |
*/ */
layouter.assign_region( layouter.assign_region(
|| "Assign gate cells", || "Assign gate cells",
|mut region| { |mut region| {
// Assign fixed column the correct values // Assign fixed column the correct values
region.assign_fixed( self.q_canon_1.enable(&mut region, 1)?;
|| "q_canon = 1", self.q_canon_2.enable(&mut region, 2)?;
self.q_canon,
1,
|| Ok(pallas::Base::one()),
)?;
region.assign_fixed(
|| "q_canon = 2",
self.q_canon,
2,
|| Ok(pallas::Base::from_u64(2)),
)?;
// Offset 0 // Offset 0
{ {