@@ -22,7 +22,9 @@ use ff::{Field, PrimeField};
2222use group:: prime:: PrimeGroup ;
2323use sha3:: Digest ;
2424use sha3:: Sha3_256 ;
25- use subtle:: CtOption ;
25+ use subtle:: Choice ;
26+ use subtle:: ConditionallySelectable ;
27+ use subtle:: ConstantTimeEq ;
2628
2729use crate :: {
2830 codec:: Shake128DuplexSponge ,
@@ -71,17 +73,15 @@ pub enum ComposedCommitment<G: PrimeGroup> {
7173}
7274
7375// Structure representing the ProverState type of Protocol as SigmaProtocol
74- pub enum ComposedProverState < G : PrimeGroup > {
76+ pub enum ComposedProverState < G : PrimeGroup + ConstantTimeEq > {
7577 Simple ( <SchnorrProof < G > as SigmaProtocol >:: ProverState ) ,
7678 And ( Vec < ComposedProverState < G > > ) ,
7779 Or ( ComposedOrProverState < G > ) ,
7880}
7981
80- type ComposedOrProverState < G > = (
81- Vec < Option < ComposedProverState < G > > > ,
82- Vec < Option < ComposedChallenge < G > > > ,
83- Vec < Option < ComposedResponse < G > > > ,
84- ) ;
82+ struct ComposedOrProverState < G : PrimeGroup + ConstantTimeEq > {
83+ prover_states : Vec < ( Choice , ComposedProverState < G > , ComposedChallenge < G > , ComposedResponse < G > ) > ,
84+ }
8585
8686// Structure representing the Response type of Protocol as SigmaProtocol
8787#[ derive( Clone ) ]
@@ -96,7 +96,7 @@ pub enum ComposedResponse<G: PrimeGroup> {
9696pub enum ComposedWitness < G : PrimeGroup > {
9797 Simple ( <SchnorrProof < G > as SigmaProtocol >:: Witness ) ,
9898 And ( Vec < ComposedWitness < G > > ) ,
99- Or ( Vec < CtOption < ComposedWitness < G > > > ) ,
99+ Or ( Vec < ComposedWitness < G > > ) ,
100100}
101101
102102type ComposedChallenge < G > = <SchnorrProof < G > as SigmaProtocol >:: Challenge ;
@@ -105,7 +105,30 @@ const fn composed_challenge_size<G: PrimeGroup>() -> usize {
105105 ( G :: Scalar :: NUM_BITS as usize + 7 ) / 8
106106}
107107
108- impl < G : PrimeGroup > ComposedRelation < G > {
108+
109+ impl < G : PrimeGroup + ConstantTimeEq > ComposedRelation < G > {
110+ fn is_witness_valid ( & self , witness : & ComposedWitness < G > ) -> Choice {
111+ let validity_bit = Choice :: from ( 0 ) ;
112+ match ( self , witness) {
113+ ( ComposedRelation :: Simple ( instance) , ComposedWitness :: Simple ( witness) ) => {
114+ instance. 0 . is_witness_valid ( witness)
115+ }
116+ ( ComposedRelation :: And ( instances) , ComposedWitness :: And ( witnesses) ) => instances
117+ . iter ( )
118+ . zip ( witnesses)
119+ . fold ( Choice :: from ( 0 ) , |bit, ( instance, witness) | {
120+ bit & instance. is_witness_valid ( witness)
121+ } ) ,
122+ ( ComposedRelation :: Or ( instances) , ComposedWitness :: Or ( witnesses) ) => instances
123+ . iter ( )
124+ . zip ( witnesses)
125+ . fold ( Choice :: from ( 0 ) , |bit, ( instance, witness) | {
126+ bit | instance. is_witness_valid ( witness)
127+ } ) ,
128+ _ => unreachable ! ( ) ,
129+ } ;
130+ validity_bit
131+ }
109132 fn prover_commit_simple (
110133 protocol : & SchnorrProof < G > ,
111134 witness : & <SchnorrProof < G > as SigmaProtocol >:: Witness ,
@@ -173,45 +196,43 @@ impl<G: PrimeGroup> ComposedRelation<G> {
173196
174197 fn prover_commit_or (
175198 instances : & [ ComposedRelation < G > ] ,
176- witnesses : & [ CtOption < ComposedWitness < G > > ] ,
199+ witnesses : & [ ComposedWitness < G > ] ,
177200 rng : & mut ( impl rand:: Rng + rand:: CryptoRng ) ,
178201 ) -> Result < ( ComposedCommitment < G > , ComposedProverState < G > ) , Error > {
179202 if instances. len ( ) != witnesses. len ( ) {
180203 return Err ( Error :: InvalidInstanceWitnessPair ) ;
181204 }
182205
183- let mut simulated_challenges = Vec :: new ( ) ;
184- let mut simulated_responses = Vec :: new ( ) ;
185- let mut commitments = Vec :: < ComposedCommitment < G > > :: with_capacity ( instances. len ( ) ) ;
206+ let mut commitments = Vec :: new ( ) ;
186207 let mut prover_states = Vec :: new ( ) ;
187208
188- for ( i, witness) in witnesses. iter ( ) . enumerate ( ) {
189- // let (simulated_commitment, simulated_challenge, simulated_response) = instances[i].simulate_transcript(rng)?;
190- let witness = witness. clone ( ) . into_option ( ) ;
191- match witness {
192- Some ( w) => {
193- let ( commitment, prover_state) = instances[ i] . prover_commit ( & w, rng) ?;
194- commitments. push ( commitment) ;
195- prover_states. push ( Some ( prover_state) ) ;
196- simulated_challenges. push ( None ) ;
197- simulated_responses. push ( None ) ;
198- }
199- None => {
200- let ( simulated_commitment, simulated_challenge, simulated_response) =
201- instances[ i] . simulate_transcript ( rng) ?;
202- commitments. push ( simulated_commitment) ;
203- prover_states. push ( None ) ;
204- simulated_challenges. push ( Some ( simulated_challenge) ) ;
205- simulated_responses. push ( Some ( simulated_response) ) ;
206- }
207- }
209+ for ( i, w) in witnesses. iter ( ) . enumerate ( ) {
210+ let ( commitment, prover_state) = instances[ i] . prover_commit ( & w, rng) ?;
211+ let ( simulated_commitment, simulated_challenge, simulated_response) =
212+ instances[ i] . simulate_transcript ( rng) ?;
213+
214+ let valid_witness = instances[ i] . is_witness_valid ( & w) ;
215+ commitments. push ( if valid_witness. unwrap_u8 ( ) == 1 { commitment } else { simulated_commitment. clone ( ) } ) ;
216+ prover_states. push ( ( valid_witness, prover_state, simulated_challenge, simulated_response) ) ;
217+ }
218+ // check that we have only one witness set
219+ let witnesses_found = prover_states
220+ . iter ( )
221+ . map ( |x| x. 0 . unwrap_u8 ( ) as usize )
222+ . sum :: < usize > ( ) ;
223+ let prover_state =
224+ ComposedOrProverState {
225+ prover_states,
226+ } ;
227+
228+ if witnesses_found > 1 {
229+ return Err ( Error :: InvalidInstanceWitnessPair ) ;
230+ } else {
231+ Ok ( (
232+ ComposedCommitment :: Or ( commitments) ,
233+ ComposedProverState :: Or ( prover_state) ,
234+ ) )
208235 }
209- let prover_state: ComposedOrProverState < G > =
210- ( prover_states, simulated_challenges, simulated_responses) ;
211- Ok ( (
212- ComposedCommitment :: Or ( commitments) ,
213- ComposedProverState :: Or ( prover_state) ,
214- ) )
215236 }
216237
217238 fn prover_response_or (
@@ -222,34 +243,30 @@ impl<G: PrimeGroup> ComposedRelation<G> {
222243 let mut result_challenges = Vec :: with_capacity ( instances. len ( ) ) ;
223244 let mut result_responses = Vec :: with_capacity ( instances. len ( ) ) ;
224245
225- // Calculate the real challenge by subtracting all simulated challenges
226- let ( child_states, simulated_challenges, simulated_responses) = prover_state;
246+ let ComposedOrProverState { prover_states } = prover_state;
227247
228- let real_challenge = challenge - simulated_challenges. iter ( ) . flatten ( ) . sum :: < G :: Scalar > ( ) ;
248+ let mut witness_challenge = challenge;
249+ for ( valid_witness, _prover_state, simulated_challenge, _simulated_response) in & prover_states {
250+ let c = G :: Scalar :: conditional_select ( & G :: Scalar :: ZERO , & simulated_challenge, * valid_witness) ;
251+ witness_challenge -= c;
252+ }
253+ for ( instance, ( valid_witness, prover_state, simulated_challenge, simulated_response) ) in instances. iter ( ) . zip ( prover_states) {
254+ let challenge_i = G :: Scalar :: conditional_select ( & witness_challenge, & simulated_challenge, valid_witness) ;
229255
230- let it = instances
231- . iter ( )
232- . zip ( child_states)
233- . zip ( simulated_challenges)
234- . zip ( simulated_responses) ;
235- for ( ( ( i, prover_state) , simulated_challenge) , simulated_response) in it {
236- if let Some ( state) = prover_state {
237- // Real case: compute response with real challenge
238- let response = i. prover_response ( state, & real_challenge) ?;
239- result_challenges. push ( real_challenge) ;
240- result_responses. push ( response) ;
241- } else {
242- result_challenges. push ( simulated_challenge. unwrap ( ) ) ;
243- result_responses. push ( simulated_response. unwrap ( ) ) ;
244- }
256+ let real_response = instance. prover_response ( prover_state, & challenge_i) ?;
257+
258+ // let response_i = ComposedResponse::conditional_select(&real_response, &simulated_response, *witness_location);
259+ let response_i = if valid_witness. unwrap_u8 ( ) == 1 { real_response } else { simulated_response } ;
260+ result_challenges. push ( challenge_i) ;
261+ result_responses. push ( response_i) ;
245262 }
246- result_challenges. pop ( ) ;
247263
264+ result_challenges. pop ( ) ;
248265 Ok ( ComposedResponse :: Or ( result_challenges, result_responses) )
249266 }
250267}
251268
252- impl < G : PrimeGroup > SigmaProtocol for ComposedRelation < G > {
269+ impl < G : PrimeGroup + ConstantTimeEq > SigmaProtocol for ComposedRelation < G > {
253270 type Commitment = ComposedCommitment < G > ;
254271 type ProverState = ComposedProverState < G > ;
255272 type Response = ComposedResponse < G > ;
@@ -501,7 +518,7 @@ impl<G: PrimeGroup> SigmaProtocol for ComposedRelation<G> {
501518 }
502519}
503520
504- impl < G : PrimeGroup > SigmaProtocolSimulator for ComposedRelation < G > {
521+ impl < G : PrimeGroup + ConstantTimeEq > SigmaProtocolSimulator for ComposedRelation < G > {
505522 fn simulate_commitment (
506523 & self ,
507524 challenge : & Self :: Challenge ,
@@ -606,7 +623,7 @@ impl<G: PrimeGroup> SigmaProtocolSimulator for ComposedRelation<G> {
606623 }
607624}
608625
609- impl < G : PrimeGroup > ComposedRelation < G > {
626+ impl < G : PrimeGroup + ConstantTimeEq > ComposedRelation < G > {
610627 /// Convert this Protocol into a non-interactive zero-knowledge proof
611628 /// using the Shake128DuplexSponge codec and a specified session identifier.
612629 ///
0 commit comments