Skip to content

Commit 15d5f37

Browse files
committed
Improve parameter error messages
1 parent 3299482 commit 15d5f37

File tree

10 files changed

+290
-101
lines changed

10 files changed

+290
-101
lines changed

src/parallel/parameters.rs

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,11 @@ pub struct TriptychParameters {
3838
#[derive(Debug, Snafu)]
3939
pub enum ParameterError {
4040
/// An invalid parameter was provided.
41-
#[snafu(display("An invalid parameter was provided"))]
42-
InvalidParameter,
41+
#[snafu(display("An invalid parameter was provided: {reason}"))]
42+
InvalidParameter {
43+
/// The reason for the parameter error.
44+
reason: &'static str,
45+
},
4346
}
4447

4548
impl TriptychParameters {
@@ -98,13 +101,18 @@ impl TriptychParameters {
98101
U: &RistrettoPoint,
99102
) -> Result<Self, ParameterError> {
100103
// These bounds are required by the protocol
101-
if n < 2 || m < 2 {
102-
return Err(ParameterError::InvalidParameter);
104+
if n < 2 {
105+
return Err(ParameterError::InvalidParameter { reason: "`n < 2`" });
106+
}
107+
if m < 2 {
108+
return Err(ParameterError::InvalidParameter { reason: "`m < 2`" });
103109
}
104110

105111
// Check that the parameters don't overflow `u32`
106112
if n.checked_pow(m).is_none() {
107-
return Err(ParameterError::InvalidParameter);
113+
return Err(ParameterError::InvalidParameter {
114+
reason: "`n**m` overflowed `u32`",
115+
});
108116
}
109117

110118
// Use `BLAKE3` to generate `CommitmentH`
@@ -121,7 +129,9 @@ impl TriptychParameters {
121129
hasher.update(&m.to_le_bytes());
122130
let mut hasher_xof = hasher.finalize_xof();
123131
let mut CommitmentG_bytes = [0u8; 64];
124-
let CommitmentG = (0..n.checked_mul(m).ok_or(ParameterError::InvalidParameter)?)
132+
let CommitmentG = (0..n.checked_mul(m).ok_or(ParameterError::InvalidParameter {
133+
reason: "`n*m` overflowed `u32`",
134+
})?)
125135
.map(|_| {
126136
hasher_xof.fill(&mut CommitmentG_bytes);
127137
RistrettoPoint::from_uniform_bytes(&CommitmentG_bytes)
@@ -166,8 +176,15 @@ impl TriptychParameters {
166176
timing: OperationTiming,
167177
) -> Result<RistrettoPoint, ParameterError> {
168178
// Check that the matrix dimensions are valid
169-
if matrix.len() != (self.m as usize) || matrix.iter().any(|m| m.len() != (self.n as usize)) {
170-
return Err(ParameterError::InvalidParameter);
179+
if matrix.len() != (self.m as usize) {
180+
return Err(ParameterError::InvalidParameter {
181+
reason: "matrix did not have `m` rows",
182+
});
183+
}
184+
if matrix.iter().any(|m| m.len() != (self.n as usize)) {
185+
return Err(ParameterError::InvalidParameter {
186+
reason: "matrix did not have `n` columns",
187+
});
171188
}
172189

173190
// Flatten before evaluating the commitment

src/parallel/proof.rs

Lines changed: 85 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,11 @@ pub struct TriptychProof {
5353
#[derive(Debug, Snafu)]
5454
pub enum ProofError {
5555
/// An invalid parameter was provided.
56-
#[snafu(display("An invalid parameter was provided"))]
57-
InvalidParameter,
56+
#[snafu(display("An invalid parameter was provided: {reason}"))]
57+
InvalidParameter {
58+
/// The reason for the parameter error.
59+
reason: &'static str,
60+
},
5861
/// A transcript challenge was invalid.
5962
#[snafu(display("A transcript challenge was invalid"))]
6063
InvalidChallenge,
@@ -174,7 +177,9 @@ impl TriptychProof {
174177
) -> Result<Self, ProofError> {
175178
// Check that the witness and statement have identical parameters
176179
if witness.get_params() != statement.get_params() {
177-
return Err(ProofError::InvalidParameter);
180+
return Err(ProofError::InvalidParameter {
181+
reason: "witness and statement parameters did not match",
182+
});
178183
}
179184

180185
// Extract values for convenience
@@ -205,13 +210,17 @@ impl TriptychProof {
205210
}
206211

207212
if M_l != r * params.get_G() {
208-
return Err(ProofError::InvalidParameter);
213+
return Err(ProofError::InvalidParameter {
214+
reason: "`M[l] != r * G`",
215+
});
209216
}
210217
if M1_l - offset != r1 * params.get_G1() {
211-
return Err(ProofError::InvalidParameter);
218+
return Err(ProofError::InvalidParameter {
219+
reason: "`M1[l] - offset != r1 * G1`",
220+
});
212221
}
213222
if &(r * J) != params.get_U() {
214-
return Err(ProofError::InvalidParameter);
223+
return Err(ProofError::InvalidParameter { reason: "`r * J != U`" });
215224
}
216225

217226
// Set up the transcript
@@ -231,16 +240,23 @@ impl TriptychProof {
231240
}
232241
let A = params
233242
.commit_matrix(&a, &r_A, timing)
234-
.map_err(|_| ProofError::InvalidParameter)?;
243+
.map_err(|_| ProofError::InvalidParameter {
244+
reason: "unable to compute `A`",
245+
})?;
235246

236247
// Compute the `B` matrix commitment
237248
let r_B = Scalar::random(transcript.as_mut_rng());
238249
let l_decomposed = match timing {
239250
OperationTiming::Constant => {
240-
GrayIterator::decompose(params.get_n(), params.get_m(), l).ok_or(ProofError::InvalidParameter)?
251+
GrayIterator::decompose(params.get_n(), params.get_m(), l).ok_or(ProofError::InvalidParameter {
252+
reason: "`l` decomposition failed",
253+
})?
241254
},
242-
OperationTiming::Variable => GrayIterator::decompose_vartime(params.get_n(), params.get_m(), l)
243-
.ok_or(ProofError::InvalidParameter)?,
255+
OperationTiming::Variable => GrayIterator::decompose_vartime(params.get_n(), params.get_m(), l).ok_or(
256+
ProofError::InvalidParameter {
257+
reason: "`l` decomposition failed",
258+
},
259+
)?,
244260
};
245261
let sigma = (0..params.get_m())
246262
.map(|j| {
@@ -251,7 +267,9 @@ impl TriptychProof {
251267
.collect::<Vec<Vec<Scalar>>>();
252268
let B = params
253269
.commit_matrix(&sigma, &r_B, timing)
254-
.map_err(|_| ProofError::InvalidParameter)?;
270+
.map_err(|_| ProofError::InvalidParameter {
271+
reason: "unable to compute `B`",
272+
})?;
255273

256274
// Compute the `C` matrix commitment
257275
let two = Scalar::from(2u32);
@@ -265,7 +283,9 @@ impl TriptychProof {
265283
.collect::<Vec<Vec<Scalar>>>();
266284
let C = params
267285
.commit_matrix(&a_sigma, &r_C, timing)
268-
.map_err(|_| ProofError::InvalidParameter)?;
286+
.map_err(|_| ProofError::InvalidParameter {
287+
reason: "unable to compute `C`",
288+
})?;
269289

270290
// Compute the `D` matrix commitment
271291
let r_D = Scalar::random(transcript.as_mut_rng());
@@ -278,7 +298,9 @@ impl TriptychProof {
278298
.collect::<Vec<Vec<Scalar>>>();
279299
let D = params
280300
.commit_matrix(&a_square, &r_D, timing)
281-
.map_err(|_| ProofError::InvalidParameter)?;
301+
.map_err(|_| ProofError::InvalidParameter {
302+
reason: "unable to compute `D`",
303+
})?;
282304

283305
// Random masks
284306
let rho = Zeroizing::new(
@@ -296,7 +318,9 @@ impl TriptychProof {
296318
let mut p = Vec::<Vec<Scalar>>::with_capacity(params.get_N() as usize);
297319
let mut k_decomposed = vec![0; params.get_m() as usize];
298320
for (gray_index, _, gray_new) in
299-
GrayIterator::new(params.get_n(), params.get_m()).ok_or(ProofError::InvalidParameter)?
321+
GrayIterator::new(params.get_n(), params.get_m()).ok_or(ProofError::InvalidParameter {
322+
reason: "coefficient decomposition failed",
323+
})?
300324
{
301325
k_decomposed[gray_index] = gray_new;
302326

@@ -305,7 +329,9 @@ impl TriptychProof {
305329
coefficients.resize(
306330
(params.get_m() as usize)
307331
.checked_add(1)
308-
.ok_or(ProofError::InvalidParameter)?,
332+
.ok_or(ProofError::InvalidParameter {
333+
reason: "polynomial degree overflowed",
334+
})?,
309335
Scalar::ZERO,
310336
);
311337
coefficients[0] = a[0][k_decomposed[0] as usize];
@@ -564,10 +590,14 @@ impl TriptychProof {
564590
) -> Result<(), ProofError> {
565591
// Check that we have the same number of statements, proofs, and transcripts
566592
if statements.len() != proofs.len() {
567-
return Err(ProofError::InvalidParameter);
593+
return Err(ProofError::InvalidParameter {
594+
reason: "number of statements and proofs does not match",
595+
});
568596
}
569597
if statements.len() != transcripts.len() {
570-
return Err(ProofError::InvalidParameter);
598+
return Err(ProofError::InvalidParameter {
599+
reason: "number of statements and transcripts does not match",
600+
});
571601
}
572602

573603
// An empty batch is considered trivially valid
@@ -578,12 +608,16 @@ impl TriptychProof {
578608

579609
// Each statement must use the same input set (checked using the hash for efficiency)
580610
if !statements.iter().map(|s| s.get_input_set().get_hash()).all_equal() {
581-
return Err(ProofError::InvalidParameter);
611+
return Err(ProofError::InvalidParameter {
612+
reason: "statement input sets do not match",
613+
});
582614
}
583615

584616
// Each statement must use the same parameters (checked using the hash for efficiency)
585617
if !statements.iter().map(|s| s.get_params().get_hash()).all_equal() {
586-
return Err(ProofError::InvalidParameter);
618+
return Err(ProofError::InvalidParameter {
619+
reason: "statement parameters do not match",
620+
});
587621
}
588622

589623
// Extract common values for convenience
@@ -594,26 +628,42 @@ impl TriptychProof {
594628
// Check that all proof semantics are valid for the statement
595629
for proof in proofs {
596630
if proof.X.len() != params.get_m() as usize {
597-
return Err(ProofError::InvalidParameter);
631+
return Err(ProofError::InvalidParameter {
632+
reason: "proof `X` vector length was not `m`",
633+
});
598634
}
599635
if proof.X1.len() != params.get_m() as usize {
600-
return Err(ProofError::InvalidParameter);
636+
return Err(ProofError::InvalidParameter {
637+
reason: "proof `X1` vector length was not `m`",
638+
});
601639
}
602640
if proof.Y.len() != params.get_m() as usize {
603-
return Err(ProofError::InvalidParameter);
641+
return Err(ProofError::InvalidParameter {
642+
reason: "proof `Y` vector length was not `m`",
643+
});
604644
}
605645
if proof.f.len() != params.get_m() as usize {
606-
return Err(ProofError::InvalidParameter);
646+
return Err(ProofError::InvalidParameter {
647+
reason: "proof `f` matrix did not have `m` rows",
648+
});
607649
}
608650
for f_row in &proof.f {
609-
if f_row.len() != params.get_n().checked_sub(1).ok_or(ProofError::InvalidParameter)? as usize {
610-
return Err(ProofError::InvalidParameter);
651+
if f_row.len() !=
652+
params.get_n().checked_sub(1).ok_or(ProofError::InvalidParameter {
653+
reason: "proof `f` matrix column count overflowed",
654+
})? as usize
655+
{
656+
return Err(ProofError::InvalidParameter {
657+
reason: "proof `f` matrix did not have `n - 1` columns",
658+
});
611659
}
612660
}
613661
}
614662

615663
// Determine the size of the final check vector, which must not overflow `usize`
616-
let batch_size = u32::try_from(proofs.len()).map_err(|_| ProofError::InvalidParameter)?;
664+
let batch_size = u32::try_from(proofs.len()).map_err(|_| ProofError::InvalidParameter {
665+
reason: "batch size overflowed `u32`",
666+
})?;
617667

618668
// This is unlikely to overflow; even if it does, the only effect is unnecessary reallocation
619669
#[allow(clippy::arithmetic_side_effects)]
@@ -631,7 +681,9 @@ impl TriptychProof {
631681
+ 3 * params.get_m() // X, X1, Y
632682
),
633683
)
634-
.map_err(|_| ProofError::InvalidParameter)?;
684+
.map_err(|_| ProofError::InvalidParameter {
685+
reason: "multiscalar multiplication size overflowed `usize`",
686+
})?;
635687

636688
// Set up the point vector for the final check
637689
let points = proofs
@@ -708,7 +760,9 @@ impl TriptychProof {
708760
// Check that `f` does not contain zero, which breaks batch inversion
709761
for f_row in &f {
710762
if f_row.contains(&Scalar::ZERO) {
711-
return Err(ProofError::InvalidParameter);
763+
return Err(ProofError::InvalidParameter {
764+
reason: "proof `f` matrix contained 0",
765+
});
712766
}
713767
}
714768

@@ -779,7 +833,9 @@ impl TriptychProof {
779833
// Set up the initial `f` product and Gray iterator
780834
let mut f_product = f.iter().map(|f_row| f_row[0]).product::<Scalar>();
781835
let gray_iterator =
782-
GrayIterator::new(params.get_n(), params.get_m()).ok_or(ProofError::InvalidParameter)?;
836+
GrayIterator::new(params.get_n(), params.get_m()).ok_or(ProofError::InvalidParameter {
837+
reason: "coefficient decomposition failed",
838+
})?;
783839

784840
// Invert each element of `f` for efficiency
785841
let mut f_inverse_flat = f.iter().flatten().copied().collect::<Vec<Scalar>>();

0 commit comments

Comments
 (0)