Response to usage of unwrap in non-test code

This commit replaces all usage of `unwrap` with `expect` within
`networks/monero`, clarifying why the panic risked is unreachable. This commit
also replaces some uses of `unwrap` with solutions which are guaranteed not to
fail.

Notably, compilation on 128-bit systems is prevented, ensuring
`u64::try_from(usize::MAX)` will never panic at runtime.

Slight breaking changes are additionally included as necessary to massage out
some avoidable panics.
This commit is contained in:
Luke Parker
2025-08-08 21:28:47 -04:00
parent 4f65a0b147
commit a5f4c450c6
31 changed files with 310 additions and 169 deletions

View File

@@ -16,8 +16,10 @@ fn generators(prefix: &'static str, path: &str) {
generators_string.extend(
format!(
"
curve25519_dalek::edwards::CompressedEdwardsY({:?}).decompress().unwrap(),
",
curve25519_dalek::edwards::CompressedEdwardsY({:?})
.decompress()
.expect(\"generator from build script wasn't on-curve\"),
",
generator.compress().to_bytes()
)
.chars(),
@@ -33,10 +35,10 @@ fn generators(prefix: &'static str, path: &str) {
let mut H_str = String::new();
serialize(&mut H_str, &generators.H);
let path = Path::new(&env::var("OUT_DIR").unwrap()).join(path);
let path = Path::new(&env::var("OUT_DIR").expect("cargo didn't set $OUT_DIR")).join(path);
let _ = remove_file(&path);
File::create(&path)
.unwrap()
.expect("failed to create file in $OUT_DIR")
.write_all(
format!(
"
@@ -52,15 +54,15 @@ fn generators(prefix: &'static str, path: &str) {
)
.as_bytes(),
)
.unwrap();
.expect("couldn't write generated source code to file on disk");
}
#[cfg(not(feature = "compile-time-generators"))]
fn generators(prefix: &'static str, path: &str) {
let path = Path::new(&env::var("OUT_DIR").unwrap()).join(path);
let path = Path::new(&env::var("OUT_DIR").expect("cargo didn't set $OUT_DIR")).join(path);
let _ = remove_file(&path);
File::create(&path)
.unwrap()
.expect("failed to create file in $OUT_DIR")
.write_all(
format!(
r#"
@@ -71,7 +73,7 @@ fn generators(prefix: &'static str, path: &str) {
)
.as_bytes(),
)
.unwrap();
.expect("couldn't write generated source code to file on disk");
}
fn main() {

View File

@@ -5,7 +5,6 @@
#![allow(non_snake_case)]
use std_shims::{
vec,
vec::Vec,
io::{self, Read, Write},
};
@@ -124,9 +123,15 @@ impl Bulletproof {
let commitments = outputs.iter().map(Commitment::calculate).collect::<Vec<_>>();
Ok(Bulletproof::Original(
OriginalStatement::new(&commitments)
.unwrap()
.prove(rng, OriginalWitness::new(outputs).unwrap())
.unwrap(),
.expect("failed to create statement despite checking amount of commitments")
.prove(
rng,
OriginalWitness::new(outputs)
.expect("failed to create witness despite checking amount of commitments"),
)
.expect(
"failed to prove Bulletproof::Original despite ensuring statement/witness consistency",
),
))
}
@@ -144,9 +149,15 @@ impl Bulletproof {
let commitments = outputs.iter().map(Commitment::calculate).collect::<Vec<_>>();
Ok(Bulletproof::Plus(
PlusStatement::new(&commitments)
.unwrap()
.prove(rng, &Zeroizing::new(PlusWitness::new(outputs).unwrap()))
.unwrap(),
.expect("failed to create statement despite checking amount of commitments")
.prove(
rng,
&Zeroizing::new(
PlusWitness::new(outputs)
.expect("failed to create witness despite checking amount of commitments"),
),
)
.expect("failed to prove Bulletproof::Plus despite ensuring statement/witness consistency"),
))
}
@@ -255,8 +266,8 @@ impl Bulletproof {
/// Serialize a Bulletproof(+) to a `Vec<u8>`.
pub fn serialize(&self) -> Vec<u8> {
let mut serialized = vec![];
self.write(&mut serialized).unwrap();
let mut serialized = Vec::with_capacity(512);
self.write(&mut serialized).expect("write failed but <Vec as io::Write> doesn't fail");
serialized
}

View File

@@ -174,7 +174,11 @@ impl IpStatement {
R_vec.push(R * INV_EIGHT());
// Now that we've calculate L, R, transcript them to receive x (26-27)
transcript = Self::transcript_L_R(transcript, *L_vec.last().unwrap(), *R_vec.last().unwrap());
transcript = Self::transcript_L_R(
transcript,
*L_vec.last().expect("couldn't get last L_vec despite always being non-empty"),
*R_vec.last().expect("couldn't get last R_vec despite always being non-empty"),
);
let x = transcript;
let x_inv = x.invert();

View File

@@ -227,8 +227,11 @@ impl<'a> AggregateRangeStatement<'a> {
let x_ip = transcript;
let ip = IpStatement::new_without_P_transcript(y_inv_pow_n, x_ip)
.prove(transcript, IpWitness::new(l, r).unwrap())
.unwrap();
.prove(
transcript,
IpWitness::new(l, r).expect("Bulletproofs::Original created an invalid IpWitness"),
)
.expect("Bulletproofs::Original failed to prove the inner-product");
let res = AggregateRangeProof { A, S, T1, T2, tau_x, mu, t_hat, ip };
#[cfg(debug_assertions)]

View File

@@ -106,7 +106,9 @@ impl<'a> AggregateRangeStatement<'a> {
let mut d = ScalarVector::new(mn);
for j in 1 ..= V.len() {
z_pow.push(*z_pow.last().unwrap() * z_pow[0]);
z_pow.push(
*z_pow.last().expect("couldn't get last z_pow despite always being non-empty") * z_pow[0],
);
d = d + &(Self::d_j(j, V.len()) * (z_pow[j - 1]));
}
@@ -229,8 +231,15 @@ impl<'a> AggregateRangeStatement<'a> {
Some(AggregateRangeProof {
A,
wip: WipStatement::new(generators, A_hat, y)
.prove(rng, transcript, &Zeroizing::new(WipWitness::new(a_l, a_r, alpha).unwrap()))
.unwrap(),
.prove(
rng,
transcript,
&Zeroizing::new(
WipWitness::new(a_l, a_r, alpha)
.expect("Bulletproofs::Plus created an invalid WipWitness"),
),
)
.expect("Bulletproof::Plus failed to prove the weighted inner-product"),
})
}

View File

@@ -230,7 +230,9 @@ impl WipStatement {
let c_l = a1.clone().weighted_inner_product(&b2, &y);
let c_r = (a2.clone() * y_n_hat).weighted_inner_product(&b1, &y);
let y_inv_n_hat = y_inv.pop().unwrap();
let y_inv_n_hat = y_inv
.pop()
.expect("couldn't pop y_inv despite y_inv being of same length as times iterated");
let mut L_terms = (a1.clone() * y_inv_n_hat)
.0
@@ -331,7 +333,9 @@ impl WipStatement {
let mut res = Vec::with_capacity(y.len());
res.push(inv_y);
while res.len() < y.len() {
res.push(inv_y * res.last().unwrap());
res.push(
inv_y * res.last().expect("couldn't get last inv_y despite inv_y always being non-empty"),
);
}
res
};