1use crate::halo2_proofs::{
4 plonk::{self, Any, ConstraintSystem, FirstPhase, SecondPhase, ThirdPhase, VerifyingKey},
5 poly::{self, commitment::Params},
6 transcript::{EncodedChallenge, Transcript},
7};
8use crate::{
9 util::{
10 arithmetic::{root_of_unity, CurveAffine, Domain, PrimeField, Rotation},
11 Itertools,
12 },
13 verifier::plonk::protocol::{
14 CommonPolynomial, Expression, InstanceCommittingKey, PlonkProtocol, Query,
15 QuotientPolynomial,
16 },
17};
18use num_integer::Integer;
19use std::{io, iter, mem::size_of};
20
21pub mod strategy;
22pub mod transcript;
23
24#[derive(Clone, Debug, Default)]
27pub struct Config {
28 zk: bool,
29 query_instance: bool,
30 num_proof: usize,
31 num_instance: Vec<usize>,
32 accumulator_indices: Option<Vec<(usize, usize)>>,
33}
34
35impl Config {
36 pub fn kzg() -> Self {
38 Self { zk: true, query_instance: false, num_proof: 1, ..Default::default() }
39 }
40
41 pub fn ipa() -> Self {
43 Self { zk: true, query_instance: true, num_proof: 1, ..Default::default() }
44 }
45
46 pub fn set_zk(mut self, zk: bool) -> Self {
48 self.zk = zk;
49 self
50 }
51
52 pub fn set_query_instance(mut self, query_instance: bool) -> Self {
54 self.query_instance = query_instance;
55 self
56 }
57
58 pub fn with_num_proof(mut self, num_proof: usize) -> Self {
60 assert!(num_proof > 0);
61 self.num_proof = num_proof;
62 self
63 }
64
65 pub fn with_num_instance(mut self, num_instance: Vec<usize>) -> Self {
67 self.num_instance = num_instance;
68 self
69 }
70
71 pub fn with_accumulator_indices(
73 mut self,
74 accumulator_indices: Option<Vec<(usize, usize)>>,
75 ) -> Self {
76 self.accumulator_indices = accumulator_indices;
77 self
78 }
79}
80
81pub fn compile<'a, C: CurveAffine, P: Params<'a, C>>(
83 params: &P,
84 vk: &VerifyingKey<C>,
85 config: Config,
86) -> PlonkProtocol<C> {
87 assert_eq!(vk.get_domain().k(), params.k());
88
89 let cs = vk.cs();
90 let Config { zk, query_instance, num_proof, num_instance, accumulator_indices } = config;
91
92 let k = params.k() as usize;
93 let domain = Domain::new(k, root_of_unity(k));
94
95 let preprocessed = vk
96 .fixed_commitments()
97 .iter()
98 .chain(vk.permutation().commitments().iter())
99 .cloned()
100 .collect();
101
102 let polynomials = &Polynomials::new(cs, zk, query_instance, num_instance, num_proof);
103
104 let evaluations = iter::empty()
105 .chain((0..num_proof).flat_map(move |t| polynomials.instance_queries(t)))
106 .chain((0..num_proof).flat_map(move |t| polynomials.advice_queries(t)))
107 .chain(polynomials.fixed_queries())
108 .chain(polynomials.random_query())
109 .chain(polynomials.permutation_fixed_queries())
110 .chain((0..num_proof).flat_map(move |t| polynomials.permutation_z_queries::<true>(t)))
111 .chain((0..num_proof).flat_map(move |t| polynomials.lookup_queries::<true>(t)))
112 .collect();
113 let queries = (0..num_proof)
115 .flat_map(|t| {
116 iter::empty()
117 .chain(polynomials.instance_queries(t))
118 .chain(polynomials.advice_queries(t))
119 .chain(polynomials.permutation_z_queries::<false>(t))
120 .chain(polynomials.lookup_queries::<false>(t))
121 })
122 .chain(polynomials.fixed_queries())
123 .chain(polynomials.permutation_fixed_queries())
124 .chain(iter::once(polynomials.quotient_query()))
125 .chain(polynomials.random_query())
126 .collect();
127
128 let transcript_initial_state = transcript_initial_state::<C>(vk);
129
130 let instance_committing_key = query_instance.then(|| {
131 instance_committing_key(
132 params,
133 polynomials.num_instance().into_iter().max().unwrap_or_default(),
134 )
135 });
136
137 let accumulator_indices = accumulator_indices
138 .map(|accumulator_indices| polynomials.accumulator_indices(accumulator_indices))
139 .unwrap_or_default();
140
141 PlonkProtocol {
142 domain,
143 domain_as_witness: None,
144 preprocessed,
145 num_instance: polynomials.num_instance(),
146 num_witness: polynomials.num_witness(),
147 num_challenge: polynomials.num_challenge(),
148 evaluations,
149 queries,
150 quotient: polynomials.quotient(),
151 transcript_initial_state: Some(transcript_initial_state),
152 instance_committing_key,
153 linearization: None,
154 accumulator_indices,
155 }
156}
157
158impl From<poly::Rotation> for Rotation {
159 fn from(rotation: poly::Rotation) -> Rotation {
160 Rotation(rotation.0)
161 }
162}
163
164struct Polynomials<'a, F: PrimeField> {
165 cs: &'a ConstraintSystem<F>,
166 zk: bool,
167 query_instance: bool,
168 num_proof: usize,
169 num_fixed: usize,
170 num_permutation_fixed: usize,
171 num_instance: Vec<usize>,
172 num_advice: Vec<usize>,
173 num_challenge: Vec<usize>,
174 advice_index: Vec<usize>,
175 challenge_index: Vec<usize>,
176 num_lookup_permuted: usize,
177 permutation_chunk_size: usize,
178 num_permutation_z: usize,
179 num_lookup_z: usize,
180}
181
182impl<'a, F: PrimeField> Polynomials<'a, F> {
183 fn new(
184 cs: &'a ConstraintSystem<F>,
185 zk: bool,
186 query_instance: bool,
187 num_instance: Vec<usize>,
188 num_proof: usize,
189 ) -> Self {
190 let degree = if zk { cs.degree() } else { unimplemented!() };
192 let permutation_chunk_size = if zk || cs.permutation().get_columns().len() >= degree {
193 degree - 2
194 } else {
195 degree - 1
196 };
197
198 let num_phase = *cs.advice_column_phase().iter().max().unwrap_or(&0) as usize + 1;
199 let remapping = |phase: Vec<u8>| {
200 let num = phase.iter().fold(vec![0; num_phase], |mut num, phase| {
201 num[*phase as usize] += 1;
202 num
203 });
204 let index = phase
205 .iter()
206 .scan(vec![0; num_phase], |state, phase| {
207 let index = state[*phase as usize];
208 state[*phase as usize] += 1;
209 Some(index)
210 })
211 .collect::<Vec<_>>();
212 (num, index)
213 };
214
215 let (num_advice, advice_index) = remapping(cs.advice_column_phase());
216 let (num_challenge, challenge_index) = remapping(cs.challenge_phase());
217 assert_eq!(num_advice.iter().sum::<usize>(), cs.num_advice_columns());
218 assert_eq!(num_challenge.iter().sum::<usize>(), cs.num_challenges());
219
220 Self {
221 cs,
222 zk,
223 query_instance,
224 num_proof,
225 num_fixed: cs.num_fixed_columns(),
226 num_permutation_fixed: cs.permutation().get_columns().len(),
227 num_instance,
228 num_advice,
229 num_challenge,
230 advice_index,
231 challenge_index,
232 num_lookup_permuted: 2 * cs.lookups().len(),
233 permutation_chunk_size,
234 num_permutation_z: Integer::div_ceil(
235 &cs.permutation().get_columns().len(),
236 &permutation_chunk_size,
237 ),
238 num_lookup_z: cs.lookups().len(),
239 }
240 }
241
242 fn num_preprocessed(&self) -> usize {
243 self.num_fixed + self.num_permutation_fixed
244 }
245
246 fn num_instance(&self) -> Vec<usize> {
247 iter::repeat(self.num_instance.clone()).take(self.num_proof).flatten().collect()
248 }
249
250 fn num_witness(&self) -> Vec<usize> {
251 iter::empty()
252 .chain(self.num_advice.clone().iter().map(|num| self.num_proof * num))
253 .chain([
254 self.num_proof * self.num_lookup_permuted,
255 self.num_proof * (self.num_permutation_z + self.num_lookup_z) + self.zk as usize,
256 ])
257 .collect()
258 }
259
260 fn num_challenge(&self) -> Vec<usize> {
261 let mut num_challenge = self.num_challenge.clone();
262 *num_challenge.last_mut().unwrap() += 1; iter::empty()
264 .chain(num_challenge)
265 .chain([
266 2, 1, ])
269 .collect()
270 }
271
272 fn instance_offset(&self) -> usize {
273 self.num_preprocessed()
274 }
275
276 fn witness_offset(&self) -> usize {
277 self.instance_offset() + self.num_instance().len()
278 }
279
280 fn cs_witness_offset(&self) -> usize {
281 self.witness_offset() + self.num_witness().iter().take(self.num_advice.len()).sum::<usize>()
282 }
283
284 fn query<C: Into<Any> + Copy, R: Into<Rotation>>(
285 &self,
286 column_type: C,
287 mut column_index: usize,
288 rotation: R,
289 t: usize,
290 ) -> Query {
291 let offset = match column_type.into() {
292 Any::Fixed => 0,
293 Any::Instance => self.instance_offset() + t * self.num_instance.len(),
294 Any::Advice(advice) => {
295 column_index = self.advice_index[column_index];
296 let phase_offset = self.num_proof
297 * self.num_advice[..advice.phase() as usize].iter().sum::<usize>();
298 self.witness_offset() + phase_offset + t * self.num_advice[advice.phase() as usize]
299 }
300 };
301 Query::new(offset + column_index, rotation.into())
302 }
303
304 fn instance_queries(&'a self, t: usize) -> impl IntoIterator<Item = Query> + 'a {
305 self.query_instance
306 .then(|| {
307 self.cs.instance_queries().iter().map(move |(column, rotation)| {
308 self.query(*column.column_type(), column.index(), *rotation, t)
309 })
310 })
311 .into_iter()
312 .flatten()
313 }
314
315 fn advice_queries(&'a self, t: usize) -> impl IntoIterator<Item = Query> + 'a {
316 self.cs.advice_queries().iter().map(move |(column, rotation)| {
317 self.query(*column.column_type(), column.index(), *rotation, t)
318 })
319 }
320
321 fn fixed_queries(&'a self) -> impl IntoIterator<Item = Query> + 'a {
322 self.cs.fixed_queries().iter().map(move |(column, rotation)| {
323 self.query(*column.column_type(), column.index(), *rotation, 0)
324 })
325 }
326
327 fn permutation_fixed_queries(&'a self) -> impl IntoIterator<Item = Query> + 'a {
328 (0..self.num_permutation_fixed).map(|i| Query::new(self.num_fixed + i, 0))
329 }
330
331 fn permutation_poly(&'a self, t: usize, i: usize) -> usize {
332 let z_offset = self.cs_witness_offset() + self.num_witness()[self.num_advice.len()];
333 z_offset + t * self.num_permutation_z + i
334 }
335
336 fn permutation_z_queries<const EVAL: bool>(
337 &'a self,
338 t: usize,
339 ) -> impl IntoIterator<Item = Query> + 'a {
340 match (self.zk, EVAL) {
341 (true, true) => (0..self.num_permutation_z)
342 .flat_map(move |i| {
343 let z = self.permutation_poly(t, i);
344 iter::empty().chain([Query::new(z, 0), Query::new(z, 1)]).chain(
345 if i == self.num_permutation_z - 1 {
346 None
347 } else {
348 Some(Query::new(z, self.rotation_last()))
349 },
350 )
351 })
352 .collect_vec(),
353 (true, false) => iter::empty()
354 .chain((0..self.num_permutation_z).flat_map(move |i| {
355 let z = self.permutation_poly(t, i);
356 [Query::new(z, 0), Query::new(z, 1)]
357 }))
358 .chain((0..self.num_permutation_z).rev().skip(1).map(move |i| {
359 let z = self.permutation_poly(t, i);
360 Query::new(z, self.rotation_last())
361 }))
362 .collect_vec(),
363 (false, _) => (0..self.num_permutation_z)
364 .flat_map(move |i| {
365 let z = self.permutation_poly(t, i);
366 [Query::new(z, 0), Query::new(z, 1)]
367 })
368 .collect_vec(),
369 }
370 }
371
372 fn lookup_poly(&'a self, t: usize, i: usize) -> (usize, usize, usize) {
373 let permuted_offset = self.cs_witness_offset();
374 let z_offset = permuted_offset
375 + self.num_witness()[self.num_advice.len()]
376 + self.num_proof * self.num_permutation_z;
377 let z = z_offset + t * self.num_lookup_z + i;
378 let permuted_input = permuted_offset + 2 * (t * self.num_lookup_z + i);
379 let permuted_table = permuted_input + 1;
380 (z, permuted_input, permuted_table)
381 }
382
383 fn lookup_queries<const EVAL: bool>(
384 &'a self,
385 t: usize,
386 ) -> impl IntoIterator<Item = Query> + 'a {
387 (0..self.num_lookup_z).flat_map(move |i| {
388 let (z, permuted_input, permuted_table) = self.lookup_poly(t, i);
389 if EVAL {
390 [
391 Query::new(z, 0),
392 Query::new(z, 1),
393 Query::new(permuted_input, 0),
394 Query::new(permuted_input, -1),
395 Query::new(permuted_table, 0),
396 ]
397 } else {
398 [
399 Query::new(z, 0),
400 Query::new(permuted_input, 0),
401 Query::new(permuted_table, 0),
402 Query::new(permuted_input, -1),
403 Query::new(z, 1),
404 ]
405 }
406 })
407 }
408
409 fn quotient_query(&self) -> Query {
410 Query::new(self.witness_offset() + self.num_witness().iter().sum::<usize>(), 0)
411 }
412
413 fn random_query(&self) -> Option<Query> {
414 self.zk.then(|| {
415 Query::new(self.witness_offset() + self.num_witness().iter().sum::<usize>() - 1, 0)
416 })
417 }
418
419 fn convert(&self, expression: &plonk::Expression<F>, t: usize) -> Expression<F> {
420 expression.evaluate(
421 &|scalar| Expression::Constant(scalar),
422 &|_| unreachable!(),
423 &|query| self.query(Any::Fixed, query.column_index(), query.rotation(), t).into(),
424 &|query| {
425 self.query(
426 match query.phase() {
427 0 => Any::advice_in(FirstPhase),
428 1 => Any::advice_in(SecondPhase),
429 2 => Any::advice_in(ThirdPhase),
430 _ => unreachable!(),
431 },
432 query.column_index(),
433 query.rotation(),
434 t,
435 )
436 .into()
437 },
438 &|query| self.query(Any::Instance, query.column_index(), query.rotation(), t).into(),
439 &|challenge| {
440 let phase_offset =
441 self.num_challenge[..challenge.phase() as usize].iter().sum::<usize>();
442 Expression::Challenge(phase_offset + self.challenge_index[challenge.index()])
443 },
444 &|a| -a,
445 &|a, b| a + b,
446 &|a, b| a * b,
447 &|a, scalar| a * scalar,
448 )
449 }
450
451 fn gate_constraints(&'a self, t: usize) -> impl IntoIterator<Item = Expression<F>> + 'a {
452 self.cs.gates().iter().flat_map(move |gate| {
453 gate.polynomials().iter().map(move |expression| self.convert(expression, t))
454 })
455 }
456
457 fn rotation_last(&self) -> Rotation {
458 Rotation(-((self.cs.blinding_factors() + 1) as i32))
459 }
460
461 fn l_last(&self) -> Expression<F> {
462 if self.zk {
463 Expression::CommonPolynomial(CommonPolynomial::Lagrange(self.rotation_last().0))
464 } else {
465 Expression::CommonPolynomial(CommonPolynomial::Lagrange(-1))
466 }
467 }
468
469 fn l_blind(&self) -> Expression<F> {
470 (self.rotation_last().0 + 1..0)
471 .map(CommonPolynomial::Lagrange)
472 .map(Expression::CommonPolynomial)
473 .sum()
474 }
475
476 fn l_active(&self) -> Expression<F> {
477 Expression::Constant(F::ONE) - self.l_last() - self.l_blind()
478 }
479
480 fn system_challenge_offset(&self) -> usize {
481 self.num_challenge.iter().sum()
482 }
483
484 fn theta(&self) -> Expression<F> {
485 Expression::Challenge(self.system_challenge_offset())
486 }
487
488 fn beta(&self) -> Expression<F> {
489 Expression::Challenge(self.system_challenge_offset() + 1)
490 }
491
492 fn gamma(&self) -> Expression<F> {
493 Expression::Challenge(self.system_challenge_offset() + 2)
494 }
495
496 fn alpha(&self) -> Expression<F> {
497 Expression::Challenge(self.system_challenge_offset() + 3)
498 }
499
500 fn permutation_constraints(&'a self, t: usize) -> impl IntoIterator<Item = Expression<F>> + 'a {
501 let one = &Expression::Constant(F::ONE);
502 let l_0 = &Expression::<F>::CommonPolynomial(CommonPolynomial::Lagrange(0));
503 let l_last = &self.l_last();
504 let l_active = &self.l_active();
505 let identity = &Expression::<F>::CommonPolynomial(CommonPolynomial::Identity);
506 let beta = &self.beta();
507 let gamma = &self.gamma();
508
509 let polys = self
510 .cs
511 .permutation()
512 .get_columns()
513 .iter()
514 .map(|column| self.query(*column.column_type(), column.index(), 0, t))
515 .map(Expression::<F>::Polynomial)
516 .collect_vec();
517 let permutation_fixeds = (0..self.num_permutation_fixed)
518 .map(|i| Query::new(self.num_fixed + i, 0))
519 .map(Expression::<F>::Polynomial)
520 .collect_vec();
521 let zs = (0..self.num_permutation_z)
522 .map(|i| {
523 let z = self.permutation_poly(t, i);
524 (
525 Expression::<F>::Polynomial(Query::new(z, 0)),
526 Expression::<F>::Polynomial(Query::new(z, 1)),
527 Expression::<F>::Polynomial(Query::new(z, self.rotation_last())),
528 )
529 })
530 .collect_vec();
531
532 iter::empty()
533 .chain(zs.first().map(|(z_0, _, _)| l_0 * (one - z_0)))
534 .chain(zs.last().and_then(|(z_l, _, _)| self.zk.then(|| l_last * (z_l * z_l - z_l))))
535 .chain(if self.zk {
536 zs.iter()
537 .skip(1)
538 .zip(zs.iter())
539 .map(|((z, _, _), (_, _, z_prev_last))| l_0 * (z - z_prev_last))
540 .collect_vec()
541 } else {
542 Vec::new()
543 })
544 .chain(
545 zs.iter()
546 .zip(zs.iter().cycle().skip(1))
547 .zip(polys.chunks(self.permutation_chunk_size))
548 .zip(permutation_fixeds.chunks(self.permutation_chunk_size))
549 .enumerate()
550 .map(
551 |(
552 i,
553 ((((z, z_omega, _), (_, z_next_omega, _)), polys), permutation_fixeds),
554 )| {
555 let left = if self.zk || zs.len() == 1 {
556 z_omega.clone()
557 } else {
558 z_omega + l_last * (z_next_omega - z_omega)
559 } * polys
560 .iter()
561 .zip(permutation_fixeds.iter())
562 .map(|(poly, permutation_fixed)| {
563 poly + beta * permutation_fixed + gamma
564 })
565 .reduce(|acc, expr| acc * expr)
566 .unwrap();
567 let right = z * polys
568 .iter()
569 .zip(
570 iter::successors(
571 Some(F::DELTA.pow_vartime([
572 (i * self.permutation_chunk_size) as u64,
573 ])),
574 |delta| Some(F::DELTA * delta),
575 )
576 .map(Expression::Constant),
577 )
578 .map(|(poly, delta)| poly + beta * delta * identity + gamma)
579 .reduce(|acc, expr| acc * expr)
580 .unwrap();
581 if self.zk {
582 l_active * (left - right)
583 } else {
584 left - right
585 }
586 },
587 ),
588 )
589 .collect_vec()
590 }
591
592 fn lookup_constraints(&'a self, t: usize) -> impl IntoIterator<Item = Expression<F>> + 'a {
593 let one = &Expression::Constant(F::ONE);
594 let l_0 = &Expression::<F>::CommonPolynomial(CommonPolynomial::Lagrange(0));
595 let l_last = &self.l_last();
596 let l_active = &self.l_active();
597 let beta = &self.beta();
598 let gamma = &self.gamma();
599
600 let polys = (0..self.num_lookup_z)
601 .map(|i| {
602 let (z, permuted_input, permuted_table) = self.lookup_poly(t, i);
603 (
604 Expression::<F>::Polynomial(Query::new(z, 0)),
605 Expression::<F>::Polynomial(Query::new(z, 1)),
606 Expression::<F>::Polynomial(Query::new(permuted_input, 0)),
607 Expression::<F>::Polynomial(Query::new(permuted_input, -1)),
608 Expression::<F>::Polynomial(Query::new(permuted_table, 0)),
609 )
610 })
611 .collect_vec();
612
613 let compress = |expressions: &'a [plonk::Expression<F>]| {
614 Expression::DistributePowers(
615 expressions.iter().map(|expression| self.convert(expression, t)).collect(),
616 self.theta().into(),
617 )
618 };
619
620 self.cs
621 .lookups()
622 .iter()
623 .zip(polys.iter())
624 .flat_map(
625 |(
626 lookup,
627 (z, z_omega, permuted_input, permuted_input_omega_inv, permuted_table),
628 )| {
629 let input = compress(lookup.input_expressions());
630 let table = compress(lookup.table_expressions());
631 iter::empty()
632 .chain(Some(l_0 * (one - z)))
633 .chain(self.zk.then(|| l_last * (z * z - z)))
634 .chain(Some(if self.zk {
635 l_active
636 * (z_omega * (permuted_input + beta) * (permuted_table + gamma)
637 - z * (input + beta) * (table + gamma))
638 } else {
639 z_omega * (permuted_input + beta) * (permuted_table + gamma)
640 - z * (input + beta) * (table + gamma)
641 }))
642 .chain(self.zk.then(|| l_0 * (permuted_input - permuted_table)))
643 .chain(Some(if self.zk {
644 l_active
645 * (permuted_input - permuted_table)
646 * (permuted_input - permuted_input_omega_inv)
647 } else {
648 (permuted_input - permuted_table)
649 * (permuted_input - permuted_input_omega_inv)
650 }))
651 },
652 )
653 .collect_vec()
654 }
655
656 fn quotient(&self) -> QuotientPolynomial<F> {
657 let constraints = (0..self.num_proof)
658 .flat_map(|t| {
659 iter::empty()
660 .chain(self.gate_constraints(t))
661 .chain(self.permutation_constraints(t))
662 .chain(self.lookup_constraints(t))
663 })
664 .collect_vec();
665 let numerator = Expression::DistributePowers(constraints, self.alpha().into());
666 QuotientPolynomial { chunk_degree: 1, numerator }
667 }
668
669 fn accumulator_indices(
670 &self,
671 accumulator_indices: Vec<(usize, usize)>,
672 ) -> Vec<Vec<(usize, usize)>> {
673 (0..self.num_proof)
674 .map(|t| {
675 accumulator_indices
676 .iter()
677 .cloned()
678 .map(|(poly, row)| (poly + t * self.num_instance.len(), row))
679 .collect()
680 })
681 .collect()
682 }
683}
684
685struct MockChallenge;
686
687impl<C: CurveAffine> EncodedChallenge<C> for MockChallenge {
688 type Input = ();
689
690 fn new(_: &Self::Input) -> Self {
691 unreachable!()
692 }
693
694 fn get_scalar(&self) -> C::Scalar {
695 unreachable!()
696 }
697}
698
699#[derive(Default)]
700struct MockTranscript<F: PrimeField>(F);
701
702impl<C: CurveAffine> Transcript<C, MockChallenge> for MockTranscript<C::Scalar> {
703 fn squeeze_challenge(&mut self) -> MockChallenge {
704 unreachable!()
705 }
706
707 fn common_point(&mut self, _: C) -> io::Result<()> {
708 unreachable!()
709 }
710
711 fn common_scalar(&mut self, scalar: C::Scalar) -> io::Result<()> {
712 self.0 = scalar;
713 Ok(())
714 }
715}
716
717pub fn transcript_initial_state<C: CurveAffine>(vk: &VerifyingKey<C>) -> C::Scalar {
720 let mut transcript = MockTranscript::default();
721 vk.hash_into(&mut transcript).unwrap();
722 transcript.0
723}
724
725fn instance_committing_key<'a, C: CurveAffine, P: Params<'a, C>>(
726 params: &P,
727 len: usize,
728) -> InstanceCommittingKey<C> {
729 let buf = {
730 let mut buf = Vec::new();
731 params.write(&mut buf).unwrap();
732 buf
733 };
734
735 let repr = C::Repr::default();
736 let repr_len = repr.as_ref().len();
737 let offset = size_of::<u32>() + (1 << params.k()) * repr_len;
738
739 let bases = (offset..)
740 .step_by(repr_len)
741 .map(|offset| {
742 let mut repr = C::Repr::default();
743 repr.as_mut().copy_from_slice(&buf[offset..offset + repr_len]);
744 C::from_bytes(&repr).unwrap()
745 })
746 .take(len)
747 .collect();
748
749 let w = {
750 let offset = size_of::<u32>() + (2 << params.k()) * repr_len;
751 let mut repr = C::Repr::default();
752 repr.as_mut().copy_from_slice(&buf[offset..offset + repr_len]);
753 C::from_bytes(&repr).unwrap()
754 };
755
756 InstanceCommittingKey { bases, constant: Some(w) }
757}