Optimise location of Poseidon within Action circuit

- 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.
This commit is contained in:
Jack Grigg 2021-07-21 12:13:47 +01:00
parent d80333799d
commit 5e6c8ae380
8 changed files with 107 additions and 31 deletions

View File

@ -203,16 +203,36 @@ impl plonk::Circuit<pallas::Base> for Circuit {
meta.enable_equality((*advice).into());
}
// 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.
// Instead, we reduce the proof size by sharing fixed columns between the ECC and
// Poseidon chips.
let lagrange_coeffs = [
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
];
let rc_a = lagrange_coeffs[2..5].try_into().unwrap();
let rc_b = lagrange_coeffs[5..8].try_into().unwrap();
// Configuration for curve point operations.
// This uses 10 advice columns and spans the whole circuit.
let ecc_config = EccChip::configure(meta, advices, table_idx);
let ecc_config = EccChip::configure(meta, advices, table_idx, lagrange_coeffs);
// Configuration for the Poseidon hash.
let poseidon_config = PoseidonChip::configure(
meta,
poseidon::OrchardNullifier,
[advices[0], advices[1], advices[2]],
advices[3],
advices[5..8].try_into().unwrap(),
advices[8],
rc_a,
rc_b,
);
// Configuration for standard PLONK (addition and multiplication).

View File

@ -433,11 +433,21 @@ mod tests {
meta.advice_column(),
];
let lookup_table = meta.fixed_column();
let lagrange_coeffs = [
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
];
// Shared fixed column for loading constants
let constants = meta.fixed_column();
meta.enable_constant(constants);
EccChip::configure(meta, advices, lookup_table)
EccChip::configure(meta, advices, lookup_table, lagrange_coeffs)
}
fn synthesize(

View File

@ -153,6 +153,7 @@ impl EccChip {
meta: &mut ConstraintSystem<pallas::Base>,
advices: [Column<Advice>; 10],
lookup_table: Column<Fixed>,
lagrange_coeffs: [Column<Fixed>; 8],
) -> <Self as Chip<pallas::Base>>::Config {
// The following columns need to be equality-enabled for their use in sub-configs:
//
@ -193,16 +194,7 @@ impl EccChip {
let config = EccConfig {
advices,
lagrange_coeffs: [
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
],
lagrange_coeffs,
fixed_z: meta.fixed_column(),
q_add_incomplete: meta.selector(),
q_add: meta.selector(),

View File

@ -405,12 +405,22 @@ pub mod tests {
meta.advice_column(),
];
let lookup_table = meta.fixed_column();
let lagrange_coeffs = [
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
];
// Shared fixed column for loading constants
let constants = meta.fixed_column();
meta.enable_constant(constants);
EccChip::configure(meta, advices, lookup_table)
EccChip::configure(meta, advices, lookup_table, lagrange_coeffs)
}
fn synthesize(

View File

@ -53,6 +53,8 @@ impl<F: FieldExt> Pow5T3Chip<F> {
spec: S,
state: [Column<Advice>; WIDTH],
partial_sbox: Column<Advice>,
rc_a: [Column<Fixed>; WIDTH],
rc_b: [Column<Fixed>; WIDTH],
) -> Pow5T3Config<F> {
// Generate constants for the Poseidon permutation.
// This gadget requires R_F and R_P to be even.
@ -62,17 +64,6 @@ impl<F: FieldExt> Pow5T3Chip<F> {
let half_partial_rounds = S::partial_rounds() / 2;
let (round_constants, m_reg, m_inv) = spec.constants();
let rc_a = [
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
];
let rc_b = [
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
];
// This allows state words to be initialized (by constraining them equal to fixed
// values), and used in a permutation from an arbitrary region. rc_a is used in
// every permutation round, while rc_b is empty in the initial and final full
@ -645,7 +636,18 @@ mod tests {
];
let partial_sbox = meta.advice_column();
Pow5T3Chip::configure(meta, OrchardNullifier, state, partial_sbox)
let rc_a = [
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
];
let rc_b = [
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
];
Pow5T3Chip::configure(meta, OrchardNullifier, state, partial_sbox, rc_a, rc_b)
}
fn synthesize(
@ -741,7 +743,18 @@ mod tests {
];
let partial_sbox = meta.advice_column();
Pow5T3Chip::configure(meta, OrchardNullifier, state, partial_sbox)
let rc_a = [
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
];
let rc_b = [
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
];
Pow5T3Chip::configure(meta, OrchardNullifier, state, partial_sbox, rc_a, rc_b)
}
fn synthesize(

View File

@ -459,11 +459,21 @@ mod tests {
meta.enable_constant(constants);
let table_idx = meta.fixed_column();
let lagrange_coeffs = [
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
];
// Fixed columns for the Sinsemilla generator lookup table
let lookup = (table_idx, meta.fixed_column(), meta.fixed_column());
let ecc_config = EccChip::configure(meta, advices, table_idx);
let ecc_config = EccChip::configure(meta, advices, table_idx, lagrange_coeffs);
let config1 = SinsemillaChip::configure(meta, advices[..5].try_into().unwrap(), lookup);
let config2 = SinsemillaChip::configure(meta, advices[5..].try_into().unwrap(), lookup);

View File

@ -685,13 +685,23 @@ mod tests {
let table_idx = meta.fixed_column();
let lookup = (table_idx, meta.fixed_column(), meta.fixed_column());
let lagrange_coeffs = [
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
];
let sinsemilla_config =
SinsemillaChip::configure(meta, advices[..5].try_into().unwrap(), lookup);
let commit_ivk_config =
CommitIvkConfig::configure(meta, advices, sinsemilla_config);
let ecc_config = EccChip::configure(meta, advices, table_idx);
let ecc_config = EccChip::configure(meta, advices, table_idx, lagrange_coeffs);
(commit_ivk_config, ecc_config)
}

View File

@ -1347,12 +1347,23 @@ mod tests {
let table_idx = meta.fixed_column();
let lookup = (table_idx, meta.fixed_column(), meta.fixed_column());
let lagrange_coeffs = [
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
meta.fixed_column(),
];
let sinsemilla_config =
SinsemillaChip::configure(meta, advices[..5].try_into().unwrap(), lookup);
let note_commit_config =
NoteCommitConfig::configure(meta, advices, sinsemilla_config);
let ecc_config = EccChip::configure(meta, advices, table_idx);
let ecc_config = EccChip::configure(meta, advices, table_idx, lagrange_coeffs);
(note_commit_config, ecc_config)
}