mirror of https://github.com/zcash/orchard.git
Update window table formula.
Previously, the window table M for fixed-base scalar multiplication computed M[w][k] = [(k+1)*(2^3)^w]B for each window w, where k is a 3-bit chunk in the scalar decomposition in the range [0..8). However, in the case k_0 = 7, k_1= 0, the window table entries would evaluate to: * M[0][k_0] = [(7+1)*(2^3)^0]B = [8]B, * M[1][k_1] = [(0+1)*(2^3)^1]B = [8]B, which means the first addition would require complete addition. To avoid this, we alter the formula to M[w][k] = [(k+2)*(2^3)^w]B. We make a corresponding change to the formula for the last window W. Previously, we had: M[W][k] = [k * (2^3)^W - \sum((2^3)^j)]B, for j in [0..W-1). Now, we have: M[W][k] = [k * (2^3)^W - \sum(2^(3j+1))]B, for j in [0..W-1).
This commit is contained in:
parent
5d57bee562
commit
0636a6f2ec
|
@ -107,14 +107,14 @@ impl<C: CurveAffine> FixedBase<C> for OrchardFixedBase<C> {
|
||||||
let mut window_table: Vec<[C; H]> = Vec::with_capacity(num_windows);
|
let mut window_table: Vec<[C; H]> = Vec::with_capacity(num_windows);
|
||||||
|
|
||||||
// Generate window table entries for all windows but the last.
|
// Generate window table entries for all windows but the last.
|
||||||
// For these first `num_windows - 1` windows, we compute the multiple [(k+1)*(8^w)]B.
|
// For these first `num_windows - 1` windows, we compute the multiple [(k+2)*(2^3)^w]B.
|
||||||
// Here, w ranges from [0..`num_windows - 1`)
|
// Here, w ranges from [0..`num_windows - 1`)
|
||||||
for w in 0..(num_windows - 1) {
|
for w in 0..(num_windows - 1) {
|
||||||
window_table.push(
|
window_table.push(
|
||||||
(0..H)
|
(0..H)
|
||||||
.map(|k| {
|
.map(|k| {
|
||||||
// scalar = (k+1)*(8^w)
|
// scalar = (k+2)*(8^w)
|
||||||
let scalar = C::ScalarExt::from_u64(k as u64 + 1)
|
let scalar = C::ScalarExt::from_u64(k as u64 + 2)
|
||||||
* C::ScalarExt::from_u64(H as u64).pow(&[w as u64, 0, 0, 0]);
|
* C::ScalarExt::from_u64(H as u64).pow(&[w as u64, 0, 0, 0]);
|
||||||
(self.0 * scalar).to_affine()
|
(self.0 * scalar).to_affine()
|
||||||
})
|
})
|
||||||
|
@ -125,15 +125,20 @@ impl<C: CurveAffine> FixedBase<C> for OrchardFixedBase<C> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate window table entries for the last window, w = `num_windows - 1`.
|
// Generate window table entries for the last window, w = `num_windows - 1`.
|
||||||
// For the last window, we compute [k * (8^w) - sum]B, where sum is defined
|
// For the last window, we compute [k * (2^3)^w - sum]B, where sum is defined
|
||||||
// as sum = \sum_{j = 0}^{`num_windows - 2`} 8^j
|
// as sum = \sum_{j = 0}^{`num_windows - 2`} 2^{3j+1}
|
||||||
let sum = (0..(num_windows - 1)).fold(C::ScalarExt::zero(), |acc, w| {
|
let sum = (0..(num_windows - 1)).fold(C::ScalarExt::zero(), |acc, j| {
|
||||||
acc + C::ScalarExt::from_u64(H as u64).pow(&[w as u64, 0, 0, 0])
|
acc + C::ScalarExt::from_u64(2).pow(&[
|
||||||
|
FIXED_BASE_WINDOW_SIZE as u64 * j as u64 + 1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
])
|
||||||
});
|
});
|
||||||
window_table.push(
|
window_table.push(
|
||||||
(0..H)
|
(0..H)
|
||||||
.map(|k| {
|
.map(|k| {
|
||||||
// scalar = k * (8^w) - sum, where w = `num_windows - 1`
|
// scalar = k * (2^3)^w - sum, where w = `num_windows - 1`
|
||||||
let scalar = C::ScalarExt::from_u64(k as u64)
|
let scalar = C::ScalarExt::from_u64(k as u64)
|
||||||
* C::ScalarExt::from_u64(H as u64).pow(&[
|
* C::ScalarExt::from_u64(H as u64).pow(&[
|
||||||
(num_windows - 1) as u64,
|
(num_windows - 1) as u64,
|
||||||
|
@ -218,7 +223,7 @@ trait TestFixedBase<C: CurveAffine> {
|
||||||
// 1. z + y = u^2,
|
// 1. z + y = u^2,
|
||||||
// 2. z - y is not a square
|
// 2. z - y is not a square
|
||||||
// for the y-coordinate of each fixed-base multiple in each window.
|
// for the y-coordinate of each fixed-base multiple in each window.
|
||||||
fn test_z(&self, z: &[u64], u: &[[[u8; 32]; H]], num_windows: usize);
|
fn test_zs_and_us(&self, z: &[u64], u: &[[[u8; 32]; H]], num_windows: usize);
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: CurveAffine> TestFixedBase<C> for OrchardFixedBase<C> {
|
impl<C: CurveAffine> TestFixedBase<C> for OrchardFixedBase<C> {
|
||||||
|
@ -233,9 +238,9 @@ impl<C: CurveAffine> TestFixedBase<C> for OrchardFixedBase<C> {
|
||||||
// Interpolate the x-coordinate using this window's coefficients
|
// Interpolate the x-coordinate using this window's coefficients
|
||||||
let interpolated_x = util::evaluate::<C>(bits, coeffs);
|
let interpolated_x = util::evaluate::<C>(bits, coeffs);
|
||||||
|
|
||||||
// Compute the actual x-coordinate of the multiple [(k+1)*(8^w)]B.
|
// Compute the actual x-coordinate of the multiple [(k+2)*(8^w)]B.
|
||||||
let point = self.0
|
let point = self.0
|
||||||
* C::Scalar::from_u64(bits as u64 + 1)
|
* C::Scalar::from_u64(bits as u64 + 2)
|
||||||
* C::Scalar::from_u64(H as u64).pow(&[idx as u64, 0, 0, 0]);
|
* C::Scalar::from_u64(H as u64).pow(&[idx as u64, 0, 0, 0]);
|
||||||
let x = *point.to_affine().coordinates().unwrap().x();
|
let x = *point.to_affine().coordinates().unwrap().x();
|
||||||
|
|
||||||
|
@ -251,9 +256,14 @@ impl<C: CurveAffine> TestFixedBase<C> for OrchardFixedBase<C> {
|
||||||
let interpolated_x = util::evaluate::<C>(bits, &lagrange_coeffs[num_windows - 1]);
|
let interpolated_x = util::evaluate::<C>(bits, &lagrange_coeffs[num_windows - 1]);
|
||||||
|
|
||||||
// Compute the actual x-coordinate of the multiple [k * (8^84) - offset]B,
|
// Compute the actual x-coordinate of the multiple [k * (8^84) - offset]B,
|
||||||
// where offset = \sum_{j = 0}^{83} 8^j
|
// where offset = \sum_{j = 0}^{83} 2^{3j+1}
|
||||||
let offset = (0..(num_windows - 1)).fold(C::Scalar::zero(), |acc, w| {
|
let offset = (0..(num_windows - 1)).fold(C::Scalar::zero(), |acc, w| {
|
||||||
acc + C::Scalar::from_u64(H as u64).pow(&[w as u64, 0, 0, 0])
|
acc + C::Scalar::from_u64(2).pow(&[
|
||||||
|
FIXED_BASE_WINDOW_SIZE as u64 * w as u64 + 1,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
])
|
||||||
});
|
});
|
||||||
let scalar = C::Scalar::from_u64(bits as u64)
|
let scalar = C::Scalar::from_u64(bits as u64)
|
||||||
* C::Scalar::from_u64(H as u64).pow(&[(num_windows - 1) as u64, 0, 0, 0])
|
* C::Scalar::from_u64(H as u64).pow(&[(num_windows - 1) as u64, 0, 0, 0])
|
||||||
|
@ -266,7 +276,7 @@ impl<C: CurveAffine> TestFixedBase<C> for OrchardFixedBase<C> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn test_z(&self, z: &[u64], u: &[[[u8; 32]; H]], num_windows: usize) {
|
fn test_zs_and_us(&self, z: &[u64], u: &[[[u8; 32]; H]], num_windows: usize) {
|
||||||
let window_table = self.compute_window_table(num_windows);
|
let window_table = self.compute_window_table(num_windows);
|
||||||
|
|
||||||
for ((u, z), window_points) in u.iter().zip(z.iter()).zip(window_table) {
|
for ((u, z), window_points) in u.iter().zip(z.iter()).zip(window_table) {
|
||||||
|
|
|
@ -2958,6 +2958,6 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn z() {
|
fn z() {
|
||||||
let base = super::generator::<pallas::Affine>();
|
let base = super::generator::<pallas::Affine>();
|
||||||
base.0.test_z(&Z, &U, NUM_WINDOWS);
|
base.0.test_zs_and_us(&Z, &U, NUM_WINDOWS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2958,6 +2958,6 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn z() {
|
fn z() {
|
||||||
let base = super::generator::<pallas::Affine>();
|
let base = super::generator::<pallas::Affine>();
|
||||||
base.0.test_z(&Z, &U, NUM_WINDOWS);
|
base.0.test_zs_and_us(&Z, &U, NUM_WINDOWS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2956,6 +2956,6 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn z() {
|
fn z() {
|
||||||
let base = super::generator::<pallas::Affine>();
|
let base = super::generator::<pallas::Affine>();
|
||||||
base.0.test_z(&Z, &U, NUM_WINDOWS);
|
base.0.test_zs_and_us(&Z, &U, NUM_WINDOWS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2958,6 +2958,6 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn z() {
|
fn z() {
|
||||||
let base = super::generator::<pallas::Affine>();
|
let base = super::generator::<pallas::Affine>();
|
||||||
base.0.test_z(&Z, &U, NUM_WINDOWS);
|
base.0.test_zs_and_us(&Z, &U, NUM_WINDOWS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -811,6 +811,6 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn z_short() {
|
fn z_short() {
|
||||||
let base = super::generator::<pallas::Affine>();
|
let base = super::generator::<pallas::Affine>();
|
||||||
base.0.test_z(&Z_SHORT, &U_SHORT, NUM_WINDOWS_SHORT);
|
base.0.test_zs_and_us(&Z_SHORT, &U_SHORT, NUM_WINDOWS_SHORT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue