@@ -8,11 +8,11 @@ use crate::{
88 homomorphism:: { fixed_base_msms, EntrywiseMap } ,
99 } ,
1010} ;
11- use ark_ec:: CurveGroup ;
11+ use ark_ec:: { pairing :: Pairing , CurveGroup } ;
1212use ark_serialize:: {
1313 CanonicalDeserialize , CanonicalSerialize , Compress , Read , SerializationError , Valid ,
1414} ;
15- pub use ark_std:: io:: Write ;
15+ use ark_std:: io:: Write ;
1616use std:: fmt:: Debug ;
1717
1818/// `TupleHomomorphism` combines two homomorphisms with the same domain
@@ -28,7 +28,7 @@ use std::fmt::Debug;
2828/// In category-theoretic terms, this is the composition of the diagonal map
2929/// `Δ: Domain -> Domain × Domain` with the product map `h1 × h2`.
3030#[ derive( CanonicalSerialize , Debug , Clone , PartialEq , Eq ) ]
31- pub struct TupleHomomorphism < H1 , H2 , const HOMOG : bool >
31+ pub struct TupleHomomorphism < H1 , H2 >
3232where
3333 H1 : homomorphism:: Trait ,
3434 H2 : homomorphism:: Trait < Domain = H1 :: Domain > ,
@@ -37,14 +37,42 @@ where
3737 pub hom2 : H2 ,
3838}
3939
40+ #[ derive( CanonicalSerialize , Debug , Clone , PartialEq , Eq ) ]
41+ pub struct PairingTupleHomomorphism < E , H1 , H2 >
42+ where
43+ E : Pairing ,
44+ H1 : homomorphism:: Trait ,
45+ H2 : homomorphism:: Trait < Domain = H1 :: Domain > ,
46+ {
47+ pub hom1 : H1 ,
48+ pub hom2 : H2 ,
49+ pub _pairing : std:: marker:: PhantomData < E > ,
50+ }
51+
4052/// Implements `Homomorphism` for `TupleHomomorphism` by applying both
4153/// component homomorphisms to the same input and returning their results
4254/// as a tuple.
4355///
4456/// In other words, for input `x: Domain`, this produces
4557/// `(hom1(x), hom2(x))`. For technical reasons, we then put the output inside a wrapper.
46- impl < H1 , H2 , const HOMOG : bool > homomorphism:: Trait for TupleHomomorphism < H1 , H2 , HOMOG >
58+ impl < H1 , H2 > homomorphism:: Trait for TupleHomomorphism < H1 , H2 >
59+ where
60+ H1 : homomorphism:: Trait ,
61+ H2 : homomorphism:: Trait < Domain = H1 :: Domain > ,
62+ H1 :: Codomain : CanonicalSerialize + CanonicalDeserialize ,
63+ H2 :: Codomain : CanonicalSerialize + CanonicalDeserialize ,
64+ {
65+ type Codomain = TupleCodomainShape < H1 :: Codomain , H2 :: Codomain > ;
66+ type Domain = H1 :: Domain ;
67+
68+ fn apply ( & self , x : & Self :: Domain ) -> Self :: Codomain {
69+ TupleCodomainShape ( self . hom1 . apply ( x) , self . hom2 . apply ( x) )
70+ }
71+ }
72+
73+ impl < E , H1 , H2 > homomorphism:: Trait for PairingTupleHomomorphism < E , H1 , H2 >
4774where
75+ E : Pairing ,
4876 H1 : homomorphism:: Trait ,
4977 H2 : homomorphism:: Trait < Domain = H1 :: Domain > ,
5078 H1 :: Codomain : CanonicalSerialize + CanonicalDeserialize ,
@@ -152,7 +180,7 @@ where
152180/// not necessary through enums.
153181///
154182/// The codomain shapes of the two homomorphisms are combined using `TupleCodomainShape`.
155- impl < H1 , H2 > fixed_base_msms:: Trait for TupleHomomorphism < H1 , H2 , true >
183+ impl < H1 , H2 > fixed_base_msms:: Trait for TupleHomomorphism < H1 , H2 >
156184where
157185 H1 : fixed_base_msms:: Trait ,
158186 H2 : fixed_base_msms:: Trait <
@@ -181,7 +209,7 @@ where
181209 }
182210}
183211
184- impl < C : CurveGroup , H1 , H2 > sigma_protocol:: Trait < C > for TupleHomomorphism < H1 , H2 , true >
212+ impl < C : CurveGroup , H1 , H2 > sigma_protocol:: Trait < C > for TupleHomomorphism < H1 , H2 >
185213where
186214 H1 : sigma_protocol:: Trait < C > ,
187215 H2 : sigma_protocol:: Trait < C > ,
@@ -207,3 +235,141 @@ where
207235 dst
208236 }
209237}
238+
239+ use crate :: sigma_protocol:: {
240+ traits:: { fiat_shamir_challenge_for_sigma_protocol, prove_homomorphism, FirstProofItem } ,
241+ Proof , Witness ,
242+ } ;
243+ use anyhow:: ensure;
244+ use aptos_crypto:: utils;
245+ use ark_ff:: { UniformRand , Zero } ;
246+ use serde:: Serialize ;
247+
248+ // Slightly hacky implementation of a sigma protocol
249+ impl < E : Pairing , H1 , H2 > PairingTupleHomomorphism < E , H1 , H2 >
250+ where
251+ H1 : sigma_protocol:: Trait < E :: G1 > ,
252+ H2 : sigma_protocol:: Trait < E :: G2 > ,
253+ H1 : fixed_base_msms:: Trait < Domain : Witness < H1 :: Scalar > > ,
254+ H2 : fixed_base_msms:: Trait < Domain = H1 :: Domain , Scalar = H1 :: Scalar > ,
255+ {
256+ fn dst ( & self ) -> Vec < u8 > {
257+ let mut dst = Vec :: new ( ) ;
258+
259+ let dst1 = self . hom1 . dst ( ) ;
260+ let dst2 = self . hom2 . dst ( ) ;
261+
262+ // Domain-separate them properly so concatenation is unambiguous.
263+ // Prefix with their lengths so [a|b] and [ab|] don't collide.
264+ dst. extend_from_slice ( b"PairingTupleHomomorphism(" ) ;
265+ dst. extend_from_slice ( & ( dst1. len ( ) as u32 ) . to_be_bytes ( ) ) ;
266+ dst. extend_from_slice ( & dst1) ;
267+ dst. extend_from_slice ( & ( dst2. len ( ) as u32 ) . to_be_bytes ( ) ) ;
268+ dst. extend_from_slice ( & dst2) ;
269+ dst. extend_from_slice ( b")" ) ;
270+
271+ dst
272+ }
273+
274+ /// Returns the MSM terms for each homomorphism, combined into a tuple.
275+ fn msm_terms (
276+ & self ,
277+ input : & H1 :: Domain ,
278+ ) -> (
279+ H1 :: CodomainShape < H1 :: MsmInput > ,
280+ H2 :: CodomainShape < H2 :: MsmInput > ,
281+ ) {
282+ let terms1 = self . hom1 . msm_terms ( input) ;
283+ let terms2 = self . hom2 . msm_terms ( input) ;
284+ ( terms1, terms2)
285+ }
286+
287+ pub fn prove < Ct : Serialize , R : rand_core:: RngCore + rand_core:: CryptoRng > (
288+ & self ,
289+ witness : & <Self as homomorphism:: Trait >:: Domain ,
290+ statement : & <Self as homomorphism:: Trait >:: Codomain ,
291+ cntxt : & Ct , // for SoK purposes
292+ rng : & mut R ,
293+ ) -> Proof < H1 :: Scalar , Self > {
294+ prove_homomorphism ( self , witness, statement, cntxt, true , rng, & self . dst ( ) )
295+ }
296+
297+ #[ allow( non_snake_case) ]
298+ pub fn verify < C : Serialize , H > (
299+ & self ,
300+ public_statement : & <Self as homomorphism:: Trait >:: Codomain ,
301+ proof : & Proof < H1 :: Scalar , H > , // Would like to set &Proof<E, Self>, but that ties the lifetime of H to that of Self, but we'd like it to be eg static
302+ cntxt : & C ,
303+ ) -> anyhow:: Result < ( ) >
304+ where
305+ H : homomorphism:: Trait <
306+ Domain = <Self as homomorphism:: Trait >:: Domain ,
307+ Codomain = <Self as homomorphism:: Trait >:: Codomain ,
308+ > ,
309+ {
310+ let ( first_msm_terms, second_msm_terms) =
311+ self . msm_terms_for_verify :: < _ , H > ( public_statement, proof, cntxt) ;
312+
313+ let first_msm_result = H1 :: msm_eval ( first_msm_terms) ;
314+ ensure ! ( first_msm_result == H1 :: MsmOutput :: zero( ) ) ;
315+
316+ let second_msm_result = H2 :: msm_eval ( second_msm_terms) ;
317+ ensure ! ( second_msm_result == H2 :: MsmOutput :: zero( ) ) ;
318+
319+ Ok ( ( ) )
320+ }
321+
322+ #[ allow( non_snake_case) ]
323+ fn msm_terms_for_verify < Ct : Serialize , H > (
324+ & self ,
325+ public_statement : & <Self as homomorphism:: Trait >:: Codomain ,
326+ proof : & Proof < H1 :: Scalar , H > ,
327+ cntxt : & Ct ,
328+ ) -> ( H1 :: MsmInput , H2 :: MsmInput )
329+ where
330+ H : homomorphism:: Trait <
331+ Domain = <Self as homomorphism:: Trait >:: Domain ,
332+ Codomain = <Self as homomorphism:: Trait >:: Codomain ,
333+ > , // need this?
334+ {
335+ let prover_first_message = match & proof. first_proof_item {
336+ FirstProofItem :: Commitment ( A ) => A ,
337+ FirstProofItem :: Challenge ( _) => {
338+ panic ! ( "Missing implementation - expected commitment, not challenge" )
339+ } ,
340+ } ;
341+ let c = fiat_shamir_challenge_for_sigma_protocol :: < _ , H1 :: Scalar , _ > (
342+ cntxt,
343+ self ,
344+ public_statement,
345+ & prover_first_message,
346+ & self . dst ( ) ,
347+ ) ;
348+
349+ let mut rng = ark_std:: rand:: thread_rng ( ) ; // TODO: make this part of the function input?
350+ let beta = H1 :: Scalar :: rand ( & mut rng) ;
351+ let len1 = public_statement. 0 . clone ( ) . into_iter ( ) . count ( ) ; // hmm maybe pass the into_iter version in merge_msm_terms?
352+ let len2 = public_statement. 1 . clone ( ) . into_iter ( ) . count ( ) ;
353+ let powers_of_beta = utils:: powers ( beta, len1 + len2) ;
354+ let ( first_powers_of_beta, second_powers_of_beta) = powers_of_beta. split_at ( len1) ;
355+
356+ let ( first_msm_terms_of_response, second_msm_terms_of_response) = self . msm_terms ( & proof. z ) ;
357+
358+ let first_input = H1 :: merge_msm_terms (
359+ first_msm_terms_of_response. into_iter ( ) . collect ( ) ,
360+ & prover_first_message. 0 ,
361+ & public_statement. 0 ,
362+ first_powers_of_beta,
363+ c,
364+ ) ;
365+ let second_input = H2 :: merge_msm_terms (
366+ second_msm_terms_of_response. into_iter ( ) . collect ( ) ,
367+ & prover_first_message. 1 ,
368+ & public_statement. 1 ,
369+ second_powers_of_beta,
370+ c,
371+ ) ;
372+
373+ ( first_input, second_input)
374+ }
375+ }
0 commit comments