Skip to content

Commit

Permalink
More casts and docs
Browse files Browse the repository at this point in the history
  • Loading branch information
recmo committed Oct 14, 2024
1 parent 6f53ba9 commit 04b2dfb
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 7 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Added support for [`subtle`](https://docs.rs/subtle).
- Added support for [`der`](https://docs.rs/der).

## [1.12.3] - 2024-06-03

### Changed
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ named feature flag.
* [`bn-rs`](https://docs.rs/bn-rs/latest/bn_rs/): Implements conversion to/from the [`BN`](https://docs.rs/bn-rs/latest/bn_rs/struct.BN.html) and [`BigNumber`](https://docs.rs/bn-rs/latest/bn_rs/struct.BigNumber.html).
* [`bytemuck`](https://docs.rs/bytemuck): Implements the [`Pod`](https://docs.rs/bytemuck/latest/bytemuck/trait.Pod.html) and [`Zeroable`](https://docs.rs/bytemuck/latest/bytemuck/trait.Zeroable.html) traits for [`Uint`] where the size is a multiple of 64, up to 1024. This allows `Uint` to be used where a `Pod` trait bound exists.
* [`num-traits`](https://docs.rs/num-traits): Implements about forty applicable traits.
* [`subtle`](https://docs.rs/subtle): Implements [`ConditionallySelectable`](https://docs.rs/subtle/latest/subtle/trait.ConditionallySelectable.html),[`ConditionallyNegatable`](https://docs.rs/subtle/latest/subtle/trait.ConditionallyNegatable.html), [`ConstantTimeEq`](https://docs.rs/subtle/latest/subtle/trait.ConstantTimeEq.html)/[`ConstantTimeGreater`](https://docs.rs/subtle/latest/subtle/trait.ConstantTimeGreater.html)/[`ConstantTimeLess`](https://docs.rs/subtle/latest/subtle/trait.ConstantTimeLess.html).
* [`der`](https://docs.rs/der): Implements [`Encode`](https://docs.rs/der/latest/der/trait.Encode.html)/[`Decode`](https://docs.rs/der/latest/der/trait.Decode.html) and [`TryFrom`]/[`From`] casting for [`Any`](https://docs.rs/der/latest/der/asn1/struct.Any.html), [`AnyRef`](https://docs.rs/der/latest/der/asn1/struct.AnyRef.html), [`Int`](https://docs.rs/der/latest/der/asn1/struct.Int.html), [`IntRef`](https://docs.rs/der/latest/der/asn1/struct.IntRef.html), [`Uint`](https://docs.rs/der/latest/der/asn1/struct.Uint.html), [`UintRef`](https://docs.rs/der/latest/der/asn1/struct.UintRef.html).

## Building and testing

Expand Down
97 changes: 90 additions & 7 deletions src/support/der.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,30 +71,93 @@ impl<const BITS: usize, const LIMBS: usize> TryFrom<UintRef<'_>> for Uint<BITS,
}
}

impl<const BITS: usize, const LIMBS: usize> TryFrom<Any> for Uint<BITS, LIMBS> {
impl<const BITS: usize, const LIMBS: usize> TryFrom<&Any> for Uint<BITS, LIMBS> {
type Error = Error;

fn try_from(any: Any) -> Result<Self> {
fn try_from(any: &Any) -> Result<Self> {
any.decode_as()
}
}

impl<const BITS: usize, const LIMBS: usize> TryFrom<Int> for Uint<BITS, LIMBS> {
impl<const BITS: usize, const LIMBS: usize> TryFrom<&Int> for Uint<BITS, LIMBS> {
type Error = Error;

fn try_from(int: Int) -> Result<Self> {
fn try_from(int: &Int) -> Result<Self> {
from_der_slice(int.as_bytes())
}
}

impl<const BITS: usize, const LIMBS: usize> TryFrom<DerUint> for Uint<BITS, LIMBS> {
impl<const BITS: usize, const LIMBS: usize> TryFrom<&DerUint> for Uint<BITS, LIMBS> {
type Error = Error;

fn try_from(uint: DerUint) -> Result<Self> {
fn try_from(uint: &DerUint) -> Result<Self> {
from_der_uint_slice(uint.as_bytes())
}
}

impl<const BITS: usize, const LIMBS: usize> From<&Uint<BITS, LIMBS>> for Any {
fn from(uint: &Uint<BITS, LIMBS>) -> Self {
if uint.is_zero() {
Self::new(Tag::Integer, Box::new([0_u8]) as Box<[u8]>).unwrap()
} else {
let mut bytes = uint.to_be_bytes_trimmed_vec();
if bytes[0] >= 0x80 {
bytes.insert(0, 0);
}
Self::new(Tag::Integer, bytes).unwrap()
}
}
}

impl<const BITS: usize, const LIMBS: usize> From<&Uint<BITS, LIMBS>> for Int {
fn from(uint: &Uint<BITS, LIMBS>) -> Self {
if uint.is_zero() {
Self::new(&[0]).unwrap()
} else {
let mut bytes = uint.to_be_bytes_trimmed_vec();
if bytes[0] >= 0x80 {
bytes.insert(0, 0);
}
Self::new(&bytes).unwrap()
}
}
}

impl<const BITS: usize, const LIMBS: usize> From<&Uint<BITS, LIMBS>> for DerUint {
fn from(uint: &Uint<BITS, LIMBS>) -> Self {
if uint.is_zero() {
Self::new(&[0]).unwrap()
} else {
// Panics:
// The only error is if the length is more than can be represented in u32.
// This is well outside of the inteded usecase for this library.
Self::new(&uint.to_be_bytes_trimmed_vec()).unwrap()
}
}
}

macro_rules! forward_ref {
($ty:ty) => {
impl<const BITS: usize, const LIMBS: usize> TryFrom<$ty> for Uint<BITS, LIMBS> {
type Error = Error;

fn try_from(obj: $ty) -> Result<Self> {
Self::try_from(&obj)
}
}

impl<const BITS: usize, const LIMBS: usize> From<Uint<BITS, LIMBS>> for $ty {
fn from(uint: Uint<BITS, LIMBS>) -> Self {
<$ty>::from(&uint)
}
}
};
}

forward_ref!(Any);
forward_ref!(Int);
forward_ref!(DerUint);

fn from_der_slice<const BITS: usize, const LIMBS: usize>(
bytes: &[u8],
) -> Result<Uint<BITS, LIMBS>> {
Expand Down Expand Up @@ -164,7 +227,7 @@ mod tests {
});
});
}
};
}
}

test_roundtrip!(test_der_anyref_roundtrip, AnyRef);
Expand All @@ -173,4 +236,24 @@ mod tests {
test_roundtrip!(test_der_any_roundtrip, Any);
test_roundtrip!(test_der_int_roundtrip, Int);
test_roundtrip!(test_der_uint_roundtrip, DerUint);

macro_rules! test_into {
($name:ident, $ty:ty) => {
#[test]
fn $name() {
const_for!(BITS in SIZES {
const LIMBS: usize = nlimbs(BITS);
proptest!(|(value: Uint<BITS, LIMBS>)| {
let obj: $ty = value.into();
let result: Uint<BITS, LIMBS> = obj.try_into().unwrap();
assert_eq!(result, value);
});
});
}
}
}

test_into!(test_into_any, Any);
test_into!(test_into_int, Int);
test_into!(test_into_uint, DerUint);
}
17 changes: 17 additions & 0 deletions src/support/subtle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ mod tests {
use super::*;
use crate::{const_for, nlimbs};
use proptest::proptest;
use subtle::ConditionallyNegatable;

#[test]
fn test_select() {
Expand All @@ -86,6 +87,22 @@ mod tests {
});
});
}

#[test]
fn test_negate() {
const_for!(BITS in SIZES {
const LIMBS: usize = nlimbs(BITS);
type U = Uint<BITS, LIMBS>;
proptest!(|(a: U, c: bool)| {
let choice = Choice::from(c as u8);
let mut r = a;
r.conditional_negate(choice);
let e = if c { -a } else { a };
assert_eq!(r, e);
});
});
}

#[test]
fn test_eq() {
const_for!(BITS in SIZES {
Expand Down

0 comments on commit 04b2dfb

Please sign in to comment.