Skip to content

Commit

Permalink
Add DER support
Browse files Browse the repository at this point in the history
  • Loading branch information
recmo committed Oct 14, 2024
1 parent 3a782ce commit b5a9ec7
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/aliases.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ alias! {
// TODO: I0, I1, I8, ... I4096

#[cfg(test)]
pub mod tests {
mod tests {
use super::*;

#[test]
Expand Down
110 changes: 110 additions & 0 deletions src/support/der.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
//! Support for the [`der`](https://crates.io/crates/der) crate.
#![cfg(feature = "der")]
#![cfg_attr(docsrs, doc(cfg(feature = "der")))]

use crate::Uint;
use der::{
asn1::{AnyRef, IntRef, UintRef},
DecodeValue, EncodeValue, Error, FixedTag, Header, Length, Reader, Result, Tag, ValueOrd,
Writer,
};
use std::cmp::Ordering;

impl<const BITS: usize, const LIMBS: usize> ValueOrd for Uint<BITS, LIMBS> {
fn value_cmp(&self, other: &Self) -> Result<Ordering> {
// DER encoding corresponds to integer comparison.
Ok(self.cmp(other))
}
}

impl<const BITS: usize, const LIMBS: usize> FixedTag for Uint<BITS, LIMBS> {
const TAG: Tag = Tag::Integer;
}

impl<const BITS: usize, const LIMBS: usize> EncodeValue for Uint<BITS, LIMBS> {
fn value_len(&self) -> Result<Length> {
(1 + self.bit_len() / 8).try_into()
}

fn encode_value(&self, writer: &mut impl Writer) -> Result<()> {
// Write bytes in big-endian order without leading zeros.
let bytes = self.to_be_bytes_trimmed_vec();
// Add leading `0x00` byte if the first byte has the highest bit set.
// or if the sequence is empty.
if bytes.first().copied().unwrap_or(0x80) >= 0x80 {
writer.write_byte(0x00)?;
}
writer.write(&bytes)
}
}

impl<'a, const BITS: usize, const LIMBS: usize> DecodeValue<'a> for Uint<BITS, LIMBS> {
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> Result<Self> {
if header.length > Length::try_from(Self::BYTES + 1)? {
return Err(Self::TAG.non_canonical_error());
}
let bytes = reader.read_vec(header.length)?;
let bytes = match bytes.as_slice() {
[] => Err(Tag::Integer.length_error()),
[0, byte, ..] if *byte < 0x80 => Err(Tag::Integer.non_canonical_error()),
[0, rest @ ..] => Ok(rest),
[byte, ..] if *byte >= 0x80 => Err(Tag::Integer.value_error()),
bytes => Ok(bytes),
}?;
Self::try_from_be_slice(bytes).ok_or_else(|| Tag::Integer.non_canonical_error())
}
}

impl<const BITS: usize, const LIMBS: usize> TryFrom<AnyRef<'_>> for Uint<BITS, LIMBS> {
type Error = Error;

fn try_from(any: AnyRef<'_>) -> Result<Self> {
any.decode_as()
}
}

impl<const BITS: usize, const LIMBS: usize> TryFrom<IntRef<'_>> for Uint<BITS, LIMBS> {
type Error = Error;

fn try_from(any: IntRef<'_>) -> Result<Self> {
any.decode_as()
}
}

impl<const BITS: usize, const LIMBS: usize> TryFrom<UintRef<'_>> for Uint<BITS, LIMBS> {
type Error = Error;

fn try_from(any: UintRef<'_>) -> Result<Self> {
any.decode_as()
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::{const_for, nlimbs};
use der::{Decode, Encode};
use proptest::proptest;

#[test]
fn test_der_roundtrip() {
const_for!(BITS in SIZES {
const LIMBS: usize = nlimbs(BITS);
proptest!(|(value: Uint<BITS, LIMBS>)| {
let serialized = value.to_der().unwrap();
let deserialized = Uint::from_der(&serialized).unwrap();
assert_eq!(value, deserialized);
});
});
}

#[test]
fn test_u128_equiv() {
proptest!(|(value: u128)| {
let uint = Uint::<128, 2>::from(value);
let serialized1 = value.to_der().unwrap();
let serialized2 = uint.to_der().unwrap();
assert_eq!(serialized1, serialized2);
});
}
}
2 changes: 2 additions & 0 deletions src/support/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod ark_ff;
mod ark_ff_04;
mod bn_rs;
mod bytemuck;
mod der;
mod fastrlp;
mod num_bigint;
mod num_integer;
Expand All @@ -23,6 +24,7 @@ pub mod scale;
mod serde;
pub mod sqlx;
pub mod ssz;
mod subtle;
mod valuable;
mod zeroize;

Expand Down

0 comments on commit b5a9ec7

Please sign in to comment.