Skip to content

Commit 9d74e37

Browse files
author
GOURIOU Lénaïck
committed
Add group-specific serialization for Ristretto and BLS12-381
- Introduced GroupSerialization trait to abstract serialization logic - Implemented Ristretto and BLS12-381 (G1Projective) serializers - Integrated into SchnorrProof's serialize/deserialize methods
1 parent fa97cb9 commit 9d74e37

File tree

4 files changed

+102
-26
lines changed

4 files changed

+102
-26
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
use std::convert::TryInto;
2+
3+
use curve25519_dalek::{ristretto::{CompressedRistretto, RistrettoPoint}, scalar::Scalar as RistrettoScalar};
4+
use bls12_381::{G1Affine, G1Projective, Scalar as BlsScalar};
5+
use ff::PrimeField;
6+
use super::r#trait::GroupSerialisation;
7+
8+
pub struct RistrettoSerialisation;
9+
10+
impl GroupSerialisation<RistrettoPoint> for RistrettoSerialisation {
11+
type Scalar = RistrettoScalar;
12+
13+
fn serialize_element(point: &RistrettoPoint) -> Vec<u8> {
14+
point.compress().to_bytes().to_vec()
15+
}
16+
17+
fn deserialize_element(bytes: &[u8]) -> Option<RistrettoPoint> {
18+
let point_size = 32;
19+
if bytes.len() != point_size {
20+
return None;
21+
}
22+
let mut buf = [0u8; 32];
23+
buf.copy_from_slice(bytes);
24+
CompressedRistretto(buf).decompress()
25+
}
26+
27+
fn serialize_scalar(scalar: &Self::Scalar) -> Vec<u8> {
28+
scalar.to_bytes().to_vec()
29+
}
30+
31+
fn deserialize_scalar(bytes: &[u8]) -> Option<Self::Scalar> {
32+
if bytes.len() != 32 {
33+
return None;
34+
}
35+
let mut buf = [0u8; 32];
36+
buf.copy_from_slice(bytes);
37+
RistrettoScalar::from_canonical_bytes(buf).into()
38+
}
39+
}
40+
41+
pub struct Bls12381Serialisation;
42+
43+
impl GroupSerialisation<G1Projective> for Bls12381Serialisation {
44+
type Scalar = BlsScalar;
45+
46+
fn serialize_element(point: &G1Projective) -> Vec<u8> {
47+
let affine = G1Affine::from(point);
48+
affine.to_compressed().as_ref().to_vec()
49+
}
50+
51+
fn deserialize_element(bytes: &[u8]) -> Option<G1Projective> {
52+
if bytes.len() != 48 {
53+
return None;
54+
}
55+
let mut buf = [0u8; 48];
56+
buf.copy_from_slice(bytes);
57+
let affine = G1Affine::from_compressed(&buf).into_option()?;
58+
Some(G1Projective::from(&affine))
59+
}
60+
61+
fn serialize_scalar(scalar: &Self::Scalar) -> Vec<u8> {
62+
scalar.to_repr().as_ref().to_vec()
63+
}
64+
65+
fn deserialize_scalar(bytes: &[u8]) -> Option<Self::Scalar> {
66+
let repr = bytes.try_into().ok()?;
67+
BlsScalar::from_repr(repr).into_option()
68+
}
69+
}

src/toolbox/sigma/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ pub mod group_morphism;
55
pub mod schnorr_proof;
66
/// Defines the transcript for a Sigma Protocol
77
pub mod transcript;
8+
pub mod group_serialisation;
89

910
pub use r#trait::{SigmaProtocol, SigmaProtocolSimulator};
1011
pub use proof_composition::{AndProtocol, OrProtocol};

src/toolbox/sigma/schnorr_proof.rs

Lines changed: 17 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,19 @@ use group::{Group, GroupEncoding};
99
use ff::{PrimeField,Field};
1010
use crate::{toolbox::sigma::{GroupMorphismPreimage, SigmaProtocol}, ProofError};
1111

12+
use super::r#trait::GroupSerialisation;
13+
1214
/// A Schnorr protocol proving knowledge some discrete logarithm relation.
1315
///
1416
/// The specific proof instance is defined by a [`GroupMorphismPreimage`] over a group `G`.
15-
pub struct SchnorrProof<G: Group + GroupEncoding> {
17+
pub struct SchnorrProof<G, S>
18+
where
19+
G: Group + GroupEncoding,
20+
S: GroupSerialisation<G, Scalar = G::Scalar>
21+
{
1622
/// The public instance and its associated group morphism.
1723
pub morphismp: GroupMorphismPreimage<G>,
24+
_marker: std::marker::PhantomData<S>
1825
}
1926

2027
/// Internal prover state during the protocol execution: (random nonce, witness)
@@ -25,10 +32,11 @@ pub struct SchnorrState<S> {
2532
pub witness: Vec<S>,
2633
}
2734

28-
impl<G> SigmaProtocol for SchnorrProof<G>
35+
impl<G, S> SigmaProtocol for SchnorrProof<G,S>
2936
where
3037
G: Group + GroupEncoding,
3138
G::Scalar: Field + Clone,
39+
S: GroupSerialisation<G, Scalar = G::Scalar>
3240
{
3341
type Commitment = Vec<G>;
3442
type ProverState = (Vec<<G as Group>::Scalar>, Vec<<G as Group>::Scalar>);
@@ -97,12 +105,12 @@ where
97105

98106
// Serialize commitments
99107
for commit in commitment.iter().take(point_nb) {
100-
bytes.extend_from_slice(commit.to_bytes().as_ref());
108+
bytes.extend_from_slice(&S::serialize_element(commit));
101109
}
102110

103111
// Serialize responses
104112
for response in response.iter().take(scalar_nb) {
105-
bytes.extend_from_slice(response.to_repr().as_ref());
113+
bytes.extend_from_slice(&S::serialize_scalar(response));
106114
}
107115
bytes
108116
}
@@ -114,6 +122,7 @@ where
114122
{
115123
let scalar_nb = self.morphismp.morphism.num_scalars;
116124
let point_nb = self.morphismp.morphism.num_statements();
125+
117126
let point_size = G::generator().to_bytes().as_ref().len();
118127
let scalar_size = <<G as Group>::Scalar as PrimeField>::Repr::default().as_ref().len();
119128

@@ -129,35 +138,17 @@ where
129138
let start = i * point_size;
130139
let end = start + point_size;
131140

132-
let mut buf = vec![0u8; point_size];
133-
buf.copy_from_slice(&data[start..end]);
134-
135-
let mut repr_array = G::Repr::default();
136-
repr_array.as_mut().copy_from_slice(&buf);
137-
138-
let elem_ct = G::from_bytes(&repr_array);
139-
if !bool::from(elem_ct.is_some()) {
140-
return None;
141-
}
142-
let elem = elem_ct.unwrap();
141+
let slice = &data[start..end];
142+
let elem = S::deserialize_element(slice)?;
143143
commitments.push(elem);
144144
}
145145

146146
for i in 0..scalar_nb {
147147
let start = point_nb * point_size + i * scalar_size;
148148
let end = start + scalar_size;
149149

150-
let mut buf = vec![0u8; scalar_size];
151-
buf.copy_from_slice(&data[start..end]);
152-
153-
let mut repr_array = <<G as Group>::Scalar as PrimeField>::Repr::default();
154-
repr_array.as_mut().copy_from_slice(&buf);
155-
156-
let scalar_ct = G::Scalar::from_repr(repr_array);
157-
if !bool::from(scalar_ct.is_some()) {
158-
return None;
159-
}
160-
let scalar = scalar_ct.unwrap();
150+
let slice = &data[start..end];
151+
let scalar = S::deserialize_scalar(slice)?;
161152
responses.push(scalar);
162153
}
163154

src/toolbox/sigma/trait.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
//!
33
//! This module defines the `SigmaProtocol` trait, a generic interface for 3-message Sigma protocols.
44
5+
use group::Group;
56
use rand::{Rng, CryptoRng};
67
use crate::ProofError;
78

@@ -120,4 +121,18 @@ pub trait SigmaProtocolSimulator: SigmaProtocol {
120121
) -> (Self::Commitment, Self::Challenge, Self::Response) {
121122
panic!("simulatable_transcription not implemented for this protocol")
122123
}
124+
}
125+
126+
pub trait GroupSerialisation<G>
127+
where
128+
G: Group,
129+
{
130+
type Scalar: ff::PrimeField;
131+
132+
fn serialize_element(point: &G) -> Vec<u8>;
133+
fn deserialize_element(bytes: &[u8]) -> Option<G>;
134+
135+
fn serialize_scalar(scalar: &Self::Scalar) -> Vec<u8>;
136+
fn deserialize_scalar(bytes: &[u8]) -> Option<Self::Scalar>;
137+
123138
}

0 commit comments

Comments
 (0)