lilium_transcript/
transcript_builder.rs1use crate::{
2 messages::PointRound,
3 params::{ParamResolver, ParamStack},
4 protocols::{Protocol, Reduction},
5 Message, Transcript,
6};
7use ark_ff::Field;
8use sponge::sponge::{Duplex, SpongeBuilder};
9use std::any::{Any, TypeId};
10
11pub struct TranscriptBuilder {
12 rounds: Vec<(TypeId, usize)>,
13 vars: usize,
15 sponge_builder: SpongeBuilder,
16 params: ParamStack,
17}
18
19impl TranscriptBuilder {
20 pub fn with_params<F>(mut self, params: ParamResolver, f: F) -> Self
21 where
22 F: Fn(Self) -> Self,
23 {
24 self.params.push(params);
25 let mut builder = f(self);
26 builder.params.pop();
27 builder
28 }
29
30 pub fn add_protocol_patter<F: Field, S: Protocol<F>>(self, key: &S::Key) -> Self {
31 S::transcript_pattern(key, self)
32 }
33
34 pub fn add_reduction_patter<F: Field, S: Reduction<F>>(self, key: &S::Key) -> Self {
35 S::transcript_pattern(key, self)
36 }
37
38 pub fn new(vars: usize, params: ParamResolver) -> Self {
39 let sponge_builder = SpongeBuilder::new();
40 Self {
41 rounds: vec![],
42 vars,
43 sponge_builder,
44 params: ParamStack::new(vec![params]),
45 }
46 }
47
48 pub fn round<F: Field, T: Any + Message<F>, const N: usize>(self) -> Self {
49 let Self {
50 mut rounds,
51 sponge_builder,
52 vars,
53 params,
54 } = self;
55 let id = TypeId::of::<T>();
56 rounds.push((id, N));
57
58 let resolver = params.top();
59 let sponge_builder = sponge_builder
60 .absorb(T::len(vars, resolver).try_into().unwrap())
61 .squeeze(N.try_into().unwrap());
62
63 Self {
64 rounds,
65 sponge_builder,
66 params,
67 ..self
68 }
69 }
70
71 pub fn point(self) -> Self {
72 let Self {
73 mut rounds,
74 vars,
75 sponge_builder,
76 ..
77 } = self;
78 let round = (TypeId::of::<PointRound>(), vars);
79 rounds.push(round);
80 let sponge_builder = sponge_builder.squeeze(vars.try_into().unwrap());
81 Self {
82 rounds,
83 vars,
84 sponge_builder,
85 ..self
86 }
87 }
88
89 fn fold_round_rec<F: Field, T: Any + Message<F>, const N: usize>(self, left: usize) -> Self {
90 if left == 0 {
91 self
92 } else {
93 let builder = self.round::<F, T, N>();
94 builder.fold_round_rec::<F, T, N>(left - 1)
95 }
96 }
97
98 pub fn fold_rounds<F: Field, T: Any + Message<F>, const N: usize>(self) -> Self {
101 let vars = self.vars;
102 self.fold_round_rec::<F, T, N>(vars)
103 }
104
105 pub fn finish<F: Field, S: Duplex<F>>(self) -> TranscriptDescriptor<F, S> {
106 let Self {
107 rounds,
108 sponge_builder,
109 vars,
110 ..
111 } = self;
112 let sponge = S::from_builder(sponge_builder);
113 TranscriptDescriptor {
114 sponge,
115 rounds,
116 vars,
117 }
118 }
119
120 pub fn repeat<const N: usize, M: Fn(Self, usize) -> Self>(self, f: M) -> Self {
121 (0..N).fold(self, f)
122 }
123}
124
125pub struct TranscriptDescriptor<F: Field, S: Duplex<F>> {
126 sponge: S::Initializer,
127 rounds: Vec<(TypeId, usize)>,
128 vars: usize,
129}
130
131impl<F: Field, S: Duplex<F>> TranscriptDescriptor<F, S> {
132 pub fn instanciate(&self) -> Transcript<F, S> {
133 let sponge = S::instanciate(&self.sponge);
134 let rounds = self.rounds.clone().into_iter();
135 Transcript::new(sponge, rounds, self.vars)
136 }
137}