Require that compactsize encodings are canonical.
This commit is contained in:
parent
68a6837cc1
commit
f00c16a624
|
|
@ -173,13 +173,23 @@ pub trait ReadZcashExt: io::Read {
|
||||||
/// );
|
/// );
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
fn read_compactsize(&mut self) -> io::Result<u64> {
|
fn read_compactsize(&mut self) -> Result<u64, SerializationError> {
|
||||||
|
use SerializationError::Parse;
|
||||||
let flag_byte = self.read_u8()?;
|
let flag_byte = self.read_u8()?;
|
||||||
match flag_byte {
|
match flag_byte {
|
||||||
0xff => self.read_u64::<LittleEndian>(),
|
n @ 0x00..=0xfc => Ok(n as u64),
|
||||||
0xfe => Ok(self.read_u32::<LittleEndian>()? as u64),
|
0xfd => match self.read_u16::<LittleEndian>()? {
|
||||||
0xfd => Ok(self.read_u16::<LittleEndian>()? as u64),
|
n @ 0x0000_00fd..=0x0000_ffff => Ok(n as u64),
|
||||||
n => Ok(n as u64),
|
_ => Err(Parse("non-canonical compactsize")),
|
||||||
|
},
|
||||||
|
0xfe => match self.read_u32::<LittleEndian>()? {
|
||||||
|
n @ 0x0001_0000..=0xffff_ffff => Ok(n as u64),
|
||||||
|
_ => Err(Parse("non-canonical compactsize")),
|
||||||
|
},
|
||||||
|
0xff => match self.read_u64::<LittleEndian>()? {
|
||||||
|
n @ 0x1_0000_0000..=0xffff_ffff_ffff_ffff => Ok(n),
|
||||||
|
_ => Err(Parse("non-canonical compactsize")),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -208,11 +218,11 @@ pub trait ReadZcashExt: io::Read {
|
||||||
|
|
||||||
/// Read a Bitcoin-encoded UTF-8 string.
|
/// Read a Bitcoin-encoded UTF-8 string.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn read_string(&mut self) -> io::Result<String> {
|
fn read_string(&mut self) -> Result<String, SerializationError> {
|
||||||
let len = self.read_compactsize()?;
|
let len = self.read_compactsize()?;
|
||||||
let mut buf = vec![0; len as usize];
|
let mut buf = vec![0; len as usize];
|
||||||
self.read_exact(&mut buf)?;
|
self.read_exact(&mut buf)?;
|
||||||
String::from_utf8(buf).map_err(|_| io::ErrorKind::InvalidData.into())
|
String::from_utf8(buf).map_err(|_| SerializationError::Parse("invalid utf-8"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convenience method to read a `[u8; 4]`.
|
/// Convenience method to read a `[u8; 4]`.
|
||||||
|
|
@ -296,16 +306,18 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn compactsize_read_then_write_round_trip(bytes in prop::array::uniform9(0u8..)) {
|
fn compactsize_read_then_write_round_trip(bytes in prop::array::uniform9(0u8..)) {
|
||||||
let s = Cursor::new(&bytes[..]).read_compactsize().unwrap();
|
// Only do the test if the bytes were valid.
|
||||||
// The compactsize encoding is variable-length, so we may not even
|
if let Ok(s) = Cursor::new(&bytes[..]).read_compactsize() {
|
||||||
// read all of the input bytes, and therefore we can't expect that
|
// The compactsize encoding is variable-length, so we may not even
|
||||||
// the encoding will reproduce bytes that were never read. Instead,
|
// read all of the input bytes, and therefore we can't expect that
|
||||||
// copy the input bytes, and overwrite them with the encoding of s,
|
// the encoding will reproduce bytes that were never read. Instead,
|
||||||
// so that if the encoding is different, we'll catch it on the part
|
// copy the input bytes, and overwrite them with the encoding of s,
|
||||||
// that's written.
|
// so that if the encoding is different, we'll catch it on the part
|
||||||
let mut expect_bytes = bytes.clone();
|
// that's written.
|
||||||
Cursor::new(&mut expect_bytes[..]).write_compactsize(s).unwrap();
|
let mut expect_bytes = bytes.clone();
|
||||||
prop_assert_eq!(bytes, expect_bytes);
|
Cursor::new(&mut expect_bytes[..]).write_compactsize(s).unwrap();
|
||||||
|
prop_assert_eq!(bytes, expect_bytes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue