Replace Vec<Bulletproofs> with Bulletproofs

Monero uses aggregated range proofs, so there's only ever one Bulletproof. This
is enforced with a consensus rule as well, making this safe.

As for why Monero uses a vec, it's probably due to the lack of variadic typing
used. Its effectively an Option for them, yet we don't need an Option since we
do have variadic typing (enums).
This commit is contained in:
Luke Parker
2023-07-04 11:41:00 -04:00
parent 6fe01d1f15
commit d9f145cd72
2 changed files with 31 additions and 33 deletions

View File

@@ -198,12 +198,12 @@ pub enum RctPrunable {
mlsags: Vec<Mlsag>, mlsags: Vec<Mlsag>,
}, },
MlsagBulletproofs { MlsagBulletproofs {
bulletproofs: Vec<Bulletproofs>, bulletproofs: Bulletproofs,
mlsags: Vec<Mlsag>, mlsags: Vec<Mlsag>,
pseudo_outs: Vec<EdwardsPoint>, pseudo_outs: Vec<EdwardsPoint>,
}, },
Clsag { Clsag {
bulletproofs: Vec<Bulletproofs>, bulletproofs: Bulletproofs,
clsags: Vec<Clsag>, clsags: Vec<Clsag>,
pseudo_outs: Vec<EdwardsPoint>, pseudo_outs: Vec<EdwardsPoint>,
}, },
@@ -224,16 +224,19 @@ impl RctPrunable {
} }
RctPrunable::MlsagBulletproofs { bulletproofs, mlsags, pseudo_outs } => { RctPrunable::MlsagBulletproofs { bulletproofs, mlsags, pseudo_outs } => {
if rct_type == RctType::Bulletproofs { if rct_type == RctType::Bulletproofs {
w.write_all(&u32::try_from(bulletproofs.len()).unwrap().to_le_bytes())?; w.write_all(&1u32.to_le_bytes())?;
} else { } else {
write_varint(&bulletproofs.len().try_into().unwrap(), w)?; w.write_all(&[1])?;
} }
write_raw_vec(Bulletproofs::write, bulletproofs, w)?; bulletproofs.write(w)?;
write_raw_vec(Mlsag::write, mlsags, w)?; write_raw_vec(Mlsag::write, mlsags, w)?;
write_raw_vec(write_point, pseudo_outs, w) write_raw_vec(write_point, pseudo_outs, w)
} }
RctPrunable::Clsag { bulletproofs, clsags, pseudo_outs } => { RctPrunable::Clsag { bulletproofs, clsags, pseudo_outs } => {
write_vec(Bulletproofs::write, bulletproofs, w)?; w.write_all(&[1])?;
bulletproofs.write(w)?;
write_raw_vec(Clsag::write, clsags, w)?; write_raw_vec(Clsag::write, clsags, w)?;
write_raw_vec(write_point, pseudo_outs, w) write_raw_vec(write_point, pseudo_outs, w)
} }
@@ -260,24 +263,30 @@ impl RctPrunable {
}, },
RctType::Bulletproofs | RctType::BulletproofsCompactAmount => { RctType::Bulletproofs | RctType::BulletproofsCompactAmount => {
RctPrunable::MlsagBulletproofs { RctPrunable::MlsagBulletproofs {
bulletproofs: read_raw_vec( bulletproofs: {
Bulletproofs::read, if (if rct_type == RctType::Bulletproofs {
if rct_type == RctType::Bulletproofs { u64::from(read_u32(r)?)
read_u32(r)?.try_into().unwrap()
} else { } else {
read_varint(r)?.try_into().unwrap() read_varint(r)?
}) != 1
{
Err(io::Error::new(io::ErrorKind::Other, "n bulletproofs instead of one"))?;
}
Bulletproofs::read(r)?
}, },
r,
)?,
mlsags: decoys.iter().map(|d| Mlsag::read(*d, r)).collect::<Result<_, _>>()?, mlsags: decoys.iter().map(|d| Mlsag::read(*d, r)).collect::<Result<_, _>>()?,
pseudo_outs: read_raw_vec(read_point, decoys.len(), r)?, pseudo_outs: read_raw_vec(read_point, decoys.len(), r)?,
} }
} }
RctType::Clsag | RctType::BulletproofsPlus => RctPrunable::Clsag { RctType::Clsag | RctType::BulletproofsPlus => RctPrunable::Clsag {
bulletproofs: read_vec( bulletproofs: {
if rct_type == RctType::Clsag { Bulletproofs::read } else { Bulletproofs::read_plus }, if read_varint(r)? != 1 {
Err(io::Error::new(io::ErrorKind::Other, "n bulletproofs instead of one"))?;
}
(if rct_type == RctType::Clsag { Bulletproofs::read } else { Bulletproofs::read_plus })(
r, r,
)?, )?
},
clsags: (0 .. decoys.len()).map(|o| Clsag::read(decoys[o], r)).collect::<Result<_, _>>()?, clsags: (0 .. decoys.len()).map(|o| Clsag::read(decoys[o], r)).collect::<Result<_, _>>()?,
pseudo_outs: read_raw_vec(read_point, decoys.len(), r)?, pseudo_outs: read_raw_vec(read_point, decoys.len(), r)?,
}, },
@@ -290,12 +299,8 @@ impl RctPrunable {
RctPrunable::MlsagBorromean { borromean, .. } => { RctPrunable::MlsagBorromean { borromean, .. } => {
borromean.iter().try_for_each(|rs| rs.write(w)) borromean.iter().try_for_each(|rs| rs.write(w))
} }
RctPrunable::MlsagBulletproofs { bulletproofs, .. } => { RctPrunable::MlsagBulletproofs { bulletproofs, .. } => bulletproofs.signature_write(w),
bulletproofs.iter().try_for_each(|bp| bp.signature_write(w)) RctPrunable::Clsag { bulletproofs, .. } => bulletproofs.signature_write(w),
}
RctPrunable::Clsag { bulletproofs, .. } => {
bulletproofs.iter().try_for_each(|bp| bp.signature_write(w))
}
} }
} }
} }
@@ -352,10 +357,7 @@ impl RctSignatures {
} }
} }
RctPrunable::Clsag { bulletproofs, .. } => { RctPrunable::Clsag { bulletproofs, .. } => {
if matches!( if matches!(bulletproofs, Bulletproofs::Original { .. }) {
bulletproofs.get(0).expect("CLSAG TXs have a 2-output minimum"),
Bulletproofs::Original { .. }
) {
RctType::Clsag RctType::Clsag
} else { } else {
RctType::BulletproofsPlus RctType::BulletproofsPlus

View File

@@ -658,11 +658,7 @@ impl SignableTransaction {
pseudo_outs: vec![], pseudo_outs: vec![],
commitments: commitments.iter().map(|commitment| commitment.calculate()).collect(), commitments: commitments.iter().map(|commitment| commitment.calculate()).collect(),
}, },
prunable: RctPrunable::Clsag { prunable: RctPrunable::Clsag { bulletproofs: bp, clsags: vec![], pseudo_outs: vec![] },
bulletproofs: vec![bp],
clsags: vec![],
pseudo_outs: vec![],
},
}, },
}, },
sum, sum,