Skip to content

Commit ca242b3

Browse files
committed
Allow unsafe deserialization of AllowedConversions.
1 parent 515f4ff commit ca242b3

File tree

1 file changed

+29
-12
lines changed

1 file changed

+29
-12
lines changed

masp_primitives/src/convert.rs

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -143,20 +143,18 @@ impl BorshSerialize for AllowedConversion {
143143
}
144144

145145
impl BorshDeserialize for AllowedConversion {
146-
/// This deserialization is unsafe because it does not do the expensive
147-
/// computation of checking whether the asset generator corresponds to the
148-
/// deserialized amount.
149146
fn deserialize_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
150-
let assets = I128Sum::read(reader)?;
151-
let gen_bytes =
152-
<<jubjub::ExtendedPoint as GroupEncoding>::Repr as BorshDeserialize>::deserialize_reader(reader)?;
153-
let generator = Option::from(jubjub::ExtendedPoint::from_bytes(&gen_bytes))
154-
.ok_or_else(|| io::Error::from(io::ErrorKind::InvalidData))?;
155-
let allowed_conversion: AllowedConversion = assets.clone().into();
156-
if allowed_conversion.generator != generator {
157-
return Err(io::Error::from(io::ErrorKind::InvalidData));
147+
// Use the unchecked reader to ensure that same format is supported
148+
let unchecked_conv = UncheckedAllowedConversion::deserialize_reader(reader)?.0;
149+
// Recompute the generator using only the value sum
150+
let safe_conv: AllowedConversion = unchecked_conv.assets.clone().into();
151+
// Check that the computed generator is identical to what was read
152+
if safe_conv.generator == unchecked_conv.generator {
153+
Ok(safe_conv)
154+
} else {
155+
// The generators do not match, so the bytes cannot be from Self::serialize
156+
Err(io::Error::from(io::ErrorKind::InvalidData))
158157
}
159-
Ok(AllowedConversion { assets, generator })
160158
}
161159
}
162160

@@ -213,6 +211,25 @@ impl Sum for AllowedConversion {
213211
}
214212
}
215213

214+
/// A seprate type to allow unchecked deserializations of AllowedConversions
215+
#[derive(Clone, Debug, PartialEq, Eq)]
216+
pub struct UncheckedAllowedConversion(pub AllowedConversion);
217+
218+
impl BorshDeserialize for UncheckedAllowedConversion {
219+
/// This deserialization is unchecked because it does not do the expensive
220+
/// computation of checking whether the asset generator corresponds to the
221+
/// deserialized amount.
222+
fn deserialize_reader<R: io::Read>(reader: &mut R) -> io::Result<Self> {
223+
let assets = I128Sum::read(reader)?;
224+
let gen_bytes =
225+
<<jubjub::ExtendedPoint as GroupEncoding>::Repr as BorshDeserialize>::deserialize_reader(reader)?;
226+
let generator = Option::from(jubjub::ExtendedPoint::from_bytes(&gen_bytes))
227+
.ok_or_else(|| io::Error::from(io::ErrorKind::InvalidData))?;
228+
// Assume that the generator just read corresponds to the value sum
229+
Ok(Self(AllowedConversion { assets, generator }))
230+
}
231+
}
232+
216233
#[cfg(test)]
217234
mod tests {
218235
use crate::asset_type::AssetType;

0 commit comments

Comments
 (0)