Skip to content

Commit

Permalink
Minor refactors, cleanups, clippy fixes, docfixes.
Browse files Browse the repository at this point in the history
Co-authored-by: Daira Hopwood <daira@jacaranda.org>
Co-authored-by: Jack Grigg <jack@electriccoin.co>
  • Loading branch information
3 people committed Jul 8, 2021
1 parent 96863c9 commit 22ec16f
Show file tree
Hide file tree
Showing 9 changed files with 119 additions and 154 deletions.
8 changes: 6 additions & 2 deletions src/circuit/gadget/ecc/chip.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,8 +284,12 @@ pub struct EccScalarFixed {
/// A signed short scalar used for fixed-base scalar multiplication.
/// A short scalar must have magnitude in the range [0..2^64), with
/// a sign of either 1 or -1.
/// This is decomposed into 22 3-bit windows in little-endian order,
/// i.e. `windows` = [k_0, k_1, ..., k_21] (for a 64-bit magnitude)
/// This is decomposed into 3-bit windows in little-endian order
/// using a running sum `z`, where z_{i+1} = (z_i - a_i) / (2^3)
/// for element α = a_0 + (2^3) a_1 + ... + (2^{3(n-1)}) a_{n-1}.
/// Each `a_i` is in the range [0..2^3).
///
/// `windows` = [k_0, k_1, ..., k_21] (for a 64-bit magnitude)
/// where `scalar = k_0 + k_1 * (2^3) + ... + k_84 * (2^3)^84` and
/// each `k_i` is in the range [0..2^3).
/// k_21 must be a single bit, i.e. 0 or 1.
Expand Down
11 changes: 7 additions & 4 deletions src/circuit/gadget/ecc/chip/mul.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use super::{add, CellValue, EccConfig, EccPoint, EccScalarVar, Var};
use crate::{
circuit::gadget::utilities::copy,
constants::{NUM_COMPLETE_BITS, T_Q},
};
use crate::{circuit::gadget::utilities::copy, constants::T_Q};
use std::ops::{Deref, Range};

use bigint::U256;
Expand All @@ -20,12 +17,18 @@ mod complete;
mod incomplete;
mod overflow;

/// Number of bits for which complete addition needs to be used in variable-base
/// scalar multiplication
const NUM_COMPLETE_BITS: usize = 3;

// Bits used in incomplete addition. k_{254} to k_{4} inclusive
const INCOMPLETE_LEN: usize = pallas::Scalar::NUM_BITS as usize - 1 - NUM_COMPLETE_BITS;
const INCOMPLETE_RANGE: Range<usize> = 0..INCOMPLETE_LEN;

// Bits k_{254} to k_{4} inclusive are used in incomplete addition.
// The `hi` half is k_{254} to k_{130} inclusive (length 125 bits).
// (It is a coincidence that k_{130} matches the boundary of the
// overflow check described in [the book](https://zcash.github.io/halo2/design/gadgets/ecc/var-base-scalar-mul.html#overflow-check).)
const INCOMPLETE_HI_RANGE: Range<usize> = 0..(INCOMPLETE_LEN / 2);

// Bits k_{254} to k_{4} inclusive are used in incomplete addition.
Expand Down
153 changes: 60 additions & 93 deletions src/circuit/gadget/ecc/chip/mul_fixed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use halo2::{
},
poly::Rotation,
};
use lazy_static::lazy_static;
use pasta_curves::{
arithmetic::{CurveAffine, FieldExt},
pallas,
Expand All @@ -25,6 +26,13 @@ pub mod base_field_elem;
pub mod full_width;
pub mod short;

lazy_static! {
static ref TWO_SCALAR: pallas::Scalar = pallas::Scalar::from_u64(2);
// H = 2^3 (3-bit window)
static ref H_SCALAR: pallas::Scalar = pallas::Scalar::from_u64(constants::H as u64);
static ref H_BASE: pallas::Base = pallas::Base::from_u64(constants::H as u64);
}

// A sum type for both full-width and short bases. This enables us to use the
// shared functionality of full-width and short fixed-base scalar multiplication.
#[derive(Copy, Clone, Debug)]
Expand Down Expand Up @@ -301,70 +309,71 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
Ok(())
}

fn initialize_accumulator(
fn process_window(
&self,
region: &mut Region<'_, pallas::Base>,
offset: usize,
w: usize,
k: Option<pallas::Scalar>,
k_usize: Option<usize>,
base: OrchardFixedBases,
scalar: &ScalarFixed,
) -> Result<EccPoint, Error> {
// Recall that the message at each window `w` is represented as
// `m_w = [(k_w + 2) ⋅ 8^w]B`.
// When `w = 0`, we have `m_0 = [(k_0 + 2)]B`.
let m0 = {
let k0 = scalar.windows_field()[0];
let m0 = k0.map(|k0| base.generator() * (k0 + pallas::Scalar::from_u64(2)));
let m0 = m0.map(|m0| m0.to_affine().coordinates().unwrap());
let base_value = base.generator();
let base_u = base.u();

// Compute [(k_w + 2) ⋅ 8^w]B
let mul_b = {
let mul_b =
k.map(|k| base_value * (k + *TWO_SCALAR) * H_SCALAR.pow(&[w as u64, 0, 0, 0]));
let mul_b = mul_b.map(|mul_b| mul_b.to_affine().coordinates().unwrap());

let x = m0.map(|m0| *m0.x());
let x = mul_b.map(|mul_b| *mul_b.x());
let x_cell = region.assign_advice(
|| "m0_x",
|| format!("mul_b_x, window {}", w),
self.x_p,
offset,
offset + w,
|| x.ok_or(Error::SynthesisError),
)?;
let x = CellValue::new(x_cell, x);

let y = m0.map(|m0| *m0.y());
let y = mul_b.map(|mul_b| *mul_b.y());
let y_cell = region.assign_advice(
|| "m0_y",
|| format!("mul_b_y, window {}", w),
self.y_p,
offset,
offset + w,
|| y.ok_or(Error::SynthesisError),
)?;
let y = CellValue::new(y_cell, y);

EccPoint { x, y }
};

// Assign u = (y_p + z_w).sqrt() for `m0`
{
let k0 = scalar.windows_usize()[0];
let u0 = &base.u()[0];
let u0 = k0.map(|k0| u0.0[k0]);

region.assign_advice(|| "u", self.u, offset, || u0.ok_or(Error::SynthesisError))?;
}

// Copy `m0` into `x_qr`, `y_qr` cells on row 1 of the incomplete addition.
let x = copy(
region,
|| "initialize acc x",
self.add_incomplete_config.x_qr,
offset + 1,
&m0.x,
&self.perm,
)?;
let y = copy(
region,
|| "initialize acc y",
self.add_incomplete_config.y_qr,
offset + 1,
&m0.y,
&self.perm,
// Assign u = (y_p + z_w).sqrt()
let u_val = k_usize.map(|k| base_u[w].0[k]);
region.assign_advice(
|| "u",
self.u,
offset + w,
|| u_val.ok_or(Error::SynthesisError),
)?;

Ok(EccPoint { x, y })
Ok(mul_b)
}

fn initialize_accumulator(
&self,
region: &mut Region<'_, pallas::Base>,
offset: usize,
base: OrchardFixedBases,
scalar: &ScalarFixed,
) -> Result<EccPoint, Error> {
// Recall that the message at each window `w` is represented as
// `m_w = [(k_w + 2) ⋅ 8^w]B`.
// When `w = 0`, we have `m_0 = [(k_0 + 2)]B`.
let w = 0;
let k0 = scalar.windows_field()[0];
let k0_usize = scalar.windows_usize()[0];
self.process_window(region, offset, w, k0, k0_usize, base)
}

fn add_incomplete(
Expand All @@ -375,57 +384,18 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
base: OrchardFixedBases,
scalar: &ScalarFixed,
) -> Result<EccPoint, Error> {
// This is 2^w, where w is the window width
let h = pallas::Scalar::from_u64(constants::H as u64);

let base_value = base.generator();
let base_u = base.u();
let scalar_windows_field = scalar.windows_field();
let scalar_windows_usize = scalar.windows_usize();

for (w, k) in scalar_windows_field[1..(scalar_windows_field.len() - 1)]
for (w, (k, k_usize)) in scalar_windows_field[..(scalar_windows_field.len() - 1)]
.iter()
.zip(scalar_windows_usize[..(scalar_windows_field.len() - 1)].iter())
.enumerate()
// Skip k_0 (already processed).
.skip(1)
{
// Offset window index by 1 since we are starting on k_1
let w = w + 1;

// Compute [(k_w + 2) ⋅ 8^w]B
let mul_b = {
let mul_b = k.map(|k| {
base_value * (k + pallas::Scalar::from_u64(2)) * h.pow(&[w as u64, 0, 0, 0])
});
let mul_b = mul_b.map(|mul_b| mul_b.to_affine().coordinates().unwrap());

let x = mul_b.map(|mul_b| *mul_b.x());
let x_cell = region.assign_advice(
|| format!("mul_b_x, window {}", w),
self.x_p,
offset + w,
|| x.ok_or(Error::SynthesisError),
)?;
let x = CellValue::new(x_cell, x);

let y = mul_b.map(|mul_b| *mul_b.y());
let y_cell = region.assign_advice(
|| format!("mul_b_y, window {}", w),
self.y_p,
offset + w,
|| y.ok_or(Error::SynthesisError),
)?;
let y = CellValue::new(y_cell, y);

EccPoint { x, y }
};

// Assign u = (y_p + z_w).sqrt()
let u_val = scalar_windows_usize[w].map(|k| base_u[w].0[k]);
region.assign_advice(
|| "u",
self.u,
offset + w,
|| u_val.ok_or(Error::SynthesisError),
)?;
let mul_b = self.process_window(region, offset, w, *k, *k_usize, base)?;

// Add to the accumulator
acc = self
Expand All @@ -442,9 +412,6 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {
base: OrchardFixedBases,
scalar: &ScalarFixed,
) -> Result<EccPoint, Error> {
// This is 2^w, where w is the window width
let h = pallas::Scalar::from_u64(constants::H as u64);

// Assign u = (y_p + z_w).sqrt() for the most significant window
{
let u_val =
Expand All @@ -459,7 +426,7 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {

// offset_acc = \sum_{j = 0}^{NUM_WINDOWS - 2} 2^{FIXED_BASE_WINDOW_SIZE * j+1}
let offset_acc = (0..(NUM_WINDOWS - 1)).fold(pallas::Scalar::zero(), |acc, w| {
acc + pallas::Scalar::from_u64(2).pow(&[
acc + (*TWO_SCALAR).pow(&[
constants::FIXED_BASE_WINDOW_SIZE as u64 * w as u64 + 1,
0,
0,
Expand All @@ -469,7 +436,7 @@ impl<const NUM_WINDOWS: usize> Config<NUM_WINDOWS> {

// `scalar = [k * 8^84 - offset_acc]`, where `offset_acc = \sum_{j = 0}^{83} 2^{FIXED_BASE_WINDOW_SIZE * j + 1}`.
let scalar = scalar.windows_field()[scalar.windows_field().len() - 1]
.map(|k| k * h.pow(&[(NUM_WINDOWS - 1) as u64, 0, 0, 0]) - offset_acc);
.map(|k| k * (*H_SCALAR).pow(&[(NUM_WINDOWS - 1) as u64, 0, 0, 0]) - offset_acc);

let mul_b = {
let mul_b = scalar.map(|scalar| base.generator() * scalar);
Expand Down Expand Up @@ -545,9 +512,9 @@ impl ScalarFixed {
.map(|idx| {
let z_cur = zs[idx].value();
let z_next = zs[idx + 1].value();
let word = z_cur.zip(z_next).map(|(z_cur, z_next)| {
z_cur - z_next * pallas::Base::from_u64(constants::H as u64)
});
let word = z_cur
.zip(z_next)
.map(|(z_cur, z_next)| z_cur - z_next * *H_BASE);
word.map(|word| pallas::Scalar::from_bytes(&word.to_bytes()).unwrap())
})
.collect::<Vec<_>>()
Expand Down
Loading

0 comments on commit 22ec16f

Please sign in to comment.