Skip to content

Commit bf074cb

Browse files
Refactor hashing domains (#107)
This PR moves hashing domains to a common module, in order to reduce the risk of collisions. It also ensures that all hashing operations are versioned. BREAKING CHANGE: Updates how some hashing operations are performed, which will break existing proofs.
1 parent a0760a0 commit bf074cb

File tree

9 files changed

+77
-78
lines changed

9 files changed

+77
-78
lines changed

src/lib.rs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,6 @@ extern crate alloc;
116116

117117
pub use merlin::Transcript;
118118

119-
pub(crate) const TRANSCRIPT_HASH_BYTES: usize = 32;
120-
121119
/// Iterated arbitrary-base Gray code functionality.
122120
pub(crate) mod gray;
123121
/// Public parameters used for generating and verifying Triptych proofs.
@@ -139,3 +137,32 @@ pub use witness::TriptychWitness;
139137

140138
/// Parallel Triptych functionality.
141139
pub mod parallel;
140+
141+
/// Domain separators used for hashing operations
142+
pub(crate) mod domains {
143+
// Version
144+
pub(crate) const VERSION: u64 = 0;
145+
146+
// Number of bytes in a transcript hash
147+
pub(crate) const TRANSCRIPT_HASH_BYTES: usize = 32;
148+
149+
// Parameters
150+
pub(crate) const TRANSCRIPT_PARAMETERS: &str = "Triptych parameters";
151+
pub(crate) const TRANSCRIPT_PARALLEL_PARAMETERS: &str = "Parallel Triptych parameters";
152+
pub(crate) const POINT_G1: &str = "Triptych G1";
153+
pub(crate) const POINT_U: &str = "Triptych U";
154+
pub(crate) const POINT_COMMITMENT_G: &str = "Triptych CommitmentG";
155+
pub(crate) const POINT_COMMITMENT_H: &str = "Triptych CommitmentH";
156+
157+
// Statement
158+
pub(crate) const TRANSCRIPT_INPUT_SET: &str = "Triptych input set";
159+
pub(crate) const TRANSCRIPT_PARALLEL_INPUT_SET: &str = "Parallel Triptych input set";
160+
pub(crate) const TRANSCRIPT_STATEMENT: &str = "Triptych statement";
161+
pub(crate) const TRANSCRIPT_PARALLEL_STATEMENT: &str = "Parallel Triptych statement";
162+
163+
// Proof
164+
pub(crate) const TRANSCRIPT_PROOF: &str = "Triptych proof";
165+
pub(crate) const TRANSCRIPT_PARALLEL_PROOF: &str = "Parallel Triptych proof";
166+
pub(crate) const TRANSCRIPT_VERIFIER_WEIGHTS: &str = "Triptych verifier weights";
167+
pub(crate) const TRANSCRIPT_PARALLEL_VERIFIER_WEIGHTS: &str = "Parallel Triptych verifier weights";
168+
}

src/parallel/parameters.rs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use curve25519_dalek::{
1313
};
1414
use snafu::prelude::*;
1515

16-
use crate::{util::OperationTiming, Transcript, TRANSCRIPT_HASH_BYTES};
16+
use crate::{domains, util::OperationTiming, Transcript};
1717

1818
/// Public parameters used for generating and verifying Triptych proofs.
1919
///
@@ -46,11 +46,6 @@ pub enum ParameterError {
4646
}
4747

4848
impl TriptychParameters {
49-
// Domain separator used for hashing
50-
const DOMAIN: &'static str = "Parallel Triptych parameters";
51-
// Version identifier used for hashing
52-
const VERSION: u64 = 0;
53-
5449
/// Generate new [`TriptychParameters`] for Triptych proofs.
5550
///
5651
/// The base `n > 1` and exponent `m > 1` define the size of verification key vectors, so it must be the case that
@@ -66,14 +61,16 @@ impl TriptychParameters {
6661
// Use `BLAKE3` to generate `G1`
6762
let mut G1_bytes = [0u8; 64];
6863
let mut hasher = Hasher::new();
69-
hasher.update(b"Triptych G1");
64+
hasher.update(domains::POINT_G1.as_bytes());
65+
hasher.update(&domains::VERSION.to_le_bytes());
7066
hasher.finalize_xof().fill(&mut G1_bytes);
7167
let G1 = RistrettoPoint::from_uniform_bytes(&G1_bytes);
7268

7369
// Use `BLAKE3` to generate `U`
7470
let mut U_bytes = [0u8; 64];
7571
let mut hasher = Hasher::new();
76-
hasher.update(b"Triptych U");
72+
hasher.update(domains::POINT_U.as_bytes());
73+
hasher.update(&domains::VERSION.to_le_bytes());
7774
hasher.finalize_xof().fill(&mut U_bytes);
7875
let U = RistrettoPoint::from_uniform_bytes(&U_bytes);
7976

@@ -118,13 +115,15 @@ impl TriptychParameters {
118115
// Use `BLAKE3` to generate `CommitmentH`
119116
let mut CommitmentH_bytes = [0u8; 64];
120117
let mut hasher = Hasher::new();
121-
hasher.update(b"Triptych CommitmentH");
118+
hasher.update(domains::POINT_COMMITMENT_H.as_bytes());
119+
hasher.update(&domains::VERSION.to_le_bytes());
122120
hasher.finalize_xof().fill(&mut CommitmentH_bytes);
123121
let CommitmentH = RistrettoPoint::from_uniform_bytes(&CommitmentH_bytes);
124122

125123
// Use `BLAKE3` for the commitment matrix generators
126124
let mut hasher = Hasher::new();
127-
hasher.update(b"Triptych CommitmentG");
125+
hasher.update(domains::POINT_COMMITMENT_G.as_bytes());
126+
hasher.update(&domains::VERSION.to_le_bytes());
128127
hasher.update(&n.to_le_bytes());
129128
hasher.update(&m.to_le_bytes());
130129
let mut hasher_xof = hasher.finalize_xof();
@@ -139,8 +138,8 @@ impl TriptychParameters {
139138
.collect::<Vec<RistrettoPoint>>();
140139

141140
// Use Merlin for the transcript hash
142-
let mut transcript = Transcript::new(Self::DOMAIN.as_bytes());
143-
transcript.append_u64(b"version", Self::VERSION);
141+
let mut transcript = Transcript::new(domains::TRANSCRIPT_PARALLEL_PARAMETERS.as_bytes());
142+
transcript.append_u64(b"version", domains::VERSION);
144143
transcript.append_message(b"n", &n.to_le_bytes());
145144
transcript.append_message(b"m", &m.to_le_bytes());
146145
transcript.append_message(b"G", G.compress().as_bytes());
@@ -150,7 +149,7 @@ impl TriptychParameters {
150149
transcript.append_message(b"CommitmentG", item.compress().as_bytes());
151150
}
152151
transcript.append_message(b"CommitmentH", CommitmentH.compress().as_bytes());
153-
let mut hash = vec![0u8; TRANSCRIPT_HASH_BYTES];
152+
let mut hash = vec![0u8; domains::TRANSCRIPT_HASH_BYTES];
154153
transcript.challenge_bytes(b"hash", &mut hash);
155154

156155
Ok(TriptychParameters {

src/parallel/proof.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use subtle::{ConditionallySelectable, ConstantTimeEq};
2121
use zeroize::Zeroizing;
2222

2323
use crate::{
24+
domains,
2425
gray::GrayIterator,
2526
parallel::{transcript::ProofTranscript, TriptychStatement, TriptychWitness},
2627
util::{delta, NullRng, OperationTiming},
@@ -722,7 +723,8 @@ impl TriptychProof {
722723
let mut U_scalar = Scalar::ZERO;
723724

724725
// Set up a transcript generator for use in weighting
725-
let mut transcript_weights = Transcript::new(b"Triptych verifier weights");
726+
let mut transcript_weights = Transcript::new(domains::TRANSCRIPT_PARALLEL_VERIFIER_WEIGHTS.as_bytes());
727+
transcript_weights.append_u64(b"version", domains::VERSION);
726728

727729
let mut null_rng = NullRng;
728730

src/parallel/statement.rs

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use alloc::{sync::Arc, vec, vec::Vec};
66
use curve25519_dalek::{traits::Identity, RistrettoPoint};
77
use snafu::prelude::*;
88

9-
use crate::{parallel::TriptychParameters, Transcript, TRANSCRIPT_HASH_BYTES};
9+
use crate::{domains, parallel::TriptychParameters, Transcript};
1010

1111
/// A Triptych input set.
1212
///
@@ -21,11 +21,6 @@ pub struct TriptychInputSet {
2121
}
2222

2323
impl TriptychInputSet {
24-
// Domain separator used for hashing
25-
const DOMAIN: &'static str = "Parallel Triptych input set";
26-
// Version identifier used for hashing
27-
const VERSION: u64 = 0;
28-
2924
/// Generate a new [`TriptychInputSet`] from a slice `M` of verification keys and slice `M1` of auxiliary
3025
/// verification keys.
3126
#[allow(non_snake_case)]
@@ -98,16 +93,16 @@ impl TriptychInputSet {
9893
})?;
9994

10095
// Use Merlin for the transcript hash
101-
let mut transcript = Transcript::new(Self::DOMAIN.as_bytes());
102-
transcript.append_u64(b"version", Self::VERSION);
96+
let mut transcript = Transcript::new(domains::TRANSCRIPT_PARALLEL_INPUT_SET.as_bytes());
97+
transcript.append_u64(b"version", domains::VERSION);
10398
transcript.append_message(b"unpadded_size", &unpadded_size.to_le_bytes());
10499
for item in M {
105100
transcript.append_message(b"M", item.compress().as_bytes());
106101
}
107102
for item in M1 {
108103
transcript.append_message(b"M1", item.compress().as_bytes());
109104
}
110-
let mut hash = vec![0u8; TRANSCRIPT_HASH_BYTES];
105+
let mut hash = vec![0u8; domains::TRANSCRIPT_HASH_BYTES];
111106
transcript.challenge_bytes(b"hash", &mut hash);
112107

113108
Ok(Self {
@@ -160,11 +155,6 @@ pub enum StatementError {
160155
}
161156

162157
impl TriptychStatement {
163-
// Domain separator used for hashing
164-
const DOMAIN: &'static str = "Parallel Triptych statement";
165-
// Version identifier used for hashing
166-
const VERSION: u64 = 0;
167-
168158
/// Generate a new [`TriptychStatement`].
169159
///
170160
/// The [`TriptychInputSet`] `input_set` must have a verification key vector whose size matches that specified by
@@ -205,13 +195,13 @@ impl TriptychStatement {
205195
}
206196

207197
// Use Merlin for the transcript hash
208-
let mut transcript = Transcript::new(Self::DOMAIN.as_bytes());
209-
transcript.append_u64(b"version", Self::VERSION);
198+
let mut transcript = Transcript::new(domains::TRANSCRIPT_PARALLEL_STATEMENT.as_bytes());
199+
transcript.append_u64(b"version", domains::VERSION);
210200
transcript.append_message(b"params", params.get_hash());
211201
transcript.append_message(b"input_set", input_set.get_hash());
212202
transcript.append_message(b"offset", offset.compress().as_bytes());
213203
transcript.append_message(b"J", J.compress().as_bytes());
214-
let mut hash = vec![0u8; TRANSCRIPT_HASH_BYTES];
204+
let mut hash = vec![0u8; domains::TRANSCRIPT_HASH_BYTES];
215205
transcript.challenge_bytes(b"hash", &mut hash);
216206

217207
Ok(Self {

src/parallel/transcript.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use merlin::TranscriptRng;
88
use rand_core::CryptoRngCore;
99

1010
use crate::{
11+
domains,
1112
parallel::{proof::ProofError, TriptychParameters, TriptychStatement, TriptychWitness},
1213
Transcript,
1314
};
@@ -21,11 +22,6 @@ pub(crate) struct ProofTranscript<'a, R: CryptoRngCore> {
2122
}
2223

2324
impl<'a, R: CryptoRngCore> ProofTranscript<'a, R> {
24-
// Domain separator used for hashing
25-
const DOMAIN: &'static str = "Parallel Triptych proof";
26-
// Version identifier used for hashing
27-
const VERSION: u64 = 0;
28-
2925
/// Initialize a transcript.
3026
pub(crate) fn new(
3127
transcript: &'a mut Transcript,
@@ -34,8 +30,8 @@ impl<'a, R: CryptoRngCore> ProofTranscript<'a, R> {
3430
witness: Option<&'a TriptychWitness>,
3531
) -> Self {
3632
// Update the transcript
37-
transcript.append_message(b"dom-sep", Self::DOMAIN.as_bytes());
38-
transcript.append_u64(b"version", Self::VERSION);
33+
transcript.append_message(b"dom-sep", domains::TRANSCRIPT_PARALLEL_PROOF.as_bytes());
34+
transcript.append_u64(b"version", domains::VERSION);
3935
transcript.append_message(b"statement", statement.get_hash());
4036

4137
// Set up the transcript generator

src/parameters.rs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use curve25519_dalek::{
1313
};
1414
use snafu::prelude::*;
1515

16-
use crate::{util::OperationTiming, Transcript, TRANSCRIPT_HASH_BYTES};
16+
use crate::{domains, util::OperationTiming, Transcript};
1717

1818
/// Public parameters used for generating and verifying Triptych proofs.
1919
///
@@ -45,11 +45,6 @@ pub enum ParameterError {
4545
}
4646

4747
impl TriptychParameters {
48-
// Domain separator used for hashing
49-
const DOMAIN: &'static str = "Triptych parameters";
50-
// Version identifier used for hashing
51-
const VERSION: u64 = 0;
52-
5348
/// Generate new [`TriptychParameters`] for Triptych proofs.
5449
///
5550
/// The base `n > 1` and exponent `m > 1` define the size of verification key vectors, so it must be the case that
@@ -65,7 +60,8 @@ impl TriptychParameters {
6560
// Use `BLAKE3` to generate `U`
6661
let mut U_bytes = [0u8; 64];
6762
let mut hasher = Hasher::new();
68-
hasher.update(b"Triptych U");
63+
hasher.update(domains::POINT_U.as_bytes());
64+
hasher.update(&domains::VERSION.to_le_bytes());
6965
hasher.finalize_xof().fill(&mut U_bytes);
7066
let U = RistrettoPoint::from_uniform_bytes(&U_bytes);
7167

@@ -103,13 +99,15 @@ impl TriptychParameters {
10399
// Use `BLAKE3` to generate `CommitmentH`
104100
let mut CommitmentH_bytes = [0u8; 64];
105101
let mut hasher = Hasher::new();
106-
hasher.update(b"Triptych CommitmentH");
102+
hasher.update(domains::POINT_COMMITMENT_H.as_bytes());
103+
hasher.update(&domains::VERSION.to_le_bytes());
107104
hasher.finalize_xof().fill(&mut CommitmentH_bytes);
108105
let CommitmentH = RistrettoPoint::from_uniform_bytes(&CommitmentH_bytes);
109106

110107
// Use `BLAKE3` for the commitment matrix generators
111108
let mut hasher = Hasher::new();
112-
hasher.update(b"Triptych CommitmentG");
109+
hasher.update(domains::POINT_COMMITMENT_G.as_bytes());
110+
hasher.update(&domains::VERSION.to_le_bytes());
113111
hasher.update(&n.to_le_bytes());
114112
hasher.update(&m.to_le_bytes());
115113
let mut hasher_xof = hasher.finalize_xof();
@@ -124,8 +122,8 @@ impl TriptychParameters {
124122
.collect::<Vec<RistrettoPoint>>();
125123

126124
// Use Merlin for the transcript hash
127-
let mut transcript = Transcript::new(Self::DOMAIN.as_bytes());
128-
transcript.append_u64(b"version", Self::VERSION);
125+
let mut transcript = Transcript::new(domains::TRANSCRIPT_PARAMETERS.as_bytes());
126+
transcript.append_u64(b"version", domains::VERSION);
129127
transcript.append_message(b"n", &n.to_le_bytes());
130128
transcript.append_message(b"m", &m.to_le_bytes());
131129
transcript.append_message(b"G", G.compress().as_bytes());
@@ -134,7 +132,7 @@ impl TriptychParameters {
134132
transcript.append_message(b"CommitmentG", item.compress().as_bytes());
135133
}
136134
transcript.append_message(b"CommitmentH", CommitmentH.compress().as_bytes());
137-
let mut hash = vec![0u8; TRANSCRIPT_HASH_BYTES];
135+
let mut hash = vec![0u8; domains::TRANSCRIPT_HASH_BYTES];
138136
transcript.challenge_bytes(b"hash", &mut hash);
139137

140138
Ok(TriptychParameters {

src/proof.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ use subtle::{ConditionallySelectable, ConstantTimeEq};
2121
use zeroize::Zeroizing;
2222

2323
use crate::{
24+
domains,
2425
gray::GrayIterator,
2526
transcript::ProofTranscript,
2627
util::{delta, NullRng, OperationTiming},
@@ -668,7 +669,8 @@ impl TriptychProof {
668669
let mut U_scalar = Scalar::ZERO;
669670

670671
// Set up a transcript generator for use in weighting
671-
let mut transcript_weights = Transcript::new(b"Triptych verifier weights");
672+
let mut transcript_weights = Transcript::new(domains::TRANSCRIPT_VERIFIER_WEIGHTS.as_bytes());
673+
transcript_weights.append_u64(b"version", domains::VERSION);
672674

673675
let mut null_rng = NullRng;
674676

src/statement.rs

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use alloc::{sync::Arc, vec, vec::Vec};
66
use curve25519_dalek::{traits::Identity, RistrettoPoint};
77
use snafu::prelude::*;
88

9-
use crate::{Transcript, TriptychParameters, TRANSCRIPT_HASH_BYTES};
9+
use crate::{domains, Transcript, TriptychParameters};
1010

1111
/// A Triptych input set.
1212
///
@@ -20,11 +20,6 @@ pub struct TriptychInputSet {
2020
}
2121

2222
impl TriptychInputSet {
23-
// Domain separator used for hashing
24-
const DOMAIN: &'static str = "Triptych input set";
25-
// Version identifier used for hashing
26-
const VERSION: u64 = 0;
27-
2823
/// Generate a new [`TriptychInputSet`] from a slice `M` of verification keys.
2924
#[allow(non_snake_case)]
3025
pub fn new(M: &[RistrettoPoint]) -> Result<Self, StatementError> {
@@ -71,13 +66,13 @@ impl TriptychInputSet {
7166
})?;
7267

7368
// Use Merlin for the transcript hash
74-
let mut transcript = Transcript::new(Self::DOMAIN.as_bytes());
75-
transcript.append_u64(b"version", Self::VERSION);
69+
let mut transcript = Transcript::new(domains::TRANSCRIPT_INPUT_SET.as_bytes());
70+
transcript.append_u64(b"version", domains::VERSION);
7671
transcript.append_message(b"unpadded_size", &unpadded_size.to_le_bytes());
7772
for item in M {
7873
transcript.append_message(b"M", item.compress().as_bytes());
7974
}
80-
let mut hash = vec![0u8; TRANSCRIPT_HASH_BYTES];
75+
let mut hash = vec![0u8; domains::TRANSCRIPT_HASH_BYTES];
8176
transcript.challenge_bytes(b"hash", &mut hash);
8277

8378
Ok(Self {
@@ -122,11 +117,6 @@ pub enum StatementError {
122117
}
123118

124119
impl TriptychStatement {
125-
// Domain separator used for hashing
126-
const DOMAIN: &'static str = "Triptych statement";
127-
// Version identifier used for hashing
128-
const VERSION: u64 = 0;
129-
130120
/// Generate a new [`TriptychStatement`].
131121
///
132122
/// The [`TriptychInputSet`] `input_set` must have a verification key vector whose size matches that specified by
@@ -155,12 +145,12 @@ impl TriptychStatement {
155145
}
156146

157147
// Use Merlin for the transcript hash
158-
let mut transcript = Transcript::new(Self::DOMAIN.as_bytes());
159-
transcript.append_u64(b"version", Self::VERSION);
148+
let mut transcript = Transcript::new(domains::TRANSCRIPT_STATEMENT.as_bytes());
149+
transcript.append_u64(b"version", domains::VERSION);
160150
transcript.append_message(b"params", params.get_hash());
161151
transcript.append_message(b"input_set", input_set.get_hash());
162152
transcript.append_message(b"J", J.compress().as_bytes());
163-
let mut hash = vec![0u8; TRANSCRIPT_HASH_BYTES];
153+
let mut hash = vec![0u8; domains::TRANSCRIPT_HASH_BYTES];
164154
transcript.challenge_bytes(b"hash", &mut hash);
165155

166156
Ok(Self {

0 commit comments

Comments
 (0)