Skip to content

Commit a1acce9

Browse files
authored
feat(protocol): add generalized Protocol structure with AND/OR compositions (#16)
- feat: define Protocol structure that generalizes SchnorrProtocol through AND/OR compositions - feat: implement sigma protocol traits for the new Protocol structure - test: add example test demonstrating Protocol structure functionality
1 parent 31e4c8f commit a1acce9

14 files changed

+851
-812
lines changed

src/fiat_shamir.rs

Lines changed: 21 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,19 @@
1111
//! This struct is generic over:
1212
//! - `P`: the underlying Sigma protocol ([`SigmaProtocol`] trait).
1313
//! - `C`: the codec ([`Codec`] trait).
14-
//! - `G`: the group used for commitments and operations ([`Group`] trait).
1514
1615
use crate::codec::Codec;
1716
use crate::errors::Error;
1817
use crate::traits::{CompactProtocol, SigmaProtocol};
1918

20-
use group::{Group, GroupEncoding};
2119
use rand::{CryptoRng, RngCore};
2220

21+
pub trait FiatShamir<C: Codec>: SigmaProtocol {
22+
fn push_commitment(&self, codec: &mut C, commitment: &Self::Commitment);
23+
24+
fn get_challenge(&self, codec: &mut C) -> Result<Self::Challenge, Error>;
25+
}
26+
2327
type Transcript<P> = (
2428
<P as SigmaProtocol>::Commitment,
2529
<P as SigmaProtocol>::Challenge,
@@ -37,12 +41,10 @@ type Transcript<P> = (
3741
/// # Type Parameters
3842
/// - `P`: the Sigma protocol implementation.
3943
/// - `C`: the codec used for Fiat-Shamir.
40-
/// - `G`: the group on which the protocol operates.
41-
pub struct NISigmaProtocol<P, C, G>
44+
pub struct NISigmaProtocol<P, C>
4245
where
43-
G: Group + GroupEncoding,
44-
P: SigmaProtocol<Commitment = Vec<G>, Challenge = <G as Group>::Scalar>,
45-
C: Codec<Challenge = <G as Group>::Scalar>,
46+
P: SigmaProtocol<Challenge: PartialEq> + FiatShamir<C>,
47+
C: Codec<Challenge = P::Challenge>,
4648
{
4749
/// Current codec state.
4850
pub hash_state: C,
@@ -51,11 +53,10 @@ where
5153
}
5254

5355
// TODO: Write a serialization of the morphism to the transcript.
54-
impl<P, C, G> NISigmaProtocol<P, C, G>
56+
impl<P, C> NISigmaProtocol<P, C>
5557
where
56-
G: Group + GroupEncoding,
57-
P: SigmaProtocol<Commitment = Vec<G>, Challenge = <G as Group>::Scalar>,
58-
C: Codec<Challenge = <G as Group>::Scalar> + Clone,
58+
P: SigmaProtocol<Challenge: PartialEq> + FiatShamir<C>,
59+
C: Codec<Challenge = P::Challenge> + Clone,
5960
{
6061
/// Constructs a new [`NISigmaProtocol`] instance.
6162
///
@@ -98,13 +99,9 @@ where
9899
let mut codec = self.hash_state.clone();
99100

100101
let (commitment, prover_state) = self.sigmap.prover_commit(witness, rng)?;
101-
// Commitment data for challenge generation
102-
let mut data = Vec::new();
103-
for commit in &commitment {
104-
data.extend_from_slice(commit.to_bytes().as_ref());
105-
}
106102
// Fiat Shamir challenge
107-
let challenge = codec.prover_message(&data).verifier_challenge();
103+
self.sigmap.push_commitment(&mut codec, &commitment);
104+
let challenge = self.sigmap.get_challenge(&mut codec)?;
108105
// Prover's response
109106
let response = self.sigmap.prover_response(prover_state, &challenge)?;
110107
// Local verification of the proof
@@ -135,13 +132,9 @@ where
135132
) -> Result<(), Error> {
136133
let mut codec = self.hash_state.clone();
137134

138-
// Commitment data for expected challenge generation
139-
let mut data = Vec::new();
140-
for commit in commitment {
141-
data.extend_from_slice(commit.to_bytes().as_ref());
142-
}
143135
// Recompute the challenge
144-
let expected_challenge = codec.prover_message(&data).verifier_challenge();
136+
self.sigmap.push_commitment(&mut codec, commitment);
137+
let expected_challenge = self.sigmap.get_challenge(&mut codec)?;
145138
// Verification of the proof
146139
match *challenge == expected_challenge {
147140
true => self.sigmap.verifier(commitment, challenge, response),
@@ -189,23 +182,18 @@ where
189182

190183
let mut codec = self.hash_state.clone();
191184

192-
// Commitment data for expected challenge generation
193-
let mut data = Vec::new();
194-
for commit in &commitment {
195-
data.extend_from_slice(commit.to_bytes().as_ref());
196-
}
197185
// Recompute the challenge
198-
let challenge = codec.prover_message(&data).verifier_challenge();
186+
self.sigmap.push_commitment(&mut codec, &commitment);
187+
let challenge = self.sigmap.get_challenge(&mut codec)?;
199188
// Verification of the proof
200189
self.sigmap.verifier(&commitment, &challenge, &response)
201190
}
202191
}
203192

204-
impl<P, C, G> NISigmaProtocol<P, C, G>
193+
impl<P, C> NISigmaProtocol<P, C>
205194
where
206-
G: Group + GroupEncoding,
207-
P: SigmaProtocol<Commitment = Vec<G>, Challenge = <G as Group>::Scalar> + CompactProtocol,
208-
C: Codec<Challenge = <G as Group>::Scalar> + Clone,
195+
P: SigmaProtocol<Challenge: PartialEq> + CompactProtocol + FiatShamir<C>,
196+
C: Codec<Challenge = P::Challenge> + Clone,
209197
{
210198
/// Generates a compact serialized proof.
211199
///

src/group_morphism.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ impl From<(ScalarVar, GroupVar)> for Term {
6161
/// where `s_i` are scalars (referenced by `scalar_vars`) and `P_i` are group elements (referenced by `element_vars`).
6262
///
6363
/// The indices refer to external lists managed by the containing Morphism.
64+
#[derive(Clone)]
6465
pub struct LinearCombination(Vec<Term>);
6566

6667
impl<T: Into<Term>> From<T> for LinearCombination {
@@ -168,7 +169,7 @@ impl<G: Group> FromIterator<(GroupVar, G)> for GroupMap<G> {
168169
///
169170
/// It supports dynamic allocation of scalars and elements,
170171
/// and evaluates by performing multi-scalar multiplications.
171-
#[derive(Default)]
172+
#[derive(Clone, Default)]
172173
pub struct Morphism<G: Group> {
173174
/// The set of linear combination constraints (equations).
174175
pub constraints: Vec<LinearCombination>,
@@ -259,7 +260,7 @@ impl<G: Group> Morphism<G> {
259260
/// Internally, the constraint system is defined through:
260261
/// - A list of group elements and linear equations (held in the [`Morphism`] field),
261262
/// - A list of [`GroupVar`] indices (`image`) that specify the expected output for each constraint.
262-
#[derive(Default)]
263+
#[derive(Clone, Default)]
263264
pub struct GroupMorphismPreimage<G>
264265
where
265266
G: Group + GroupEncoding,

src/group_serialization.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@ pub fn serialize_element<G: Group + GroupEncoding>(element: &G) -> Vec<u8> {
3030
/// does not represent a valid group element.
3131
pub fn deserialize_element<G: Group + GroupEncoding>(data: &[u8]) -> Result<G, Error> {
3232
let element_len = G::Repr::default().as_ref().len();
33-
if data.len() != element_len {
33+
if data.len() < element_len {
3434
return Err(Error::GroupSerializationFailure);
3535
}
3636

3737
let mut repr = G::Repr::default();
38-
repr.as_mut().copy_from_slice(data);
38+
repr.as_mut().copy_from_slice(&data[..element_len]);
3939
let ct_point = G::from_bytes(&repr);
4040
if ct_point.is_some().into() {
4141
let point = ct_point.unwrap();
@@ -70,13 +70,13 @@ pub fn deserialize_scalar<G: Group>(data: &[u8]) -> Result<G::Scalar, Error> {
7070
let scalar_len = <<G as Group>::Scalar as PrimeField>::Repr::default()
7171
.as_ref()
7272
.len();
73-
if data.len() != scalar_len {
73+
if data.len() < scalar_len {
7474
return Err(Error::GroupSerializationFailure);
7575
}
7676

7777
let mut repr = <<G as Group>::Scalar as PrimeField>::Repr::default();
7878
repr.as_mut().copy_from_slice(&{
79-
let mut tmp = data.to_vec();
79+
let mut tmp = data[..scalar_len].to_vec();
8080
tmp.reverse();
8181
tmp
8282
});

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ pub mod fiat_shamir;
1818
pub mod group_morphism;
1919
pub mod group_serialization;
2020
pub mod proof_builder;
21-
pub mod proof_composition;
21+
pub mod protocol;
2222
pub mod schnorr_protocol;
2323
pub mod traits;
2424

src/proof_builder.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,4 @@ use crate::{codec::ShakeCodec, fiat_shamir::NISigmaProtocol, schnorr_protocol::S
2222
/// - `G`: A group that implements both [`Group`] and [`GroupEncoding`].
2323
///
2424
/// [`GroupMorphismPreimage`]: crate::GroupMorphismPreimage
25-
pub type NISchnorr<G> = NISigmaProtocol<SchnorrProtocol<G>, ShakeCodec<G>, G>;
25+
pub type NISchnorr<G> = NISigmaProtocol<SchnorrProtocol<G>, ShakeCodec<G>>;

0 commit comments

Comments
 (0)