Skip to content

Commit 6be467f

Browse files
authored
wip: nonlinear relation handling in SchnorrProof (#63)
1 parent 31a6e7a commit 6be467f

File tree

3 files changed

+129
-18
lines changed

3 files changed

+129
-18
lines changed

src/schnorr_protocol.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,11 +147,13 @@ where
147147
}
148148

149149
let lhs = self.0.linear_map.evaluate(response)?;
150+
let zero_vec = vec![<<G as Group>::Scalar as Field>::ZERO; self.0.linear_map.num_scalars];
151+
let zero_image = self.0.linear_map.evaluate(&zero_vec)?;
150152
let mut rhs = Vec::new();
151153
for (i, g) in commitment.iter().enumerate() {
152154
rhs.push({
153155
let image_var = self.0.image[i];
154-
self.0.linear_map.group_elements.get(image_var)? * challenge + g
156+
(self.0.linear_map.group_elements.get(image_var)? - zero_image[i]) * challenge + g
155157
});
156158
}
157159
if lhs == rhs {
@@ -322,13 +324,16 @@ where
322324
return Err(Error::InvalidInstanceWitnessPair);
323325
}
324326

327+
let zero_vec = vec![<<G as Group>::Scalar as Field>::ZERO; self.0.linear_map.num_scalars];
328+
let zero_image = self.0.linear_map.evaluate(&zero_vec)?;
325329
let response_image = self.0.linear_map.evaluate(response)?;
326330
let image = self.0.image()?;
327331

328332
let commitment = response_image
329333
.iter()
330334
.zip(&image)
331-
.map(|(res, img)| *res - *img * challenge)
335+
.zip(&zero_image)
336+
.map(|((res, img), z_img)| *res - (*img - *z_img) * challenge)
332337
.collect::<Vec<_>>();
333338
Ok(commitment)
334339
}

src/tests/relations.rs

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use rand::rngs::OsRng;
55
use crate::fiat_shamir::NISigmaProtocol;
66
use crate::tests::test_utils::{
77
bbs_blind_commitment_computation, discrete_logarithm, dleq, pedersen_commitment,
8-
pedersen_commitment_dleq,
8+
pedersen_commitment_dleq, translated_discrete_logarithm, translated_dleq,
99
};
1010
use crate::{codec::ShakeCodec, schnorr_protocol::SchnorrProof};
1111

@@ -17,12 +17,24 @@ fn test_discrete_logarithm() {
1717
discrete_logarithm::<G>(Scalar::random(&mut rng));
1818
}
1919

20+
#[test]
21+
fn test_translated_discrete_logarithm() {
22+
let mut rng = OsRng;
23+
translated_discrete_logarithm::<G>(Scalar::random(&mut rng));
24+
}
25+
2026
#[test]
2127
fn test_dleq() {
2228
let mut rng = OsRng;
2329
dleq(G::random(&mut rng), Scalar::random(&mut rng));
2430
}
2531

32+
#[test]
33+
fn test_translated_dleq() {
34+
let mut rng = OsRng;
35+
dleq(G::random(&mut rng), Scalar::random(&mut rng));
36+
}
37+
2638
#[test]
2739
fn test_pedersen_commitment() {
2840
let mut rng = OsRng;
@@ -97,6 +109,33 @@ fn noninteractive_discrete_logarithm() {
97109
);
98110
}
99111

112+
#[test]
113+
fn noninteractive_translated_discrete_logarithm() {
114+
let mut rng = OsRng;
115+
let (relation, witness) = translated_discrete_logarithm(Scalar::random(&mut rng));
116+
117+
// The SigmaProtocol induced by relation
118+
let protocol = SchnorrProof::from(relation);
119+
// Fiat-Shamir wrapper
120+
let domain_sep = b"test-fiat-shamir-translated-schnorr";
121+
let nizk = NISigmaProtocol::<SchnorrProof<G>, ShakeCodec<G>>::new(domain_sep, protocol);
122+
123+
// Batchable and compact proofs
124+
let proof_batchable_bytes = nizk.prove_batchable(&witness, &mut rng).unwrap();
125+
let proof_compact_bytes = nizk.prove_compact(&witness, &mut rng).unwrap();
126+
// Verify proofs
127+
let verified_batchable = nizk.verify_batchable(&proof_batchable_bytes).is_ok();
128+
let verified_compact = nizk.verify_compact(&proof_compact_bytes).is_ok();
129+
assert!(
130+
verified_batchable,
131+
"Fiat-Shamir Schnorr proof verification failed"
132+
);
133+
assert!(
134+
verified_compact,
135+
"Fiat-Shamir Schnorr proof verification failed"
136+
);
137+
}
138+
100139
#[test]
101140
fn noninteractive_dleq() {
102141
let mut rng = OsRng;
@@ -124,6 +163,33 @@ fn noninteractive_dleq() {
124163
);
125164
}
126165

166+
#[test]
167+
fn noninteractive_translated_dleq() {
168+
let mut rng = OsRng;
169+
let (relation, witness) = translated_dleq(G::random(&mut rng), Scalar::random(&mut rng));
170+
171+
// The SigmaProtocol induced by relation
172+
let protocol = SchnorrProof::from(relation);
173+
// Fiat-Shamir wrapper
174+
let domain_sep = b"test-fiat-shamir-translated-DLEQ";
175+
let nizk = NISigmaProtocol::<SchnorrProof<G>, ShakeCodec<G>>::new(domain_sep, protocol);
176+
177+
// Batchable and compact proofs
178+
let proof_batchable_bytes = nizk.prove_batchable(&witness, &mut rng).unwrap();
179+
let proof_compact_bytes = nizk.prove_compact(&witness, &mut rng).unwrap();
180+
// Verify proofs
181+
let verified_batchable = nizk.verify_batchable(&proof_batchable_bytes).is_ok();
182+
let verified_compact = nizk.verify_compact(&proof_compact_bytes).is_ok();
183+
assert!(
184+
verified_batchable,
185+
"Fiat-Shamir Schnorr proof verification failed"
186+
);
187+
assert!(
188+
verified_compact,
189+
"Fiat-Shamir Schnorr proof verification failed"
190+
);
191+
}
192+
127193
#[test]
128194
fn noninteractive_pedersen_commitment() {
129195
let mut rng = OsRng;

src/tests/test_utils.rs

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//! Definitions used in tests for this crate.
22
3+
use ff::Field;
34
use group::{Group, GroupEncoding};
45

56
use crate::linear_relation::{msm_pr, LinearRelation};
@@ -25,6 +26,27 @@ pub fn discrete_logarithm<G: Group + GroupEncoding>(
2526
(relation, vec![x])
2627
}
2728

29+
/// LinearMap for knowledge of a translated discrete logarithm relative to a fixed basepoint.
30+
#[allow(non_snake_case)]
31+
pub fn translated_discrete_logarithm<G: Group + GroupEncoding>(
32+
x: G::Scalar,
33+
) -> (LinearRelation<G>, Vec<G::Scalar>) {
34+
let mut relation: LinearRelation<G> = LinearRelation::new();
35+
36+
let var_x = relation.allocate_scalar();
37+
let var_G = relation.allocate_element();
38+
39+
let var_X = relation.allocate_eq((var_x + <<G as Group>::Scalar as Field>::ONE) * var_G);
40+
41+
relation.set_element(var_G, G::generator());
42+
relation.compute_image(&[x]).unwrap();
43+
44+
let X = relation.linear_map.group_elements.get(var_X).unwrap();
45+
46+
assert!(vec![X] == relation.linear_map.evaluate(&[x]).unwrap());
47+
(relation, vec![x])
48+
}
49+
2850
/// LinearMap for knowledge of a discrete logarithm equality between two pairs.
2951
#[allow(non_snake_case)]
3052
pub fn dleq<G: Group + GroupEncoding>(H: G, x: G::Scalar) -> (LinearRelation<G>, Vec<G::Scalar>) {
@@ -47,6 +69,31 @@ pub fn dleq<G: Group + GroupEncoding>(H: G, x: G::Scalar) -> (LinearRelation<G>,
4769
(relation, vec![x])
4870
}
4971

72+
/// LinearMap for knowledge of a translated dleq.
73+
#[allow(non_snake_case)]
74+
pub fn translated_dleq<G: Group + GroupEncoding>(
75+
H: G,
76+
x: G::Scalar,
77+
) -> (LinearRelation<G>, Vec<G::Scalar>) {
78+
let mut relation: LinearRelation<G> = LinearRelation::new();
79+
80+
let var_x = relation.allocate_scalar();
81+
let [var_G, var_H] = relation.allocate_elements();
82+
83+
let var_X = relation.allocate_eq(var_x * var_G + var_H);
84+
let var_Y = relation.allocate_eq(var_x * var_H + var_G);
85+
86+
relation.set_elements([(var_G, G::generator()), (var_H, H)]);
87+
relation.compute_image(&[x]).unwrap();
88+
89+
let X = relation.linear_map.group_elements.get(var_X).unwrap();
90+
let Y = relation.linear_map.group_elements.get(var_Y).unwrap();
91+
92+
assert_eq!(X, G::generator() * x + H);
93+
assert_eq!(Y, H * x + G::generator());
94+
(relation, vec![x])
95+
}
96+
5097
/// LinearMap for knowledge of an opening to a Pederson commitment.
5198
#[allow(non_snake_case)]
5299
pub fn pedersen_commitment<G: Group + GroupEncoding>(
@@ -85,7 +132,8 @@ pub fn pedersen_commitment_dleq<G: Group + GroupEncoding>(
85132
let [var_x, var_r] = relation.allocate_scalars();
86133

87134
let var_Gs = relation.allocate_elements::<4>();
88-
let [var_X, var_Y] = relation.allocate_elements();
135+
let var_X = relation.allocate_eq(var_x * var_Gs[0] + var_r * var_Gs[1]);
136+
let var_Y = relation.allocate_eq(var_x * var_Gs[2] + var_r * var_Gs[3]);
89137

90138
relation.set_elements([
91139
(var_Gs[0], generators[0]),
@@ -95,9 +143,6 @@ pub fn pedersen_commitment_dleq<G: Group + GroupEncoding>(
95143
]);
96144
relation.set_elements([(var_X, X), (var_Y, Y)]);
97145

98-
relation.append_equation(var_X, [(var_x, var_Gs[0]), (var_r, var_Gs[1])]);
99-
relation.append_equation(var_Y, [(var_x, var_Gs[2]), (var_r, var_Gs[3])]);
100-
101146
assert!(vec![X, Y] == relation.linear_map.evaluate(&witness).unwrap());
102147
(relation, witness.to_vec())
103148
}
@@ -119,7 +164,12 @@ pub fn bbs_blind_commitment_computation<G: Group + GroupEncoding>(
119164
let [var_secret_prover_blind, var_msg_1, var_msg_2, var_msg_3] = relation.allocate_scalars();
120165

121166
let [var_Q_2, var_J_1, var_J_2, var_J_3] = relation.allocate_elements();
122-
let var_C = relation.allocate_element();
167+
let var_C = relation.allocate_eq(
168+
var_secret_prover_blind * var_Q_2
169+
+ var_msg_1 * var_J_1
170+
+ var_msg_2 * var_J_2
171+
+ var_msg_3 * var_J_3,
172+
);
123173

124174
relation.set_elements([
125175
(var_Q_2, Q_2),
@@ -129,16 +179,6 @@ pub fn bbs_blind_commitment_computation<G: Group + GroupEncoding>(
129179
(var_C, C),
130180
]);
131181

132-
relation.append_equation(
133-
var_C,
134-
[
135-
(var_secret_prover_blind, var_Q_2),
136-
(var_msg_1, var_J_1),
137-
(var_msg_2, var_J_2),
138-
(var_msg_3, var_J_3),
139-
],
140-
);
141-
142182
let witness = vec![secret_prover_blind, msg_1, msg_2, msg_3];
143183

144184
assert!(vec![C] == relation.linear_map.evaluate(&witness).unwrap());

0 commit comments

Comments
 (0)