Skip to content

Commit f9d8cb9

Browse files
committed
VID division working
1 parent 6c1b0db commit f9d8cb9

File tree

1 file changed

+149
-0
lines changed

1 file changed

+149
-0
lines changed

saffron/src/vid.rs

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,59 @@ pub struct VIDProof {
2929
pub opening_proof: OpeningProof<Curve>,
3030
}
3131

32+
/// Divide `self` by the vanishing polynomial for the sub-domain, `X^{domain_size} - coeff`.
33+
pub fn divide_by_sub_vanishing_poly(
34+
poly: &DensePolynomial<ScalarField>,
35+
domain_size: usize,
36+
coeff: ScalarField,
37+
) -> (DensePolynomial<ScalarField>, DensePolynomial<ScalarField>) {
38+
if poly.coeffs.len() < domain_size {
39+
// If degree(poly) < len(Domain), then the quotient is zero, and the entire polynomial is the remainder
40+
(DensePolynomial::<ScalarField>::zero(), poly.clone())
41+
} else {
42+
// Compute the quotient
43+
//
44+
// If `poly.len() <= 2 * domain_size`
45+
// then quotient is simply `poly.coeffs[domain_size..]`
46+
// Otherwise
47+
// during the division by `x^domain_size - 1`, some of `poly.coeffs[domain_size..]` will be updated as well
48+
// which can be computed using the following algorithm.
49+
//
50+
51+
let mut quotient_vec = poly.coeffs[domain_size..].to_vec();
52+
//println!("poly.len(): {:?}", poly.len());
53+
assert!(poly.len() / domain_size <= 2);
54+
for i in 1..(poly.len() / domain_size) {
55+
quotient_vec
56+
.iter_mut()
57+
.zip(&poly.coeffs[domain_size * (i + 1)..])
58+
.for_each(|(s, c)| *s += c * &coeff);
59+
}
60+
61+
// Compute the remainder
62+
//
63+
// `remainder = poly - quotient_vec * (x^domain_size - 1)`
64+
//
65+
// Note that remainder must be smaller than `domain_size`.
66+
// So we can look at only the first `domain_size` terms.
67+
//
68+
// Therefore,
69+
// `remainder = poly.coeffs[0..domain_size] - quotient_vec * (-1)`
70+
// i.e.,
71+
// `remainder = poly.coeffs[0..domain_size] + quotient_vec`
72+
//
73+
let mut remainder_vec = poly.coeffs[0..domain_size].to_vec();
74+
remainder_vec
75+
.iter_mut()
76+
.zip(&quotient_vec)
77+
.for_each(|(s, c)| *s += c * &coeff);
78+
79+
let quotient = DensePolynomial::from_coefficients_vec(quotient_vec);
80+
let remainder = DensePolynomial::from_coefficients_vec(remainder_vec);
81+
(quotient, remainder)
82+
}
83+
}
84+
3285
//pub fn precompute_quotient_helpers_alt(
3386
// srs: &SRS<Curve>,
3487
// domain: EvaluationDomains<ScalarField>,
@@ -564,4 +617,100 @@ mod tests {
564617
);
565618
assert!(res, "proof must verify")
566619
}
620+
621+
#[test]
622+
fn test_vid_poly_div() {
623+
let mut rng = OsRng;
624+
let srs = poly_commitment::precomputed_srs::get_srs_test::<Vesta>();
625+
let domain: EvaluationDomains<ScalarField> =
626+
EvaluationDomains::<ScalarField>::create(srs.size()).unwrap();
627+
628+
let data: Vec<ScalarField> = (0..domain.d2.size)
629+
.map(|_| ScalarField::rand(&mut rng))
630+
.collect();
631+
632+
let data_eval: Evaluations<ScalarField, R2D<ScalarField>> =
633+
Evaluations::from_vec_and_domain(data, domain.d2);
634+
635+
let verifier_ix = 1;
636+
//let per_node_size = 256;
637+
let per_node_size = domain.d1.size();
638+
let proofs_number = domain.d2.size() / per_node_size;
639+
640+
let indices: Vec<usize> = (0..per_node_size)
641+
.map(|j| j * proofs_number + verifier_ix)
642+
.collect();
643+
644+
let numerator_eval: Evaluations<ScalarField, R2D<ScalarField>> = {
645+
let mut res = data_eval.clone();
646+
for i in indices {
647+
res.evals[i] = ScalarField::zero();
648+
}
649+
res
650+
};
651+
652+
let coset_omega = domain
653+
.d2
654+
.group_gen
655+
.pow([(verifier_ix * per_node_size) as u64]);
656+
657+
// X^per_node_size - w^verifier_ix
658+
let divisor = {
659+
let mut res = DensePolynomial {
660+
coeffs: vec![ScalarField::zero(); per_node_size + 1],
661+
};
662+
res[0] = -coset_omega;
663+
//res[0] = -ScalarField::one();
664+
res[per_node_size] = ScalarField::one();
665+
res
666+
};
667+
668+
println!("Numerator eval interpolate");
669+
let numerator_eval_interpolated = numerator_eval.interpolate();
670+
671+
// sanity checking numerator_eval
672+
{
673+
let numerator_1 = DensePolynomial {
674+
coeffs: numerator_eval_interpolated[..per_node_size].to_vec(),
675+
};
676+
let numerator_2 = DensePolynomial {
677+
coeffs: numerator_eval_interpolated[per_node_size..2 * per_node_size].to_vec(),
678+
};
679+
let numerator_3 = DensePolynomial {
680+
coeffs: numerator_eval_interpolated[2 * per_node_size..].to_vec(),
681+
};
682+
683+
for zero_point in (0..per_node_size)
684+
.map(|i| domain.d2.group_gen.pow([i as u64]) * coset_omega)
685+
.take(15)
686+
{
687+
assert!(
688+
numerator_1.evaluate(&zero_point)
689+
+ coset_omega * numerator_2.evaluate(&zero_point)
690+
+ coset_omega * coset_omega * numerator_3.evaluate(&zero_point)
691+
== ScalarField::zero()
692+
);
693+
}
694+
}
695+
696+
println!("Division");
697+
let (quot, rem) =
698+
divide_by_sub_vanishing_poly(&numerator_eval_interpolated, per_node_size, coset_omega);
699+
700+
println!(
701+
"Degree of numerator_eval_interpolated: {:?}",
702+
numerator_eval_interpolated.degree()
703+
);
704+
println!("Degree of divisor: {:?}", divisor.degree());
705+
println!("Degree of quot: {:?}", quot.degree());
706+
707+
let error = &(&quot * &divisor) - &numerator_eval_interpolated;
708+
709+
println!("error degree: {:?}", error.degree());
710+
711+
assert!(&quot * &divisor == numerator_eval_interpolated);
712+
assert!(&quot * &divisor + &rem == numerator_eval_interpolated);
713+
println!("rem degree: {:?}", rem.degree());
714+
assert!(rem.is_zero());
715+
}
567716
}

0 commit comments

Comments
 (0)