1+ use rand:: Rng ;
2+
13use curve25519_dalek:: ristretto:: RistrettoPoint ;
24use curve25519_dalek:: scalar:: Scalar ;
35use curve25519_dalek:: traits:: Identity ;
6+
47use generators:: GeneratorsView ;
58use inner_product_proof;
69use proof_transcript:: ProofTranscript ;
10+
711use util;
812
913use super :: messages:: * ;
@@ -25,12 +29,30 @@ impl Dealer {
2529 if !m. is_power_of_two ( ) {
2630 return Err ( "m is not valid: must be a power of 2" ) ;
2731 }
32+
33+ // At the end of the protocol, the dealer will attempt to
34+ // verify the proof, and if it fails, determine which party's
35+ // shares were invalid.
36+ //
37+ // However, verifying the proof requires either knowledge of
38+ // all of the challenges, or a copy of the initial transcript
39+ // state.
40+ //
41+ // The dealer has all of the challenges, but using them for
42+ // verification would require duplicating the verification
43+ // logic. Instead, we keep a copy of the initial transcript
44+ // state.
45+ let initial_transcript = transcript. clone ( ) ;
46+
47+ // Commit to aggregation parameters
2848 transcript. commit_u64 ( n as u64 ) ;
2949 transcript. commit_u64 ( m as u64 ) ;
50+
3051 Ok ( DealerAwaitingValueCommitments {
3152 n,
3253 m,
3354 transcript,
55+ initial_transcript,
3456 gens,
3557 } )
3658 }
@@ -42,6 +64,9 @@ pub struct DealerAwaitingValueCommitments<'a, 'b> {
4264 n : usize ,
4365 m : usize ,
4466 transcript : & ' a mut ProofTranscript ,
67+ /// The dealer keeps a copy of the initial transcript state, so
68+ /// that it can attempt to verify the aggregated proof at the end.
69+ initial_transcript : ProofTranscript ,
4570 gens : GeneratorsView < ' b > ,
4671}
4772
@@ -79,6 +104,7 @@ impl<'a, 'b> DealerAwaitingValueCommitments<'a, 'b> {
79104 n : self . n ,
80105 m : self . m ,
81106 transcript : self . transcript ,
107+ initial_transcript : self . initial_transcript ,
82108 gens : self . gens ,
83109 value_challenge : value_challenge. clone ( ) ,
84110 } ,
@@ -91,6 +117,7 @@ pub struct DealerAwaitingPolyCommitments<'a, 'b> {
91117 n : usize ,
92118 m : usize ,
93119 transcript : & ' a mut ProofTranscript ,
120+ initial_transcript : ProofTranscript ,
94121 gens : GeneratorsView < ' b > ,
95122 value_challenge : ValueChallenge ,
96123}
@@ -122,6 +149,7 @@ impl<'a, 'b> DealerAwaitingPolyCommitments<'a, 'b> {
122149 n : self . n ,
123150 m : self . m ,
124151 transcript : self . transcript ,
152+ initial_transcript : self . initial_transcript ,
125153 gens : self . gens ,
126154 value_challenge : self . value_challenge ,
127155 poly_challenge : poly_challenge. clone ( ) ,
@@ -135,31 +163,26 @@ pub struct DealerAwaitingProofShares<'a, 'b> {
135163 n : usize ,
136164 m : usize ,
137165 transcript : & ' a mut ProofTranscript ,
166+ initial_transcript : ProofTranscript ,
138167 gens : GeneratorsView < ' b > ,
139168 value_challenge : ValueChallenge ,
140169 poly_challenge : PolyChallenge ,
141170}
142171
143172impl < ' a , ' b > DealerAwaitingProofShares < ' a , ' b > {
144- pub fn receive_shares (
145- self ,
173+ /// Assembles proof shares into an `AggregatedProof`.
174+ ///
175+ /// Used as a helper function by `receive_trusted_shares` (which
176+ /// just hands back the result) and `receive_shares` (which
177+ /// validates the proof shares.
178+ fn assemble_shares (
179+ & mut self ,
146180 proof_shares : & [ ProofShare ] ,
147- ) -> Result < ( AggregatedProof , Vec < ProofShareVerifier > ) , & ' static str > {
181+ ) -> Result < AggregatedProof , & ' static str > {
148182 if self . m != proof_shares. len ( ) {
149183 return Err ( "Length of proof shares doesn't match expected length m" ) ;
150184 }
151185
152- let mut share_verifiers = Vec :: new ( ) ;
153- for ( j, proof_share) in proof_shares. iter ( ) . enumerate ( ) {
154- share_verifiers. push ( ProofShareVerifier {
155- proof_share : proof_share. clone ( ) ,
156- n : self . n ,
157- j : j,
158- value_challenge : self . value_challenge . clone ( ) ,
159- poly_challenge : self . poly_challenge . clone ( ) ,
160- } ) ;
161- }
162-
163186 let value_commitments = proof_shares
164187 . iter ( )
165188 . map ( |ps| ps. value_commitment . V )
@@ -221,7 +244,7 @@ impl<'a, 'b> DealerAwaitingProofShares<'a, 'b> {
221244 r_vec. clone ( ) ,
222245 ) ;
223246
224- let aggregated_proof = AggregatedProof {
247+ Ok ( AggregatedProof {
225248 n : self . n ,
226249 value_commitments,
227250 A ,
@@ -232,8 +255,59 @@ impl<'a, 'b> DealerAwaitingProofShares<'a, 'b> {
232255 t_x_blinding,
233256 e_blinding,
234257 ipp_proof,
235- } ;
258+ } )
259+ }
260+
261+ /// Assemble the final aggregated proof from the given
262+ /// `proof_shares`, and validate that all input shares and the
263+ /// aggregated proof are well-formed. If the aggregated proof is
264+ /// not well-formed, this function detects which party submitted a
265+ /// malformed share and returns that information as part of the
266+ /// error.
267+ ///
268+ /// XXX define error types so we can surface the blame info
269+ pub fn receive_shares < R : Rng > (
270+ mut self ,
271+ rng : & mut R ,
272+ proof_shares : & [ ProofShare ] ,
273+ ) -> Result < AggregatedProof , & ' static str > {
274+ let proof = self . assemble_shares ( proof_shares) ?;
236275
237- Ok ( ( aggregated_proof, share_verifiers) )
276+ // See comment in `Dealer::new` for why we use `initial_transcript`
277+ if proof. verify ( rng, & mut self . initial_transcript ) . is_ok ( ) {
278+ Ok ( proof)
279+ } else {
280+ // Create a list of bad shares
281+ let mut bad_shares = Vec :: new ( ) ;
282+ for ( j, share) in proof_shares. iter ( ) . enumerate ( ) {
283+ match share. verify_share ( self . n , j, & self . value_challenge , & self . poly_challenge ) {
284+ Ok ( _) => { }
285+ Err ( _) => bad_shares. push ( j) ,
286+ }
287+ }
288+ // XXX pass this upwards
289+ println ! ( "bad shares: {:?}" , bad_shares) ;
290+ Err ( "proof failed to verify" )
291+ }
292+ }
293+
294+ /// Assemble the final aggregated proof from the given
295+ /// `proof_shares`, but does not validate that they are well-formed.
296+ ///
297+ /// ## WARNING
298+ ///
299+ /// This function does **NOT** validate the proof shares. It is
300+ /// suitable for creating aggregated proofs when all parties are
301+ /// known by the dealer to be honest (for instance, when there's
302+ /// only one party playing all roles).
303+ ///
304+ /// Otherwise, use `receive_shares`, which validates that all
305+ /// shares are well-formed, or else detects which party(ies)
306+ /// submitted malformed shares.
307+ pub fn receive_trusted_shares (
308+ mut self ,
309+ proof_shares : & [ ProofShare ] ,
310+ ) -> Result < AggregatedProof , & ' static str > {
311+ self . assemble_shares ( proof_shares)
238312 }
239313}
0 commit comments