mirror of https://github.com/zcash/halo2.git
Merge pull request #113 from zcash/avoid-square-challenges
Avoid square challenges in inner product argument
This commit is contained in:
commit
adf1c2f451
|
@ -16,15 +16,6 @@ pub trait FieldExt:
|
|||
/// Inverse of `ROOT_OF_UNITY`
|
||||
const ROOT_OF_UNITY_INV: Self;
|
||||
|
||||
/// The value $(2^S)^{-1} \mod t$.
|
||||
const UNROLL_T_EXPONENT: [u64; 4];
|
||||
|
||||
/// Represents $t$ where $2^S \cdot t = p - 1$ with $t$ odd.
|
||||
const T_EXPONENT: [u64; 4];
|
||||
|
||||
/// The value $t^{-1} \mod 2^S$.
|
||||
const UNROLL_S_EXPONENT: u64;
|
||||
|
||||
/// Generator of the $t-order$ multiplicative subgroup
|
||||
const DELTA: Self;
|
||||
|
||||
|
@ -67,68 +58,6 @@ pub trait FieldExt:
|
|||
/// byte representation of an integer.
|
||||
fn from_bytes_wide(bytes: &[u8; 64]) -> Self;
|
||||
|
||||
/// Returns a square root of this element, if it exists and this element is
|
||||
/// nonzero. Always returns the same square root, and it is efficient to
|
||||
/// check that it has done so using `extract_radix2_vartime`.
|
||||
fn deterministic_sqrt(&self) -> Option<Self> {
|
||||
let sqrt = self.sqrt();
|
||||
if bool::from(sqrt.is_none()) {
|
||||
return None;
|
||||
}
|
||||
let sqrt = sqrt.unwrap();
|
||||
let extracted = sqrt.extract_radix2_vartime()?;
|
||||
|
||||
if extracted.1 >> (Self::S - 1) == 1 {
|
||||
Some(-sqrt)
|
||||
} else {
|
||||
Some(sqrt)
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns an element $a$ of multiplicative order $t$ together with an
|
||||
/// integer `s` such that `self` is the square of $a \cdot \omega^{s}$ if
|
||||
/// indeed `self` is a square.
|
||||
fn extract_radix2_vartime(&self) -> Option<(Self, u64)> {
|
||||
if bool::from(self.ct_is_zero()) {
|
||||
return None;
|
||||
}
|
||||
|
||||
// TODO: these can probably be simplified
|
||||
let t = self.pow_vartime(&[1 << Self::S, 0, 0, 0]);
|
||||
let t = t.pow_vartime(&Self::UNROLL_T_EXPONENT);
|
||||
let t = t.pow_vartime(&Self::UNROLL_T_EXPONENT);
|
||||
let s = self.pow_vartime(&Self::T_EXPONENT);
|
||||
let mut s = s.pow_vartime(&[Self::UNROLL_S_EXPONENT, 0, 0, 0]);
|
||||
|
||||
let mut m = Self::S;
|
||||
let mut c = Self::ROOT_OF_UNITY_INV;
|
||||
|
||||
let mut extract: u64 = 0;
|
||||
|
||||
let mut cur = 1;
|
||||
while s != Self::one() {
|
||||
let mut i = 1;
|
||||
{
|
||||
let mut s2i = s;
|
||||
s2i = s2i.square();
|
||||
while s2i != Self::one() {
|
||||
i += 1;
|
||||
s2i = s2i.square();
|
||||
}
|
||||
}
|
||||
|
||||
for _ in 0..(m - i) {
|
||||
c = c.square();
|
||||
cur <<= 1;
|
||||
}
|
||||
extract |= cur;
|
||||
s *= c;
|
||||
m = i;
|
||||
}
|
||||
|
||||
Some((t, extract))
|
||||
}
|
||||
|
||||
/// Exponentiates `self` by `by`, where `by` is a little-endian order
|
||||
/// integer exponent.
|
||||
fn pow(&self, by: &[u64; 4]) -> Self {
|
||||
|
|
|
@ -6,21 +6,3 @@ mod fq;
|
|||
|
||||
pub use fp::*;
|
||||
pub use fq::*;
|
||||
|
||||
#[cfg(test)]
|
||||
use ff::{Field, PrimeField};
|
||||
|
||||
#[cfg(test)]
|
||||
use crate::arithmetic::FieldExt;
|
||||
|
||||
#[test]
|
||||
fn test_extract() {
|
||||
let a = Fq::rand();
|
||||
let a = a.square();
|
||||
let (t, s) = a.extract_radix2_vartime().unwrap();
|
||||
assert_eq!(
|
||||
t.pow_vartime(&[1 << Fq::S, 0, 0, 0]) * Fq::ROOT_OF_UNITY.pow_vartime(&[s, 0, 0, 0]),
|
||||
a
|
||||
);
|
||||
assert_eq!(a.deterministic_sqrt().unwrap().square(), a);
|
||||
}
|
||||
|
|
|
@ -643,20 +643,7 @@ impl FieldExt for Fp {
|
|||
0xb4ed8e647196dad1,
|
||||
0x2cd5282c53116b5c,
|
||||
]);
|
||||
const UNROLL_T_EXPONENT: [u64; 4] = [
|
||||
0x955a0a417453113c,
|
||||
0x0000000022016b89,
|
||||
0xc000000000000000,
|
||||
0x3f7ed4c6,
|
||||
];
|
||||
const T_EXPONENT: [u64; 4] = [
|
||||
0x094cf91b992d30ed,
|
||||
0x00000000224698fc,
|
||||
0x0000000000000000,
|
||||
0x40000000,
|
||||
];
|
||||
const DELTA: Self = DELTA;
|
||||
const UNROLL_S_EXPONENT: u64 = 0x204ace5;
|
||||
const TWO_INV: Self = Fp::from_raw([
|
||||
0xcc96987680000001,
|
||||
0x11234c7e04a67c8d,
|
||||
|
@ -791,13 +778,6 @@ fn test_sqrt() {
|
|||
assert!(v == Fp::TWO_INV || (-v) == Fp::TWO_INV);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deterministic_sqrt() {
|
||||
// NB: TWO_INV is standing in as a "random" field element
|
||||
let v = (Fp::TWO_INV).square().deterministic_sqrt().unwrap();
|
||||
assert!(v == Fp::TWO_INV || (-v) == Fp::TWO_INV);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zeta() {
|
||||
assert_eq!(
|
||||
|
|
|
@ -643,20 +643,7 @@ impl FieldExt for Fq {
|
|||
0xf4c8f353124086c1,
|
||||
0x2235e1a7415bf936,
|
||||
]);
|
||||
const UNROLL_T_EXPONENT: [u64; 4] = [
|
||||
0xcc771cc2ac1e1664,
|
||||
0x00000000062dfe9e,
|
||||
0xc000000000000000,
|
||||
0xb89e9c7,
|
||||
];
|
||||
const T_EXPONENT: [u64; 4] = [
|
||||
0x0994a8dd8c46eb21,
|
||||
0x00000000224698fc,
|
||||
0x0000000000000000,
|
||||
0x40000000,
|
||||
];
|
||||
const DELTA: Self = DELTA;
|
||||
const UNROLL_S_EXPONENT: u64 = 0xd1d858e1;
|
||||
const TWO_INV: Self = Fq::from_raw([
|
||||
0xc623759080000001,
|
||||
0x11234c7e04ca546e,
|
||||
|
@ -791,13 +778,6 @@ fn test_sqrt() {
|
|||
assert!(v == Fq::TWO_INV || (-v) == Fq::TWO_INV);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_deterministic_sqrt() {
|
||||
// NB: TWO_INV is standing in as a "random" field element
|
||||
let v = (Fq::TWO_INV).square().deterministic_sqrt().unwrap();
|
||||
assert!(v == Fq::TWO_INV || (-v) == Fq::TWO_INV);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_zeta() {
|
||||
assert_eq!(
|
||||
|
|
|
@ -3,8 +3,8 @@ use ff::Field;
|
|||
use super::super::{Coeff, Polynomial};
|
||||
use super::{Blind, Params};
|
||||
use crate::arithmetic::{
|
||||
best_multiexp, compute_inner_product, eval_polynomial, parallelize, small_multiexp, Curve,
|
||||
CurveAffine, FieldExt,
|
||||
best_multiexp, compute_inner_product, eval_polynomial, parallelize, Curve, CurveAffine,
|
||||
FieldExt,
|
||||
};
|
||||
use crate::transcript::{Challenge, ChallengeScalar, TranscriptWrite};
|
||||
use std::io;
|
||||
|
@ -84,9 +84,8 @@ pub fn create_proof<C: CurveAffine, T: TranscriptWrite<C>>(
|
|||
}
|
||||
}
|
||||
|
||||
// Initialize the vector `G` from the SRS. We'll be progressively
|
||||
// collapsing this vector into smaller and smaller vectors until it is
|
||||
// of length 1.
|
||||
// Initialize the vector `G` from the SRS. We'll be progressively collapsing
|
||||
// this vector into smaller and smaller vectors until it is of length 1.
|
||||
let mut g = params.g.clone();
|
||||
|
||||
// Perform the inner product argument, round by round.
|
||||
|
@ -98,76 +97,42 @@ pub fn create_proof<C: CurveAffine, T: TranscriptWrite<C>>(
|
|||
// TODO: If we modify multiexp to take "extra" bases, we could speed
|
||||
// this piece up a bit by combining the multiexps.
|
||||
metrics::counter!("multiexp", 2, "val" => "l/r", "size" => format!("{}", half));
|
||||
let l = best_multiexp(&a[0..half], &g[half..]);
|
||||
let r = best_multiexp(&a[half..], &g[0..half]);
|
||||
let value_l = compute_inner_product(&a[0..half], &b[half..]);
|
||||
let value_r = compute_inner_product(&a[half..], &b[0..half]);
|
||||
let mut l_randomness = C::Scalar::rand();
|
||||
let l = best_multiexp(&a[half..], &g[0..half]);
|
||||
let r = best_multiexp(&a[0..half], &g[half..]);
|
||||
let value_l = compute_inner_product(&a[half..], &b[0..half]);
|
||||
let value_r = compute_inner_product(&a[0..half], &b[half..]);
|
||||
let l_randomness = C::Scalar::rand();
|
||||
let r_randomness = C::Scalar::rand();
|
||||
metrics::counter!("multiexp", 2, "val" => "l/r", "size" => "2");
|
||||
let l = l + &best_multiexp(&[value_l * &z, l_randomness], &[params.u, params.h]);
|
||||
let r = r + &best_multiexp(&[value_r * &z, r_randomness], &[params.u, params.h]);
|
||||
let mut l = l.to_affine();
|
||||
let l = l.to_affine();
|
||||
let r = r.to_affine();
|
||||
|
||||
let challenge = loop {
|
||||
// We'll fork the transcript and adjust our randomness
|
||||
// until the challenge is a square.
|
||||
let mut transcript = transcript.fork();
|
||||
|
||||
// Feed L and R into the cloned transcript.
|
||||
// We expect these to not be points at infinity due to the randomness.
|
||||
transcript.write_point(l)?;
|
||||
transcript.write_point(r)?;
|
||||
|
||||
// ... and get the squared challenge.
|
||||
let challenge_sq_packed = Challenge::get(&mut transcript);
|
||||
let challenge_sq = *ChallengeScalar::<C, ()>::from(challenge_sq_packed);
|
||||
|
||||
// There might be no square root, in which case we'll fork the
|
||||
// transcript.
|
||||
let challenge = challenge_sq.deterministic_sqrt();
|
||||
if let Some(challenge) = challenge {
|
||||
break challenge;
|
||||
} else {
|
||||
// Try again, with slightly different randomness
|
||||
l = (l + params.h).to_affine();
|
||||
l_randomness += &C::Scalar::one();
|
||||
}
|
||||
};
|
||||
|
||||
// Challenge is unlikely to be zero.
|
||||
let challenge_inv = challenge.invert().unwrap();
|
||||
let challenge_sq_inv = challenge_inv.square();
|
||||
let challenge_sq = challenge.square();
|
||||
|
||||
// Feed L and R into the real transcript
|
||||
transcript.write_point(l)?;
|
||||
transcript.write_point(r)?;
|
||||
|
||||
// And obtain the challenge, even though we already have it, since
|
||||
// squeezing affects the transcript.
|
||||
{
|
||||
let challenge_sq_expected = ChallengeScalar::<_, ()>::get(transcript);
|
||||
assert_eq!(challenge_sq, *challenge_sq_expected);
|
||||
}
|
||||
let challenge_packed = Challenge::get(transcript);
|
||||
let challenge = *ChallengeScalar::<C, ()>::from(challenge_packed);
|
||||
let challenge_inv = challenge.invert().unwrap(); // TODO, bubble this up
|
||||
|
||||
// Collapse `a` and `b`.
|
||||
// TODO: parallelize
|
||||
for i in 0..half {
|
||||
a[i] = (a[i] * &challenge) + &(a[i + half] * &challenge_inv);
|
||||
b[i] = (b[i] * &challenge_inv) + &(b[i + half] * &challenge);
|
||||
a[i] = a[i] + &(a[i + half] * &challenge_inv);
|
||||
b[i] = b[i] + &(b[i + half] * &challenge);
|
||||
}
|
||||
a.truncate(half);
|
||||
b.truncate(half);
|
||||
|
||||
// Collapse `G`
|
||||
parallel_generator_collapse(&mut g, challenge, challenge_inv);
|
||||
parallel_generator_collapse(&mut g, challenge);
|
||||
g.truncate(half);
|
||||
|
||||
// Update randomness (the synthetic blinding factor at the end)
|
||||
blind += &(l_randomness * &challenge_sq);
|
||||
blind += &(r_randomness * &challenge_sq_inv);
|
||||
blind += &(l_randomness * &challenge_inv);
|
||||
blind += &(r_randomness * &challenge);
|
||||
}
|
||||
|
||||
// We have fully collapsed `a`, `b`, `G`
|
||||
|
@ -180,20 +145,16 @@ pub fn create_proof<C: CurveAffine, T: TranscriptWrite<C>>(
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn parallel_generator_collapse<C: CurveAffine>(
|
||||
g: &mut [C],
|
||||
challenge: C::Scalar,
|
||||
challenge_inv: C::Scalar,
|
||||
) {
|
||||
fn parallel_generator_collapse<C: CurveAffine>(g: &mut [C], challenge: C::Scalar) {
|
||||
let len = g.len() / 2;
|
||||
let (mut g_lo, g_hi) = g.split_at_mut(len);
|
||||
metrics::counter!("multiexp", len as u64, "size" => "2", "fn" => "parallel_generator_collapse");
|
||||
metrics::counter!("scalar_multiplication", len as u64, "fn" => "parallel_generator_collapse");
|
||||
|
||||
parallelize(&mut g_lo, |g_lo, start| {
|
||||
let g_hi = &g_hi[start..];
|
||||
let mut tmp = Vec::with_capacity(g_lo.len());
|
||||
for (g_lo, g_hi) in g_lo.iter().zip(g_hi.iter()) {
|
||||
tmp.push(small_multiexp(&[challenge_inv, challenge], &[*g_lo, *g_hi]));
|
||||
tmp.push(g_lo.to_projective() + &(*g_hi * challenge));
|
||||
}
|
||||
C::Projective::batch_to_affine(&tmp, g_lo);
|
||||
});
|
||||
|
|
|
@ -4,16 +4,15 @@ use super::super::Error;
|
|||
use super::{Params, MSM};
|
||||
use crate::transcript::{Challenge, ChallengeScalar, TranscriptRead};
|
||||
|
||||
use crate::arithmetic::{best_multiexp, Curve, CurveAffine, FieldExt};
|
||||
use crate::arithmetic::{best_multiexp, BatchInvert, Curve, CurveAffine};
|
||||
|
||||
/// A guard returned by the verifier
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Guard<'a, C: CurveAffine> {
|
||||
msm: MSM<'a, C>,
|
||||
neg_a: C::Scalar,
|
||||
allinv: C::Scalar,
|
||||
challenges_sq: Vec<C::Scalar>,
|
||||
challenges_sq_packed: Vec<Challenge>,
|
||||
challenges: Vec<C::Scalar>,
|
||||
challenges_packed: Vec<Challenge>,
|
||||
}
|
||||
|
||||
/// An accumulator instance consisting of an evaluation claim and a proof.
|
||||
|
@ -24,14 +23,14 @@ pub struct Accumulator<C: CurveAffine> {
|
|||
|
||||
/// A vector of 128-bit challenges sampled by the verifier, to be used in
|
||||
/// computing g.
|
||||
pub challenges_sq_packed: Vec<Challenge>,
|
||||
pub challenges_packed: Vec<Challenge>,
|
||||
}
|
||||
|
||||
impl<'a, C: CurveAffine> Guard<'a, C> {
|
||||
/// Lets caller supply the challenges and obtain an MSM with updated
|
||||
/// scalars and points.
|
||||
pub fn use_challenges(mut self) -> MSM<'a, C> {
|
||||
let s = compute_s(&self.challenges_sq, self.allinv * &self.neg_a);
|
||||
let s = compute_s(&self.challenges, self.neg_a);
|
||||
self.msm.add_to_g_scalars(&s);
|
||||
self.msm.add_to_h_scalar(self.neg_a);
|
||||
|
||||
|
@ -45,7 +44,7 @@ impl<'a, C: CurveAffine> Guard<'a, C> {
|
|||
|
||||
let accumulator = Accumulator {
|
||||
g,
|
||||
challenges_sq_packed: self.challenges_sq_packed,
|
||||
challenges_packed: self.challenges_packed,
|
||||
};
|
||||
|
||||
(self.msm, accumulator)
|
||||
|
@ -53,7 +52,7 @@ impl<'a, C: CurveAffine> Guard<'a, C> {
|
|||
|
||||
/// Computes G + H, where G = ⟨s, params.g⟩ and H is used for blinding
|
||||
pub fn compute_g(&self) -> C {
|
||||
let s = compute_s(&self.challenges_sq, self.allinv);
|
||||
let s = compute_s(&self.challenges, C::Scalar::one());
|
||||
|
||||
metrics::increment_counter!("multiexp", "size" => format!("{}", s.len()), "fn" => "compute_g");
|
||||
let mut tmp = best_multiexp(&s, &self.msm.params.g);
|
||||
|
@ -84,46 +83,37 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead<C>>(
|
|||
|
||||
let z = *ChallengeScalar::<C, ()>::get(transcript);
|
||||
|
||||
// Data about the challenges from each of the rounds.
|
||||
let mut challenges = Vec::with_capacity(k);
|
||||
let mut challenges_inv = Vec::with_capacity(k);
|
||||
let mut challenges_sq = Vec::with_capacity(k);
|
||||
let mut challenges_sq_packed: Vec<Challenge> = Vec::with_capacity(k);
|
||||
let mut allinv = C::Scalar::one();
|
||||
|
||||
let mut rounds = vec![];
|
||||
for _ in 0..k {
|
||||
// Read L and R from the proof and write them to the transcript
|
||||
let l = transcript.read_point().map_err(|_| Error::OpeningError)?;
|
||||
let r = transcript.read_point().map_err(|_| Error::OpeningError)?;
|
||||
|
||||
let challenge_sq_packed = Challenge::get(transcript);
|
||||
let challenge_sq = *ChallengeScalar::<C, ()>::from(challenge_sq_packed);
|
||||
let challenge_packed = Challenge::get(transcript);
|
||||
let challenge = *ChallengeScalar::<C, ()>::from(challenge_packed);
|
||||
|
||||
let challenge = challenge_sq.deterministic_sqrt();
|
||||
if challenge.is_none() {
|
||||
// We didn't sample a square.
|
||||
return Err(Error::OpeningError);
|
||||
}
|
||||
let challenge = challenge.unwrap();
|
||||
rounds.push((
|
||||
l,
|
||||
r,
|
||||
challenge,
|
||||
/* to be inverted */ challenge,
|
||||
challenge_packed,
|
||||
));
|
||||
}
|
||||
|
||||
let challenge_inv = challenge.invert();
|
||||
if bool::from(challenge_inv.is_none()) {
|
||||
// We sampled zero for some reason, unlikely to happen by
|
||||
// chance.
|
||||
return Err(Error::OpeningError);
|
||||
}
|
||||
let challenge_inv = challenge_inv.unwrap();
|
||||
allinv *= &challenge_inv;
|
||||
rounds
|
||||
.iter_mut()
|
||||
.map(|&mut (_, _, _, ref mut challenge, _)| challenge)
|
||||
.batch_invert();
|
||||
|
||||
let challenge_sq_inv = challenge_inv.square();
|
||||
|
||||
msm.append_term(challenge_sq, l);
|
||||
msm.append_term(challenge_sq_inv, r);
|
||||
let mut challenges = Vec::with_capacity(k);
|
||||
let mut challenges_packed: Vec<Challenge> = Vec::with_capacity(k);
|
||||
for (l, r, challenge, challenge_inv, challenge_packed) in rounds {
|
||||
msm.append_term(challenge_inv, l);
|
||||
msm.append_term(challenge, r);
|
||||
|
||||
challenges.push(challenge);
|
||||
challenges_inv.push(challenge_inv);
|
||||
challenges_sq.push(challenge_sq);
|
||||
challenges_sq_packed.push(challenge_sq_packed);
|
||||
challenges_packed.push(challenge_packed);
|
||||
}
|
||||
|
||||
// Our goal is to open
|
||||
|
@ -142,7 +132,7 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead<C>>(
|
|||
let a = transcript.read_scalar().map_err(|_| Error::SamplingError)?;
|
||||
let neg_a = -a;
|
||||
let h = transcript.read_scalar().map_err(|_| Error::SamplingError)?;
|
||||
let b = compute_b(x, &challenges, &challenges_inv);
|
||||
let b = compute_b(x, &challenges);
|
||||
|
||||
msm.add_to_u_scalar(neg_a * &b * &z);
|
||||
msm.add_to_h_scalar(a - &h);
|
||||
|
@ -150,42 +140,43 @@ pub fn verify_proof<'a, C: CurveAffine, T: TranscriptRead<C>>(
|
|||
let guard = Guard {
|
||||
msm,
|
||||
neg_a,
|
||||
allinv,
|
||||
challenges_sq,
|
||||
challenges_sq_packed,
|
||||
challenges,
|
||||
challenges_packed,
|
||||
};
|
||||
|
||||
Ok(guard)
|
||||
}
|
||||
|
||||
fn compute_b<F: Field>(x: F, challenges: &[F], challenges_inv: &[F]) -> F {
|
||||
assert!(!challenges.is_empty());
|
||||
assert_eq!(challenges.len(), challenges_inv.len());
|
||||
if challenges.len() == 1 {
|
||||
*challenges_inv.last().unwrap() + *challenges.last().unwrap() * x
|
||||
} else {
|
||||
(*challenges_inv.last().unwrap() + *challenges.last().unwrap() * x)
|
||||
* compute_b(
|
||||
x.square(),
|
||||
&challenges[0..(challenges.len() - 1)],
|
||||
&challenges_inv[0..(challenges.len() - 1)],
|
||||
)
|
||||
/// Computes $\prod\limits_{i=0}^{k-1} (1 + u_i x^{2^i})$.
|
||||
fn compute_b<F: Field>(x: F, challenges: &[F]) -> F {
|
||||
let mut tmp = F::one();
|
||||
let mut cur = x;
|
||||
for challenge in challenges.iter().rev() {
|
||||
tmp *= F::one() + &(*challenge * &cur);
|
||||
cur *= cur;
|
||||
}
|
||||
tmp
|
||||
}
|
||||
|
||||
// TODO: parallelize
|
||||
fn compute_s<F: Field>(challenges_sq: &[F], allinv: F) -> Vec<F> {
|
||||
let lg_n = challenges_sq.len();
|
||||
let n = 1 << lg_n;
|
||||
/// Computes the coefficients of $g(X) = \prod\limits_{i=0}^{k-1} (1 + u_i X^{2^i})$.
|
||||
fn compute_s<F: Field>(challenges: &[F], init: F) -> Vec<F> {
|
||||
assert!(challenges.len() > 0);
|
||||
let mut v = vec![F::zero(); 1 << challenges.len()];
|
||||
v[0] = init;
|
||||
|
||||
let mut s = Vec::with_capacity(n);
|
||||
s.push(allinv);
|
||||
for i in 1..n {
|
||||
let lg_i = (32 - 1 - (i as u32).leading_zeros()) as usize;
|
||||
let k = 1 << lg_i;
|
||||
let u_lg_i_sq = challenges_sq[(lg_n - 1) - lg_i];
|
||||
s.push(s[i - k] * u_lg_i_sq);
|
||||
for (len, challenge) in challenges
|
||||
.iter()
|
||||
.rev()
|
||||
.enumerate()
|
||||
.map(|(i, challenge)| (1 << i, challenge))
|
||||
{
|
||||
let (left, right) = v.split_at_mut(len);
|
||||
let right = &mut right[0..len];
|
||||
right.copy_from_slice(&left);
|
||||
for v in right {
|
||||
*v *= challenge;
|
||||
}
|
||||
}
|
||||
|
||||
s
|
||||
v
|
||||
}
|
||||
|
|
|
@ -32,18 +32,11 @@ pub trait TranscriptRead<C: CurveAffine>: Transcript<C> {
|
|||
/// Transcript view from the perspective of a prover that has access to an
|
||||
/// output stream of messages from the prover to the verifier.
|
||||
pub trait TranscriptWrite<C: CurveAffine>: Transcript<C> {
|
||||
/// Forked transcript that does not write to the proof structure.
|
||||
type ForkedTranscript: TranscriptWrite<C>;
|
||||
|
||||
/// Write a curve point to the proof and the transcript.
|
||||
fn write_point(&mut self, point: C) -> io::Result<()>;
|
||||
|
||||
/// Write a scalar to the proof and the transcript.
|
||||
fn write_scalar(&mut self, scalar: C::Scalar) -> io::Result<()>;
|
||||
|
||||
/// Fork the transcript, creating a variant of this `TranscriptWrite` which
|
||||
/// does not output anything to the writer.
|
||||
fn fork(&self) -> Self::ForkedTranscript;
|
||||
}
|
||||
|
||||
/// This is just a simple (and completely broken) transcript reader
|
||||
|
@ -161,8 +154,6 @@ impl<W: Write, C: CurveAffine> DummyHashWrite<W, C> {
|
|||
}
|
||||
|
||||
impl<W: Write, C: CurveAffine> TranscriptWrite<C> for DummyHashWrite<W, C> {
|
||||
type ForkedTranscript = DummyHashWrite<io::Sink, C>;
|
||||
|
||||
fn write_point(&mut self, point: C) -> io::Result<()> {
|
||||
self.common_point(point)?;
|
||||
let compressed = point.to_bytes();
|
||||
|
@ -175,14 +166,6 @@ impl<W: Write, C: CurveAffine> TranscriptWrite<C> for DummyHashWrite<W, C> {
|
|||
let data = scalar.to_bytes();
|
||||
self.writer.write_all(&data[..])
|
||||
}
|
||||
fn fork(&self) -> Self::ForkedTranscript {
|
||||
DummyHashWrite {
|
||||
base_state: self.base_state,
|
||||
scalar_state: self.scalar_state,
|
||||
written_scalar: self.written_scalar,
|
||||
writer: io::sink(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<W: Write, C: CurveAffine> Transcript<C> for DummyHashWrite<W, C> {
|
||||
|
|
Loading…
Reference in New Issue