44//! a Sigma protocol proving different types of discrete logarithm relations (eg. Schnorr, Pedersen's commitments)
55//! through a group morphism abstraction (see [Maurer09](https://crypto-test.ethz.ch/publications/files/Maurer09.pdf)).
66
7- use crate :: errors:: { Error , InvalidInstance } ;
8- use crate :: linear_relation:: { CanonicalLinearRelation , LinearRelation } ;
7+ use crate :: errors:: Error ;
8+ use crate :: linear_relation:: CanonicalLinearRelation ;
99use crate :: {
1010 serialization:: {
1111 deserialize_elements, deserialize_scalars, serialize_elements, serialize_scalars,
@@ -17,70 +17,9 @@ use ff::Field;
1717use group:: prime:: PrimeGroup ;
1818use rand:: { CryptoRng , Rng , RngCore } ;
1919
20- /// A Schnorr protocol proving knowledge of a witness for a linear group relation.
21- ///
22- /// This implementation generalizes Schnorr’s discrete logarithm proof by using
23- /// a [`LinearRelation`], representing an abstract linear relation over the group.
24- ///
25- /// # Type Parameters
26- /// - `G`: A [`PrimeGroup`] instance.
27- #[ derive( Clone , Default , Debug ) ]
28- pub struct SchnorrProof < G : PrimeGroup > ( pub CanonicalLinearRelation < G > ) ;
29-
30- pub struct ProverState < G : PrimeGroup > ( Vec < G :: Scalar > , Vec < G :: Scalar > ) ;
31-
32- impl < G : PrimeGroup > SchnorrProof < G > {
33- pub fn witness_length ( & self ) -> usize {
34- self . 0 . num_scalars
35- }
36-
37- pub fn commitment_length ( & self ) -> usize {
38- self . 0 . linear_combinations . len ( )
39- }
40-
41- /// Internal method to commit using provided nonces (for deterministic testing)
42- pub fn commit_with_nonces (
43- & self ,
44- witness : & [ G :: Scalar ] ,
45- nonces : & [ G :: Scalar ] ,
46- ) -> Result < ( Vec < G > , ProverState < G > ) , Error > {
47- if witness. len ( ) != self . witness_length ( ) {
48- return Err ( Error :: InvalidInstanceWitnessPair ) ;
49- }
50- if nonces. len ( ) != self . witness_length ( ) {
51- return Err ( Error :: InvalidInstanceWitnessPair ) ;
52- }
53-
54- // If the image is the identity, then the relation must be
55- // trivial, or else the proof will be unsound
56- if self
57- . 0
58- . image
59- . iter ( )
60- . zip ( self . 0 . linear_combinations . iter ( ) )
61- . any ( |( & x, c) | x == G :: identity ( ) && !c. is_empty ( ) )
62- {
63- return Err ( Error :: InvalidInstanceWitnessPair ) ;
64- }
65-
66- let commitment = self . 0 . evaluate ( nonces) ;
67- let prover_state = ProverState ( nonces. to_vec ( ) , witness. to_vec ( ) ) ;
68- Ok ( ( commitment, prover_state) )
69- }
70- }
71-
72- impl < G : PrimeGroup > TryFrom < LinearRelation < G > > for SchnorrProof < G > {
73- type Error = InvalidInstance ;
74-
75- fn try_from ( linear_relation : LinearRelation < G > ) -> Result < Self , Self :: Error > {
76- let canonical_linear_relation = CanonicalLinearRelation :: try_from ( & linear_relation) ?;
77- Ok ( Self ( canonical_linear_relation) )
78- }
79- }
80-
81- impl < G : PrimeGroup > SigmaProtocol for SchnorrProof < G > {
20+ impl < G : PrimeGroup > SigmaProtocol for CanonicalLinearRelation < G > {
8221 type Commitment = Vec < G > ;
83- type ProverState = ProverState < G > ;
22+ type ProverState = ( Vec < G :: Scalar > , Vec < G :: Scalar > ) ;
8423 type Response = Vec < G :: Scalar > ;
8524 type Witness = Vec < G :: Scalar > ;
8625 type Challenge = G :: Scalar ;
@@ -103,26 +42,29 @@ impl<G: PrimeGroup> SigmaProtocol for SchnorrProof<G> {
10342 witness : & Self :: Witness ,
10443 rng : & mut ( impl RngCore + CryptoRng ) ,
10544 ) -> Result < ( Self :: Commitment , Self :: ProverState ) , Error > {
106- if witness. len ( ) != self . witness_length ( ) {
45+ if witness. len ( ) != self . num_scalars {
10746 return Err ( Error :: InvalidInstanceWitnessPair ) ;
10847 }
10948
49+ // TODO: Check this when constructing the CanonicalLinearRelation instead of here.
11050 // If the image is the identity, then the relation must be
11151 // trivial, or else the proof will be unsound
11252 if self
113- . 0
11453 . image
11554 . iter ( )
116- . zip ( self . 0 . linear_combinations . iter ( ) )
55+ . zip ( self . linear_combinations . iter ( ) )
11756 . any ( |( & x, c) | x == G :: identity ( ) && !c. is_empty ( ) )
11857 {
11958 return Err ( Error :: InvalidInstanceWitnessPair ) ;
12059 }
12160
122- let nonces = ( 0 ..self . witness_length ( ) )
61+ let nonces = ( 0 ..self . num_scalars )
12362 . map ( |_| G :: Scalar :: random ( & mut * rng) )
12463 . collect :: < Vec < _ > > ( ) ;
125- self . commit_with_nonces ( witness, & nonces)
64+
65+ let commitment = self . evaluate ( & nonces) ;
66+ let prover_state = ( nonces. to_vec ( ) , witness. to_vec ( ) ) ;
67+ Ok ( ( commitment, prover_state) )
12668 }
12769
12870 /// Computes the prover's response (second message) using the challenge.
@@ -141,7 +83,7 @@ impl<G: PrimeGroup> SigmaProtocol for SchnorrProof<G> {
14183 prover_state : Self :: ProverState ,
14284 challenge : & Self :: Challenge ,
14385 ) -> Result < Self :: Response , Error > {
144- let ProverState ( nonces, witness) = prover_state;
86+ let ( nonces, witness) = prover_state;
14587
14688 let responses = nonces
14789 . into_iter ( )
@@ -172,14 +114,14 @@ impl<G: PrimeGroup> SigmaProtocol for SchnorrProof<G> {
172114 challenge : & Self :: Challenge ,
173115 response : & Self :: Response ,
174116 ) -> Result < ( ) , Error > {
175- if commitment. len ( ) != self . commitment_length ( ) || response. len ( ) != self . witness_length ( ) {
117+ if commitment. len ( ) != self . image . len ( ) || response. len ( ) != self . num_scalars {
176118 return Err ( Error :: InvalidInstanceWitnessPair ) ;
177119 }
178120
179- let lhs = self . 0 . evaluate ( response) ;
121+ let lhs = self . evaluate ( response) ;
180122 let mut rhs = Vec :: new ( ) ;
181123 for ( i, g) in commitment. iter ( ) . enumerate ( ) {
182- rhs. push ( self . 0 . image [ i] * challenge + g) ;
124+ rhs. push ( self . image [ i] * challenge + g) ;
183125 }
184126 if lhs == rhs {
185127 Ok ( ( ) )
@@ -247,7 +189,7 @@ impl<G: PrimeGroup> SigmaProtocol for SchnorrProof<G> {
247189 /// # Errors
248190 /// - Returns [`Error::VerificationFailure`] if the data is malformed or contains an invalid encoding.
249191 fn deserialize_commitment ( & self , data : & [ u8 ] ) -> Result < Self :: Commitment , Error > {
250- deserialize_elements :: < G > ( data, self . commitment_length ( ) ) . ok_or ( Error :: VerificationFailure )
192+ deserialize_elements :: < G > ( data, self . image . len ( ) ) . ok_or ( Error :: VerificationFailure )
251193 }
252194
253195 /// Deserializes a byte slice into a challenge scalar.
@@ -281,19 +223,19 @@ impl<G: PrimeGroup> SigmaProtocol for SchnorrProof<G> {
281223 /// # Errors
282224 /// - Returns [`Error::VerificationFailure`] if the byte data is malformed or the length is incorrect.
283225 fn deserialize_response ( & self , data : & [ u8 ] ) -> Result < Self :: Response , Error > {
284- deserialize_scalars :: < G > ( data, self . witness_length ( ) ) . ok_or ( Error :: VerificationFailure )
226+ deserialize_scalars :: < G > ( data, self . num_scalars ) . ok_or ( Error :: VerificationFailure )
285227 }
286228
287229 fn instance_label ( & self ) -> impl AsRef < [ u8 ] > {
288- self . 0 . label ( )
230+ self . label ( )
289231 }
290232
291233 fn protocol_identifier ( & self ) -> impl AsRef < [ u8 ] > {
292234 b"draft-zkproof-fiat-shamir"
293235 }
294236}
295237
296- impl < G > SigmaProtocolSimulator for SchnorrProof < G >
238+ impl < G > SigmaProtocolSimulator for CanonicalLinearRelation < G >
297239where
298240 G : PrimeGroup ,
299241{
@@ -306,7 +248,7 @@ where
306248 /// # Returns
307249 /// - A commitment and response forming a valid proof for the given challenge.
308250 fn simulate_response < R : Rng + CryptoRng > ( & self , rng : & mut R ) -> Self :: Response {
309- let response: Vec < G :: Scalar > = ( 0 ..self . witness_length ( ) )
251+ let response: Vec < G :: Scalar > = ( 0 ..self . num_scalars )
310252 . map ( |_| G :: Scalar :: random ( & mut * rng) )
311253 . collect ( ) ;
312254 response
@@ -345,16 +287,14 @@ where
345287 challenge : & Self :: Challenge ,
346288 response : & Self :: Response ,
347289 ) -> Result < Self :: Commitment , Error > {
348- if response. len ( ) != self . witness_length ( ) {
290+ if response. len ( ) != self . num_scalars {
349291 return Err ( Error :: InvalidInstanceWitnessPair ) ;
350292 }
351293
352- let response_image = self . 0 . evaluate ( response) ;
353- let image = & self . 0 . image ;
354-
294+ let response_image = self . evaluate ( response) ;
355295 let commitment = response_image
356296 . iter ( )
357- . zip ( image)
297+ . zip ( & self . image )
358298 . map ( |( res, img) | * res - * img * challenge)
359299 . collect :: < Vec < _ > > ( ) ;
360300 Ok ( commitment)
0 commit comments