@@ -51,7 +51,7 @@ pub enum ComposedRelation<G: PrimeGroup> {
5151 Or ( Vec < ComposedRelation < G > > ) ,
5252}
5353
54- impl < G : PrimeGroup + ConstantTimeEq > ComposedRelation < G > {
54+ impl < G : PrimeGroup + ConstantTimeEq + ConditionallySelectable > ComposedRelation < G > {
5555 /// Create a [ComposedRelation] for an AND relation from the given list of relations.
5656 pub fn and < T : Into < ComposedRelation < G > > > ( witness : impl IntoIterator < Item = T > ) -> Self {
5757 Self :: And ( witness. into_iter ( ) . map ( |x| x. into ( ) ) . collect ( ) )
@@ -85,6 +85,49 @@ pub enum ComposedCommitment<G: PrimeGroup> {
8585 Or ( Vec < ComposedCommitment < G > > ) ,
8686}
8787
88+ impl < G : PrimeGroup > ComposedCommitment < G >
89+ where
90+ G : ConditionallySelectable ,
91+ {
92+ /// Conditionally select between two ComposedCommitment values.
93+ /// This function performs constant-time selection of the commitment values.
94+ pub fn conditional_select ( a : & Self , b : & Self , choice : Choice ) -> Self {
95+ match ( a, b) {
96+ ( ComposedCommitment :: Simple ( a_elements) , ComposedCommitment :: Simple ( b_elements) ) => {
97+ // Both vectors must have the same length for this to work
98+ debug_assert_eq ! ( a_elements. len( ) , b_elements. len( ) ) ;
99+ let selected: Vec < G > = a_elements
100+ . iter ( )
101+ . zip ( b_elements. iter ( ) )
102+ . map ( |( a, b) | G :: conditional_select ( a, b, choice) )
103+ . collect ( ) ;
104+ ComposedCommitment :: Simple ( selected)
105+ }
106+ ( ComposedCommitment :: And ( a_commitments) , ComposedCommitment :: And ( b_commitments) ) => {
107+ debug_assert_eq ! ( a_commitments. len( ) , b_commitments. len( ) ) ;
108+ let selected: Vec < ComposedCommitment < G > > = a_commitments
109+ . iter ( )
110+ . zip ( b_commitments. iter ( ) )
111+ . map ( |( a, b) | ComposedCommitment :: conditional_select ( a, b, choice) )
112+ . collect ( ) ;
113+ ComposedCommitment :: And ( selected)
114+ }
115+ ( ComposedCommitment :: Or ( a_commitments) , ComposedCommitment :: Or ( b_commitments) ) => {
116+ debug_assert_eq ! ( a_commitments. len( ) , b_commitments. len( ) ) ;
117+ let selected: Vec < ComposedCommitment < G > > = a_commitments
118+ . iter ( )
119+ . zip ( b_commitments. iter ( ) )
120+ . map ( |( a, b) | ComposedCommitment :: conditional_select ( a, b, choice) )
121+ . collect ( ) ;
122+ ComposedCommitment :: Or ( selected)
123+ }
124+ _ => {
125+ unreachable ! ( "Mismatched ComposedCommitment variants in conditional_select" ) ;
126+ }
127+ }
128+ }
129+ }
130+
88131// Structure representing the ProverState type of Protocol as SigmaProtocol
89132pub enum ComposedProverState < G : PrimeGroup + ConstantTimeEq > {
90133 Simple ( <CanonicalLinearRelation < G > as SigmaProtocol >:: ProverState ) ,
@@ -108,6 +151,58 @@ pub enum ComposedResponse<G: PrimeGroup> {
108151 Or ( Vec < ComposedChallenge < G > > , Vec < ComposedResponse < G > > ) ,
109152}
110153
154+ impl < G : PrimeGroup > ComposedResponse < G > {
155+ /// Conditionally select between two ComposedResponse values.
156+ /// This function performs constant-time selection of the response values.
157+ pub fn conditional_select ( a : & Self , b : & Self , choice : Choice ) -> Self {
158+ match ( a, b) {
159+ ( ComposedResponse :: Simple ( a_scalars) , ComposedResponse :: Simple ( b_scalars) ) => {
160+ // Both vectors must have the same length for this to work
161+ debug_assert_eq ! ( a_scalars. len( ) , b_scalars. len( ) ) ;
162+ let selected: Vec < G :: Scalar > = a_scalars
163+ . iter ( )
164+ . zip ( b_scalars. iter ( ) )
165+ . map ( |( a, b) | G :: Scalar :: conditional_select ( a, b, choice) )
166+ . collect ( ) ;
167+ ComposedResponse :: Simple ( selected)
168+ }
169+ ( ComposedResponse :: And ( a_responses) , ComposedResponse :: And ( b_responses) ) => {
170+ debug_assert_eq ! ( a_responses. len( ) , b_responses. len( ) ) ;
171+ let selected: Vec < ComposedResponse < G > > = a_responses
172+ . iter ( )
173+ . zip ( b_responses. iter ( ) )
174+ . map ( |( a, b) | ComposedResponse :: conditional_select ( a, b, choice) )
175+ . collect ( ) ;
176+ ComposedResponse :: And ( selected)
177+ }
178+ (
179+ ComposedResponse :: Or ( a_challenges, a_responses) ,
180+ ComposedResponse :: Or ( b_challenges, b_responses) ,
181+ ) => {
182+ debug_assert_eq ! ( a_challenges. len( ) , b_challenges. len( ) ) ;
183+ debug_assert_eq ! ( a_responses. len( ) , b_responses. len( ) ) ;
184+
185+ let selected_challenges: Vec < ComposedChallenge < G > > = a_challenges
186+ . iter ( )
187+ . zip ( b_challenges. iter ( ) )
188+ . map ( |( a, b) | G :: Scalar :: conditional_select ( a, b, choice) )
189+ . collect ( ) ;
190+
191+ let selected_responses: Vec < ComposedResponse < G > > = a_responses
192+ . iter ( )
193+ . zip ( b_responses. iter ( ) )
194+ . map ( |( a, b) | ComposedResponse :: conditional_select ( a, b, choice) )
195+ . collect ( ) ;
196+
197+ ComposedResponse :: Or ( selected_challenges, selected_responses)
198+ }
199+ _ => {
200+ unreachable ! ( "Mismatched ComposedResponse variants in conditional_select" ) ;
201+ }
202+ }
203+ }
204+ }
205+
111206// Structure representing the Witness type of Protocol as SigmaProtocol
112207#[ derive( Clone ) ]
113208pub enum ComposedWitness < G : PrimeGroup > {
@@ -142,7 +237,7 @@ const fn composed_challenge_size<G: PrimeGroup>() -> usize {
142237 ( G :: Scalar :: NUM_BITS as usize ) . div_ceil ( 8 )
143238}
144239
145- impl < G : PrimeGroup + ConstantTimeEq > ComposedRelation < G > {
240+ impl < G : PrimeGroup + ConstantTimeEq + ConditionallySelectable > ComposedRelation < G > {
146241 fn is_witness_valid ( & self , witness : & ComposedWitness < G > ) -> Choice {
147242 match ( self , witness) {
148243 ( ComposedRelation :: Simple ( instance) , ComposedWitness :: Simple ( witness) ) => {
@@ -233,7 +328,10 @@ impl<G: PrimeGroup + ConstantTimeEq> ComposedRelation<G> {
233328 instances : & [ ComposedRelation < G > ] ,
234329 witnesses : & [ ComposedWitness < G > ] ,
235330 rng : & mut ( impl Rng + CryptoRng ) ,
236- ) -> Result < ( ComposedCommitment < G > , ComposedProverState < G > ) , Error > {
331+ ) -> Result < ( ComposedCommitment < G > , ComposedProverState < G > ) , Error >
332+ where
333+ G : ConditionallySelectable ,
334+ {
237335 if instances. len ( ) != witnesses. len ( ) {
238336 return Err ( Error :: InvalidInstanceWitnessPair ) ;
239337 }
@@ -248,28 +346,16 @@ impl<G: PrimeGroup + ConstantTimeEq> ComposedRelation<G> {
248346 let ( simulated_commitment, simulated_challenge, simulated_response) =
249347 instances[ i] . simulate_transcript ( rng) ?;
250348
251- let valid_witness = instances[ i] . is_witness_valid ( w) ;
252- let select_witness = valid_witness & !valid_witness_found;
253-
254- let simulated_commitment_ptr =
255- & simulated_commitment as * const ComposedCommitment < G > as u64 ;
256- let commitment_ptr = & commitment as * const ComposedCommitment < G > as u64 ;
349+ let valid_witness = instances[ i] . is_witness_valid ( w) & !valid_witness_found;
350+ let select_witness = valid_witness;
257351
258- let selected_commitment_ptr = ConditionallySelectable :: conditional_select (
259- & simulated_commitment_ptr ,
260- & commitment_ptr ,
352+ let commitment = ComposedCommitment :: conditional_select (
353+ & simulated_commitment ,
354+ & commitment ,
261355 select_witness,
262356 ) ;
263- let discarded_commitment_ptr = ConditionallySelectable :: conditional_select (
264- & simulated_commitment_ptr,
265- & commitment_ptr,
266- !select_witness,
267- ) ;
268- let commitment = unsafe { & * ( selected_commitment_ptr as * const ComposedCommitment < G > ) } ;
269- let _discarded =
270- unsafe { & * ( discarded_commitment_ptr as * const ComposedCommitment < G > ) } ;
271357
272- commitments. push ( commitment. clone ( ) ) ;
358+ commitments. push ( commitment) ;
273359 prover_states. push ( ComposedOrProverStateEntry (
274360 select_witness,
275361 prover_state,
@@ -330,21 +416,8 @@ impl<G: PrimeGroup + ConstantTimeEq> ComposedRelation<G> {
330416 ) ;
331417
332418 let response = instance. prover_response ( prover_state, & challenge_i) ?;
333- let response_ptr = & response as * const ComposedResponse < G > as u64 ;
334- let simulated_response_ptr = & simulated_response as * const ComposedResponse < G > as u64 ;
335- let selected_response_ptr = ConditionallySelectable :: conditional_select (
336- & simulated_response_ptr,
337- & response_ptr,
338- valid_witness,
339- ) ;
340- let _discarded_response_ptr = ConditionallySelectable :: conditional_select (
341- & simulated_response_ptr,
342- & response_ptr,
343- !valid_witness,
344- ) ;
345- let response = unsafe { & * ( selected_response_ptr as * const ComposedResponse < G > ) } ;
346- let _discarded_response =
347- unsafe { & * ( _discarded_response_ptr as * const ComposedResponse < G > ) } ;
419+ let response =
420+ ComposedResponse :: conditional_select ( & simulated_response, & response, valid_witness) ;
348421
349422 result_challenges. push ( challenge_i) ;
350423 result_responses. push ( response. clone ( ) ) ;
@@ -355,7 +428,9 @@ impl<G: PrimeGroup + ConstantTimeEq> ComposedRelation<G> {
355428 }
356429}
357430
358- impl < G : PrimeGroup + ConstantTimeEq > SigmaProtocol for ComposedRelation < G > {
431+ impl < G : PrimeGroup + ConstantTimeEq + ConditionallySelectable > SigmaProtocol
432+ for ComposedRelation < G >
433+ {
359434 type Commitment = ComposedCommitment < G > ;
360435 type ProverState = ComposedProverState < G > ;
361436 type Response = ComposedResponse < G > ;
@@ -607,7 +682,9 @@ impl<G: PrimeGroup + ConstantTimeEq> SigmaProtocol for ComposedRelation<G> {
607682 }
608683}
609684
610- impl < G : PrimeGroup + ConstantTimeEq > SigmaProtocolSimulator for ComposedRelation < G > {
685+ impl < G : PrimeGroup + ConstantTimeEq + ConditionallySelectable > SigmaProtocolSimulator
686+ for ComposedRelation < G >
687+ {
611688 fn simulate_commitment (
612689 & self ,
613690 challenge : & Self :: Challenge ,
@@ -712,7 +789,7 @@ impl<G: PrimeGroup + ConstantTimeEq> SigmaProtocolSimulator for ComposedRelation
712789 }
713790}
714791
715- impl < G : PrimeGroup + ConstantTimeEq > ComposedRelation < G > {
792+ impl < G : PrimeGroup + ConstantTimeEq + ConditionallySelectable > ComposedRelation < G > {
716793 /// Convert this Protocol into a non-interactive zero-knowledge proof
717794 /// using the Shake128DuplexSponge codec and a specified session identifier.
718795 ///
0 commit comments