Skip to content

Commit 3232107

Browse files
committed
Add DST to DDH and key consistency proofs
Adds a domain-separation-tag parameter to the Fiat-Shamir challenges of: - DdhTupleNizk (fastcrypto/src/nizk.rs) - ZeroProof, ConsistencyProof, KeyConsistencyProof (fastcrypto/src/twisted_elgamal.rs) - VerifiableKeyEncapsulation, which threads the DST through to its inner KeyConsistencyProof. The bulletproofs range proofs intentionally do not take a DST, to match the Move and TypeScript implementations in mystenlabs/contra.
1 parent 239eed7 commit 3232107

2 files changed

Lines changed: 133 additions & 52 deletions

File tree

fastcrypto/src/nizk.rs

Lines changed: 47 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -31,28 +31,38 @@ where
3131
<G as GroupElement>::ScalarType: FiatShamirChallenge,
3232
{
3333
/// Create a new NIZKPoK for the DDH tuple `(G, H=eG, xG, xH)` using the given RNG.
34+
/// `dst` is a domain separation tag bound into the Fiat-Shamir challenge; the same `dst` must
35+
/// be passed to [Self::verify].
3436
pub fn create<R: AllowedRng>(
3537
x: &G::ScalarType,
3638
g: &G,
3739
h: &G,
3840
x_g: &G,
3941
x_h: &G,
42+
dst: &[u8],
4043
rng: &mut R,
4144
) -> Self {
4245
let r = G::ScalarType::rand(rng);
4346
let a = *g * r;
4447
let b = *h * r;
45-
let challenge = Self::fiat_shamir_challenge(g, h, x_g, x_h, &a, &b);
48+
let challenge = Self::fiat_shamir_challenge(g, h, x_g, x_h, &a, &b, dst);
4649
let z = challenge * x + r;
4750
DdhTupleNizk { a, b, z }
4851
}
4952

50-
/// Verify this NIZKPoK.
51-
pub fn verify(&self, g: &G, h: &G, x_g: &G, x_h: &G) -> FastCryptoResult<()> {
53+
/// Verify this NIZKPoK. `dst` must match the value used in [Self::create].
54+
pub fn verify(
55+
&self,
56+
g: &G,
57+
h: &G,
58+
x_g: &G,
59+
x_h: &G,
60+
dst: &[u8],
61+
) -> FastCryptoResult<()> {
5262
if *g == G::zero() || *h == G::zero() || *x_g == G::zero() || *x_h == G::zero() {
5363
return Err(FastCryptoError::InvalidProof);
5464
}
55-
let challenge = Self::fiat_shamir_challenge(g, h, x_g, x_h, &self.a, &self.b);
65+
let challenge = Self::fiat_shamir_challenge(g, h, x_g, x_h, &self.a, &self.b, dst);
5666
if !is_valid_relation(&self.a, x_g, g, &self.z, &challenge)
5767
|| !is_valid_relation(
5868
&self.b, // B
@@ -66,8 +76,16 @@ where
6676
}
6777

6878
/// Returns the challenge for Fiat-Shamir.
69-
fn fiat_shamir_challenge(g: &G, h: &G, x_g: &G, x_h: &G, a: &G, b: &G) -> G::ScalarType {
70-
let output = Sha3_256::digest(bcs::to_bytes(&(g, h, x_g, x_h, a, b)).unwrap());
79+
fn fiat_shamir_challenge(
80+
g: &G,
81+
h: &G,
82+
x_g: &G,
83+
x_h: &G,
84+
a: &G,
85+
b: &G,
86+
dst: &[u8],
87+
) -> G::ScalarType {
88+
let output = Sha3_256::digest(bcs::to_bytes(&(dst, g, h, x_g, x_h, a, b)).unwrap());
7189
G::ScalarType::fiat_shamir_reduction_to_group_element(&output.digest)
7290
}
7391
}
@@ -107,31 +125,35 @@ mod tests {
107125

108126
#[test]
109127
fn test_nizk_flow() {
128+
let dst = b"test";
110129
let e = S::rand(&mut thread_rng());
111130
let x = S::rand(&mut thread_rng());
112131
let g = G::generator() * S::rand(&mut thread_rng());
113132
let h = g * e;
114133
let x_g = g * x;
115134
let x_h = h * x;
116-
let nizk = DdhTupleNizk::create(&x, &g, &h, &x_g, &x_h, &mut thread_rng());
117-
assert!(nizk.verify(&g, &h, &x_g, &x_h).is_ok());
135+
let nizk = DdhTupleNizk::create(&x, &g, &h, &x_g, &x_h, dst, &mut thread_rng());
136+
assert!(nizk.verify(&g, &h, &x_g, &x_h, dst).is_ok());
137+
138+
// A different DST must not verify
139+
assert!(nizk.verify(&g, &h, &x_g, &x_h, b"other").is_err());
118140

119141
let invalid_witness = x + S::generator();
120142
let invalid_nizk =
121-
DdhTupleNizk::create(&invalid_witness, &g, &h, &x_g, &x_h, &mut thread_rng());
122-
assert!(invalid_nizk.verify(&g, &h, &x_g, &x_h).is_err());
143+
DdhTupleNizk::create(&invalid_witness, &g, &h, &x_g, &x_h, dst, &mut thread_rng());
144+
assert!(invalid_nizk.verify(&g, &h, &x_g, &x_h, dst).is_err());
123145

124146
let other_g = g + G::generator();
125-
assert!(nizk.verify(&other_g, &h, &x_g, &x_h).is_err());
147+
assert!(nizk.verify(&other_g, &h, &x_g, &x_h, dst).is_err());
126148

127149
let other_h = h + G::generator();
128-
assert!(nizk.verify(&g, &other_h, &x_g, &x_h).is_err());
150+
assert!(nizk.verify(&g, &other_h, &x_g, &x_h, dst).is_err());
129151

130152
let other_x_g = x_g + G::generator();
131-
assert!(nizk.verify(&g, &h, &other_x_g, &x_h).is_err());
153+
assert!(nizk.verify(&g, &h, &other_x_g, &x_h, dst).is_err());
132154

133155
let other_x_h = x_h + G::generator();
134-
assert!(nizk.verify(&g, &h, &x_g, &other_x_h).is_err());
156+
assert!(nizk.verify(&g, &h, &x_g, &other_x_h, dst).is_err());
135157
}
136158

137159
#[test]
@@ -145,10 +167,10 @@ mod tests {
145167
let r = S::from(91u64);
146168
let a = g * r;
147169
let b = h * r;
148-
let c = DdhTupleNizk::fiat_shamir_challenge(&g, &h, &x_g, &x_h, &a, &b);
170+
let c = DdhTupleNizk::fiat_shamir_challenge(&g, &h, &x_g, &x_h, &a, &b, b"test");
149171
assert_eq!(
150172
&c.to_byte_array(),
151-
Hex::decode("30db2f4121471c4af67d2dcfdede1f4aefb15475867c20c0dd5c228c0721f80e")
173+
Hex::decode("308ef93a3c19c20dcbf293b99363eeb4158c90aff86fe006477c80f6140e6a0f")
152174
.unwrap()
153175
.as_slice()
154176
);
@@ -157,30 +179,32 @@ mod tests {
157179
#[test]
158180
fn test_invalid_proofs() {
159181
// x_g/h_g/h=inf should be rejected
182+
let dst = b"test";
160183
let e = S::zero();
161184
let x = S::rand(&mut thread_rng());
162185
let g = G::generator() * S::rand(&mut thread_rng());
163186
let h = g * e;
164187
let x_g = g * x;
165188
let x_h = h * x;
166-
let nizk = DdhTupleNizk::create(&x, &g, &h, &x_g, &x_h, &mut thread_rng());
189+
let nizk = DdhTupleNizk::create(&x, &g, &h, &x_g, &x_h, dst, &mut thread_rng());
167190

168-
assert!(nizk.verify(&G::zero(), &h, &x_g, &x_h).is_err());
169-
assert!(nizk.verify(&g, &G::zero(), &x_g, &x_h).is_err());
170-
assert!(nizk.verify(&g, &h, &G::zero(), &x_h).is_err());
171-
assert!(nizk.verify(&g, &h, &x_g, &G::zero()).is_err());
191+
assert!(nizk.verify(&G::zero(), &h, &x_g, &x_h, dst).is_err());
192+
assert!(nizk.verify(&g, &G::zero(), &x_g, &x_h, dst).is_err());
193+
assert!(nizk.verify(&g, &h, &G::zero(), &x_h, dst).is_err());
194+
assert!(nizk.verify(&g, &h, &x_g, &G::zero(), dst).is_err());
172195
}
173196

174197
#[test]
175198
fn test_serde() {
199+
let dst = b"test";
176200
let e = S::rand(&mut thread_rng());
177201
let x2 = S::rand(&mut thread_rng());
178202
let g = G::generator() * S::rand(&mut thread_rng());
179203
let h = g * e;
180204
let x_g = g * x2;
181205
let x_h = h * x2;
182-
let nizk = DdhTupleNizk::create(&x2, &g, &h, &x_g, &x_h, &mut thread_rng());
183-
assert!(nizk.verify(&g, &h, &x_g, &x_h).is_ok());
206+
let nizk = DdhTupleNizk::create(&x2, &g, &h, &x_g, &x_h, dst, &mut thread_rng());
207+
assert!(nizk.verify(&g, &h, &x_g, &x_h, dst).is_ok());
184208

185209
let as_bytes = bcs::to_bytes(&nizk).unwrap();
186210
let nizk2: DdhTupleNizk<G> = bcs::from_bytes(&as_bytes).unwrap();

0 commit comments

Comments
 (0)