Skip to content

Commit

Permalink
Rpo256: Add RpoDigest conversions (#311)
Browse files Browse the repository at this point in the history
  • Loading branch information
hackaugusto authored May 6, 2024
1 parent 2b6d8d1 commit ae22edc
Show file tree
Hide file tree
Showing 3 changed files with 474 additions and 143 deletions.
292 changes: 227 additions & 65 deletions src/hash/rescue/rpo/digest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,26 +118,106 @@ impl Randomizable for RpoDigest {
// CONVERSIONS: FROM RPO DIGEST
// ================================================================================================

impl From<&RpoDigest> for [Felt; DIGEST_SIZE] {
fn from(value: &RpoDigest) -> Self {
value.0
#[derive(Copy, Clone, Debug)]
pub enum RpoDigestError {
InvalidInteger,
}

impl TryFrom<&RpoDigest> for [bool; DIGEST_SIZE] {
type Error = RpoDigestError;

fn try_from(value: &RpoDigest) -> Result<Self, Self::Error> {
(*value).try_into()
}
}

impl From<RpoDigest> for [Felt; DIGEST_SIZE] {
fn from(value: RpoDigest) -> Self {
value.0
impl TryFrom<RpoDigest> for [bool; DIGEST_SIZE] {
type Error = RpoDigestError;

fn try_from(value: RpoDigest) -> Result<Self, Self::Error> {
fn to_bool(v: u64) -> Option<bool> {
if v <= 1 {
Some(v == 1)
} else {
None
}
}

Ok([
to_bool(value.0[0].as_int()).ok_or(RpoDigestError::InvalidInteger)?,
to_bool(value.0[1].as_int()).ok_or(RpoDigestError::InvalidInteger)?,
to_bool(value.0[2].as_int()).ok_or(RpoDigestError::InvalidInteger)?,
to_bool(value.0[3].as_int()).ok_or(RpoDigestError::InvalidInteger)?,
])
}
}

impl TryFrom<&RpoDigest> for [u8; DIGEST_SIZE] {
type Error = RpoDigestError;

fn try_from(value: &RpoDigest) -> Result<Self, Self::Error> {
(*value).try_into()
}
}

impl TryFrom<RpoDigest> for [u8; DIGEST_SIZE] {
type Error = RpoDigestError;

fn try_from(value: RpoDigest) -> Result<Self, Self::Error> {
Ok([
value.0[0].as_int().try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
value.0[1].as_int().try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
value.0[2].as_int().try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
value.0[3].as_int().try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
])
}
}

impl TryFrom<&RpoDigest> for [u16; DIGEST_SIZE] {
type Error = RpoDigestError;

fn try_from(value: &RpoDigest) -> Result<Self, Self::Error> {
(*value).try_into()
}
}

impl TryFrom<RpoDigest> for [u16; DIGEST_SIZE] {
type Error = RpoDigestError;

fn try_from(value: RpoDigest) -> Result<Self, Self::Error> {
Ok([
value.0[0].as_int().try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
value.0[1].as_int().try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
value.0[2].as_int().try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
value.0[3].as_int().try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
])
}
}

impl TryFrom<&RpoDigest> for [u32; DIGEST_SIZE] {
type Error = RpoDigestError;

fn try_from(value: &RpoDigest) -> Result<Self, Self::Error> {
(*value).try_into()
}
}

impl TryFrom<RpoDigest> for [u32; DIGEST_SIZE] {
type Error = RpoDigestError;

fn try_from(value: RpoDigest) -> Result<Self, Self::Error> {
Ok([
value.0[0].as_int().try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
value.0[1].as_int().try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
value.0[2].as_int().try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
value.0[3].as_int().try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
])
}
}

impl From<&RpoDigest> for [u64; DIGEST_SIZE] {
fn from(value: &RpoDigest) -> Self {
[
value.0[0].as_int(),
value.0[1].as_int(),
value.0[2].as_int(),
value.0[3].as_int(),
]
(*value).into()
}
}

Expand All @@ -152,9 +232,21 @@ impl From<RpoDigest> for [u64; DIGEST_SIZE] {
}
}

impl From<&RpoDigest> for [Felt; DIGEST_SIZE] {
fn from(value: &RpoDigest) -> Self {
(*value).into()
}
}

impl From<RpoDigest> for [Felt; DIGEST_SIZE] {
fn from(value: RpoDigest) -> Self {
value.0
}
}

impl From<&RpoDigest> for [u8; DIGEST_BYTES] {
fn from(value: &RpoDigest) -> Self {
value.as_bytes()
(*value).into()
}
}

Expand All @@ -164,27 +256,90 @@ impl From<RpoDigest> for [u8; DIGEST_BYTES] {
}
}

impl From<&RpoDigest> for String {
/// The returned string starts with `0x`.
fn from(value: &RpoDigest) -> Self {
(*value).into()
}
}

impl From<RpoDigest> for String {
/// The returned string starts with `0x`.
fn from(value: RpoDigest) -> Self {
value.to_hex()
}
}

impl From<&RpoDigest> for String {
/// The returned string starts with `0x`.
fn from(value: &RpoDigest) -> Self {
// CONVERSIONS: TO RPO DIGEST
// ================================================================================================

impl From<&[bool; DIGEST_SIZE]> for RpoDigest {
fn from(value: &[bool; DIGEST_SIZE]) -> Self {
(*value).into()
}
}

// CONVERSIONS: TO RPO DIGEST
// ================================================================================================
impl From<[bool; DIGEST_SIZE]> for RpoDigest {
fn from(value: [bool; DIGEST_SIZE]) -> Self {
[value[0] as u32, value[1] as u32, value[2] as u32, value[3] as u32].into()
}
}

#[derive(Copy, Clone, Debug)]
pub enum RpoDigestError {
/// The provided u64 integer does not fit in the field's moduli.
InvalidInteger,
impl From<&[u8; DIGEST_SIZE]> for RpoDigest {
fn from(value: &[u8; DIGEST_SIZE]) -> Self {
(*value).into()
}
}

impl From<[u8; DIGEST_SIZE]> for RpoDigest {
fn from(value: [u8; DIGEST_SIZE]) -> Self {
Self([value[0].into(), value[1].into(), value[2].into(), value[3].into()])
}
}

impl From<&[u16; DIGEST_SIZE]> for RpoDigest {
fn from(value: &[u16; DIGEST_SIZE]) -> Self {
(*value).into()
}
}

impl From<[u16; DIGEST_SIZE]> for RpoDigest {
fn from(value: [u16; DIGEST_SIZE]) -> Self {
Self([value[0].into(), value[1].into(), value[2].into(), value[3].into()])
}
}

impl From<&[u32; DIGEST_SIZE]> for RpoDigest {
fn from(value: &[u32; DIGEST_SIZE]) -> Self {
(*value).into()
}
}

impl From<[u32; DIGEST_SIZE]> for RpoDigest {
fn from(value: [u32; DIGEST_SIZE]) -> Self {
Self([value[0].into(), value[1].into(), value[2].into(), value[3].into()])
}
}

impl TryFrom<&[u64; DIGEST_SIZE]> for RpoDigest {
type Error = RpoDigestError;

fn try_from(value: &[u64; DIGEST_SIZE]) -> Result<Self, RpoDigestError> {
(*value).try_into()
}
}

impl TryFrom<[u64; DIGEST_SIZE]> for RpoDigest {
type Error = RpoDigestError;

fn try_from(value: [u64; DIGEST_SIZE]) -> Result<Self, RpoDigestError> {
Ok(Self([
value[0].try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
value[1].try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
value[2].try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
value[3].try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
]))
}
}

impl From<&[Felt; DIGEST_SIZE]> for RpoDigest {
Expand All @@ -199,6 +354,14 @@ impl From<[Felt; DIGEST_SIZE]> for RpoDigest {
}
}

impl TryFrom<&[u8; DIGEST_BYTES]> for RpoDigest {
type Error = HexParseError;

fn try_from(value: &[u8; DIGEST_BYTES]) -> Result<Self, Self::Error> {
(*value).try_into()
}
}

impl TryFrom<[u8; DIGEST_BYTES]> for RpoDigest {
type Error = HexParseError;

Expand All @@ -218,14 +381,6 @@ impl TryFrom<[u8; DIGEST_BYTES]> for RpoDigest {
}
}

impl TryFrom<&[u8; DIGEST_BYTES]> for RpoDigest {
type Error = HexParseError;

fn try_from(value: &[u8; DIGEST_BYTES]) -> Result<Self, Self::Error> {
(*value).try_into()
}
}

impl TryFrom<&[u8]> for RpoDigest {
type Error = HexParseError;

Expand All @@ -234,33 +389,12 @@ impl TryFrom<&[u8]> for RpoDigest {
}
}

impl TryFrom<[u64; DIGEST_SIZE]> for RpoDigest {
type Error = RpoDigestError;

fn try_from(value: [u64; DIGEST_SIZE]) -> Result<Self, RpoDigestError> {
Ok(Self([
value[0].try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
value[1].try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
value[2].try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
value[3].try_into().map_err(|_| RpoDigestError::InvalidInteger)?,
]))
}
}

impl TryFrom<&[u64; DIGEST_SIZE]> for RpoDigest {
type Error = RpoDigestError;

fn try_from(value: &[u64; DIGEST_SIZE]) -> Result<Self, RpoDigestError> {
(*value).try_into()
}
}

impl TryFrom<&str> for RpoDigest {
type Error = HexParseError;

/// Expects the string to start with `0x`.
fn try_from(value: &str) -> Result<Self, Self::Error> {
hex_to_bytes(value).and_then(|v| v.try_into())
hex_to_bytes::<DIGEST_BYTES>(value).and_then(RpoDigest::try_from)
}
}

Expand Down Expand Up @@ -373,43 +507,71 @@ mod tests {
Felt::new(rand_value()),
]);

let v: [Felt; DIGEST_SIZE] = digest.into();
// BY VALUE
// ----------------------------------------------------------------------------------------
let v: [bool; DIGEST_SIZE] = [true, false, true, true];
let v2: RpoDigest = v.into();
assert_eq!(digest, v2);
assert_eq!(v, <[bool; DIGEST_SIZE]>::try_from(v2).unwrap());

let v: [Felt; DIGEST_SIZE] = (&digest).into();
let v: [u8; DIGEST_SIZE] = [0_u8, 1_u8, 2_u8, 3_u8];
let v2: RpoDigest = v.into();
assert_eq!(digest, v2);
assert_eq!(v, <[u8; DIGEST_SIZE]>::try_from(v2).unwrap());

let v: [u16; DIGEST_SIZE] = [0_u16, 1_u16, 2_u16, 3_u16];
let v2: RpoDigest = v.into();
assert_eq!(v, <[u16; DIGEST_SIZE]>::try_from(v2).unwrap());

let v: [u32; DIGEST_SIZE] = [0_u32, 1_u32, 2_u32, 3_u32];
let v2: RpoDigest = v.into();
assert_eq!(v, <[u32; DIGEST_SIZE]>::try_from(v2).unwrap());

let v: [u64; DIGEST_SIZE] = digest.into();
let v2: RpoDigest = v.try_into().unwrap();
assert_eq!(digest, v2);

let v: [u64; DIGEST_SIZE] = (&digest).into();
let v2: RpoDigest = v.try_into().unwrap();
let v: [Felt; DIGEST_SIZE] = digest.into();
let v2: RpoDigest = v.into();
assert_eq!(digest, v2);

let v: [u8; DIGEST_BYTES] = digest.into();
let v2: RpoDigest = v.try_into().unwrap();
assert_eq!(digest, v2);

let v: [u8; DIGEST_BYTES] = (&digest).into();
let v: String = digest.into();
let v2: RpoDigest = v.try_into().unwrap();
assert_eq!(digest, v2);

let v: String = digest.into();
let v2: RpoDigest = v.try_into().unwrap();
// BY REF
// ----------------------------------------------------------------------------------------
let v: [bool; DIGEST_SIZE] = [true, false, true, true];
let v2: RpoDigest = (&v).into();
assert_eq!(v, <[bool; DIGEST_SIZE]>::try_from(&v2).unwrap());

let v: [u8; DIGEST_SIZE] = [0_u8, 1_u8, 2_u8, 3_u8];
let v2: RpoDigest = (&v).into();
assert_eq!(v, <[u8; DIGEST_SIZE]>::try_from(&v2).unwrap());

let v: [u16; DIGEST_SIZE] = [0_u16, 1_u16, 2_u16, 3_u16];
let v2: RpoDigest = (&v).into();
assert_eq!(v, <[u16; DIGEST_SIZE]>::try_from(&v2).unwrap());

let v: [u32; DIGEST_SIZE] = [0_u32, 1_u32, 2_u32, 3_u32];
let v2: RpoDigest = (&v).into();
assert_eq!(v, <[u32; DIGEST_SIZE]>::try_from(&v2).unwrap());

let v: [u64; DIGEST_SIZE] = (&digest).into();
let v2: RpoDigest = (&v).try_into().unwrap();
assert_eq!(digest, v2);

let v: String = (&digest).into();
let v2: RpoDigest = v.try_into().unwrap();
let v: [Felt; DIGEST_SIZE] = (&digest).into();
let v2: RpoDigest = (&v).into();
assert_eq!(digest, v2);

let v: [u8; DIGEST_BYTES] = digest.into();
let v: [u8; DIGEST_BYTES] = (&digest).into();
let v2: RpoDigest = (&v).try_into().unwrap();
assert_eq!(digest, v2);

let v: [u8; DIGEST_BYTES] = (&digest).into();
let v: String = (&digest).into();
let v2: RpoDigest = (&v).try_into().unwrap();
assert_eq!(digest, v2);
}
Expand Down
Loading

0 comments on commit ae22edc

Please sign in to comment.