reverie/transcript/
prover.rs

1use std::any::type_name;
2use std::convert::TryFrom;
3use std::mem;
4
5use num_traits::Zero;
6
7use super::*;
8use crate::algebra::{Hashable, Pack, PackSelected};
9use crate::crypto::hash::PackedHasher;
10use crate::generator::ShareGen;
11use crate::proof::{OpenOnline, OpenPreprocessing};
12
13pub struct ProverTranscript<D: Domain, I: Iterator<Item = D::Recon>> {
14    // original un-expanded seeds
15    // (used to extract proof at the end)
16    seeds: [[u8; KEY_SIZE]; PACKED],
17
18    //
19    witness: I,
20
21    // used to generate fresh shares
22    share_gen: Box<ShareGen<D>>,
23
24    // transcript hashes
25    hash_online: PackedHasher,
26    hash_preprocess: PackedHasher,
27
28    // recorded corrections/reconstructions/masked inputs
29    reconstructions: Vec<D::Share>,
30    corrections: Vec<D::Recon>,
31    inputs: Vec<D::Recon>,
32}
33
34impl<D: Domain, I: Iterator<Item = D::Recon>> ProverTranscript<D, I> {
35    pub fn new(
36        witness: I,           // iterator over
37        seeds: [Key; PACKED], // seeds for each packed repetition
38    ) -> Self {
39        Self {
40            seeds,
41            share_gen: share_gen_from_rep_seeds(&seeds),
42            witness,
43            hash_online: PackedHasher::new(),
44            hash_preprocess: PackedHasher::new(),
45            reconstructions: vec![],
46            corrections: vec![],
47            inputs: vec![],
48        }
49    }
50
51    /// Extracts proofs from transcript
52    ///
53    /// # Arguments
54    ///
55    /// - 'players': The players to omit from the online execution.
56    ///              If players[i] == PLAYERS, the preprocessing is opened instead.
57    pub(crate) fn extract(
58        self,                     // consumes the transcript
59        players: [usize; PACKED], // the online players to omit.
60    ) -> (Vec<OpenOnline>, Vec<OpenPreprocessing>) {
61        let mut dst_recon: [Vec<u8>; PACKED] = [
62            vec![],
63            vec![],
64            vec![],
65            vec![],
66            vec![],
67            vec![],
68            vec![],
69            vec![],
70        ];
71
72        let mut dst_corr: [Vec<u8>; PACKED] = [
73            vec![],
74            vec![],
75            vec![],
76            vec![],
77            vec![],
78            vec![],
79            vec![],
80            vec![],
81        ];
82
83        let mut dst_input: [Vec<u8>; PACKED] = [
84            vec![],
85            vec![],
86            vec![],
87            vec![],
88            vec![],
89            vec![],
90            vec![],
91            vec![],
92        ];
93
94        let selected: Vec<bool> = players.iter().copied().map(|i| i < PLAYERS).collect();
95
96        // pack reconstruction shares of omitted player
97        D::Share::pack_selected(&mut dst_recon, &self.reconstructions[..], players);
98
99        // pack corrections
100        D::Recon::pack(
101            &mut dst_corr,
102            &self.corrections[..],
103            <&[bool; PACKED]>::try_from(&selected[..]).unwrap(),
104        );
105
106        // pack masked inputs
107        D::Recon::pack(
108            &mut dst_input,
109            &self.inputs[..],
110            <&[bool; PACKED]>::try_from(&selected[..]).unwrap(),
111        );
112
113        // open
114        let mut open_preprocessing: Vec<OpenPreprocessing> = vec![];
115        let mut open_online: Vec<OpenOnline> = vec![];
116        for rep in 0..PACKED {
117            let omit = players[rep];
118            debug_assert!(omit <= PLAYERS);
119            if omit < PLAYERS {
120                // fetch the packed corrections
121                let corrs = mem::take(&mut dst_corr[rep]);
122                let recons = mem::take(&mut dst_recon[rep]);
123                let inputs = mem::take(&mut dst_input[rep]);
124
125                // remove seed of unopened player
126                let mut seeds = expand_seed(self.seeds[rep]);
127                seeds[omit] = [0u8; KEY_SIZE];
128
129                // append to opening
130                open_online.push(OpenOnline {
131                    omit: omit as u8,
132                    recons,
133                    corrs,
134                    inputs,
135                    seeds,
136                })
137            } else {
138                debug_assert_eq!(omit, PLAYERS);
139                debug_assert_eq!(
140                    dst_corr[rep].len(),
141                    0,
142                    "rep = {}, players = {:?}, {:?}",
143                    rep,
144                    &players,
145                    &dst_corr
146                );
147
148                debug_assert_eq!(
149                    dst_recon[rep].len(),
150                    0,
151                    "rep = {}, players = {:?}, domain = {}, {:?}",
152                    rep,
153                    &players,
154                    type_name::<D>(),
155                    &dst_recon
156                );
157
158                debug_assert_eq!(
159                    dst_input[rep].len(),
160                    0,
161                    "rep = {}, players = {:?}, {:?}",
162                    rep,
163                    &players,
164                    &dst_input
165                );
166
167                open_preprocessing.push(OpenPreprocessing {
168                    comm_online: self.hash_online[rep].finalize().into(),
169                    seed: self.seeds[rep],
170                })
171            }
172        }
173
174        (open_online, open_preprocessing)
175    }
176}
177
178impl<D: Domain, I: Iterator<Item = D::Recon>> Transcript<D> for ProverTranscript<D, I> {
179    const IS_PROVER: bool = true;
180
181    fn input(&mut self) -> Wire<D> {
182        // generate fresh share
183        let mask = self.share_gen.next();
184
185        // reconstruct mask
186        let lambda = D::reconstruct(&mask);
187
188        // fetch next input and compute "correction"
189        // st. mask + corr = input, i.e. (mask || corr) is a sharing of input.
190        let input = self.witness.next().expect("witness is too short");
191        let corr = input - lambda;
192
193        // commit to input
194        corr.hash(&mut self.hash_online);
195
196        // save masked input for proof extraction
197        self.inputs.push(corr);
198        Wire { mask, corr }
199    }
200
201    fn online_hash(&self) -> [Hash; PACKED] {
202        self.hash_online.finalize()
203    }
204
205    fn preprocess_hash(&self) -> [Hash; PACKED] {
206        self.hash_preprocess.finalize()
207    }
208
209    fn reconstruct(&mut self, mask: D::Share) -> D::Recon {
210        mask.hash(&mut self.hash_online);
211        self.reconstructions.push(mask);
212        D::reconstruct(&mask)
213    }
214
215    fn correction(&mut self, corr: D::Recon) -> D::Recon {
216        corr.hash(&mut self.hash_preprocess);
217        self.corrections.push(corr);
218        corr
219    }
220
221    fn zero_check(&mut self, recon: D::Recon) {
222        // TODO: create a useful trace for the user
223        assert!(
224            recon.is_zero(),
225            "witness is invalid!. Wire has value {:?}, expected zero.",
226            recon
227        );
228    }
229
230    fn new_mask(&mut self) -> D::Share {
231        self.share_gen.next()
232    }
233}