diff options
Diffstat (limited to 'vendor/crypto-bigint/src/uint/encoding')
-rw-r--r-- | vendor/crypto-bigint/src/uint/encoding/der.rs | 69 | ||||
-rw-r--r-- | vendor/crypto-bigint/src/uint/encoding/rlp.rs | 79 |
2 files changed, 148 insertions, 0 deletions
diff --git a/vendor/crypto-bigint/src/uint/encoding/der.rs b/vendor/crypto-bigint/src/uint/encoding/der.rs new file mode 100644 index 000000000..cf1b9c31e --- /dev/null +++ b/vendor/crypto-bigint/src/uint/encoding/der.rs @@ -0,0 +1,69 @@ +//! Support for decoding/encoding [`UInt`] as an ASN.1 DER `INTEGER`. + +use crate::{generic_array::GenericArray, ArrayEncoding, UInt}; +use ::der::{ + asn1::{AnyRef, UIntRef}, + DecodeValue, EncodeValue, FixedTag, Length, Tag, +}; + +#[cfg_attr(docsrs, doc(cfg(feature = "der")))] +impl<'a, const LIMBS: usize> TryFrom<AnyRef<'a>> for UInt<LIMBS> +where + UInt<LIMBS>: ArrayEncoding, +{ + type Error = der::Error; + + fn try_from(any: AnyRef<'a>) -> der::Result<UInt<LIMBS>> { + UIntRef::try_from(any)?.try_into() + } +} + +#[cfg_attr(docsrs, doc(cfg(feature = "der")))] +impl<'a, const LIMBS: usize> TryFrom<UIntRef<'a>> for UInt<LIMBS> +where + UInt<LIMBS>: ArrayEncoding, +{ + type Error = der::Error; + + fn try_from(bytes: UIntRef<'a>) -> der::Result<UInt<LIMBS>> { + let mut array = GenericArray::default(); + let offset = array.len().saturating_sub(bytes.len().try_into()?); + array[offset..].copy_from_slice(bytes.as_bytes()); + Ok(UInt::from_be_byte_array(array)) + } +} + +#[cfg_attr(docsrs, doc(cfg(feature = "der")))] +impl<'a, const LIMBS: usize> DecodeValue<'a> for UInt<LIMBS> +where + UInt<LIMBS>: ArrayEncoding, +{ + fn decode_value<R: der::Reader<'a>>(reader: &mut R, header: der::Header) -> der::Result<Self> { + UIntRef::decode_value(reader, header)?.try_into() + } +} + +#[cfg_attr(docsrs, doc(cfg(feature = "der")))] +impl<const LIMBS: usize> EncodeValue for UInt<LIMBS> +where + UInt<LIMBS>: ArrayEncoding, +{ + fn value_len(&self) -> der::Result<Length> { + // TODO(tarcieri): more efficient length calculation + let array = self.to_be_byte_array(); + UIntRef::new(&array)?.value_len() + } + + fn encode_value(&self, encoder: &mut dyn der::Writer) -> der::Result<()> { + let array = self.to_be_byte_array(); + UIntRef::new(&array)?.encode_value(encoder) + } +} + +#[cfg_attr(docsrs, doc(cfg(feature = "der")))] +impl<const LIMBS: usize> FixedTag for UInt<LIMBS> +where + UInt<LIMBS>: ArrayEncoding, +{ + const TAG: Tag = Tag::Integer; +} diff --git a/vendor/crypto-bigint/src/uint/encoding/rlp.rs b/vendor/crypto-bigint/src/uint/encoding/rlp.rs new file mode 100644 index 000000000..8a10170d5 --- /dev/null +++ b/vendor/crypto-bigint/src/uint/encoding/rlp.rs @@ -0,0 +1,79 @@ +//! Recursive Length Prefix (RLP) encoding support. + +use crate::{Encoding, UInt}; +use rlp::{DecoderError, Rlp, RlpStream}; + +#[cfg_attr(docsrs, doc(cfg(feature = "rlp")))] +impl<const LIMBS: usize> rlp::Encodable for UInt<LIMBS> +where + Self: Encoding, +{ + fn rlp_append(&self, stream: &mut RlpStream) { + let bytes = self.to_be_bytes(); + let mut bytes_stripped = bytes.as_ref(); + + while bytes_stripped.first().cloned() == Some(0) { + bytes_stripped = &bytes_stripped[1..]; + } + + stream.encoder().encode_value(bytes_stripped); + } +} + +#[cfg_attr(docsrs, doc(cfg(feature = "rlp")))] +impl<const LIMBS: usize> rlp::Decodable for UInt<LIMBS> +where + Self: Encoding, + <Self as Encoding>::Repr: Default, +{ + fn decode(rlp: &Rlp<'_>) -> Result<Self, DecoderError> { + rlp.decoder().decode_value(|bytes| { + if bytes.first().cloned() == Some(0) { + Err(rlp::DecoderError::RlpInvalidIndirection) + } else { + let mut repr = <Self as Encoding>::Repr::default(); + let offset = repr + .as_ref() + .len() + .checked_sub(bytes.len()) + .ok_or(DecoderError::RlpIsTooBig)?; + + repr.as_mut()[offset..].copy_from_slice(bytes); + Ok(Self::from_be_bytes(repr)) + } + }) + } +} + +#[cfg(test)] +mod tests { + use crate::U256; + use hex_literal::hex; + + /// U256 test vectors from the `rlp` crate. + /// + /// <https://github.com/paritytech/parity-common/blob/faad8b6/rlp/tests/tests.rs#L216-L222> + const U256_VECTORS: &[(U256, &[u8])] = &[ + (U256::ZERO, &hex!("80")), + ( + U256::from_be_hex("0000000000000000000000000000000000000000000000000000000001000000"), + &hex!("8401000000"), + ), + ( + U256::from_be_hex("00000000000000000000000000000000000000000000000000000000ffffffff"), + &hex!("84ffffffff"), + ), + ( + U256::from_be_hex("8090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0"), + &hex!("a08090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0"), + ), + ]; + + #[test] + fn round_trip() { + for &(uint, expected_bytes) in U256_VECTORS { + assert_eq!(rlp::encode(&uint), expected_bytes); + assert_eq!(rlp::decode::<U256>(expected_bytes).unwrap(), uint); + } + } +} |