use encdec::{DecodeOwned, Encode};
use ledger_proto::ApduError;
use num_enum::TryFromPrimitive;
use rand_core::{CryptoRng, RngCore};
use sha2::{Digest as _, Sha512_256};
use strum::{Display, EnumIter, EnumString, EnumVariantNames};
#[derive(
Copy, Clone, PartialEq, Debug, EnumString, Display, EnumVariantNames, EnumIter, TryFromPrimitive,
)]
#[repr(u8)]
pub enum TxState {
Init = 0x00,
SignMemos = 0x01,
SetMessage = 0x02,
SummaryInit = 0x03,
SummaryAddTxOut = 0x04,
SummaryAddTxIn = 0x05,
SummaryReady = 0x06,
SummaryComplete = 0x07,
Pending = 0x10,
Ready = 0x20,
RingInit = 0x30,
RingBuild = 0x31,
RingSign = 0x32,
RingComplete = 0x33,
TxComplete = 0x40,
TxDenied = 0x41,
IdentPending = 0x50,
IdentApproved = 0x51,
IdentDenied = 0x52,
Error = 0xFF,
}
impl Encode for TxState {
type Error = ApduError;
fn encode_len(&self) -> Result<usize, ApduError> {
Ok(1)
}
fn encode(&self, buff: &mut [u8]) -> Result<usize, ApduError> {
buff[0] = *self as u8;
Ok(1)
}
}
impl DecodeOwned for TxState {
type Output = Self;
type Error = ApduError;
fn decode_owned(buff: &[u8]) -> Result<(Self::Output, usize), ApduError> {
if buff.is_empty() {
return Err(ApduError::InvalidLength);
}
match Self::try_from(buff[0]) {
Ok(v) => Ok((v, 1)),
Err(_) => Err(ApduError::InvalidEncoding),
}
}
}
#[derive(Clone, PartialEq, Encode)]
pub struct Digest([u8; 32]);
impl Digest {
pub const fn new() -> Self {
Self([0u8; 32])
}
#[inline(never)]
pub fn from_random<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
let mut b = [0u8; 32];
rng.fill_bytes(&mut b);
let r = Sha512_256::new().chain_update(b).finalize();
b.copy_from_slice(r.as_ref());
Self(b)
}
#[inline(never)]
pub fn update(&mut self, evt: &[u8; 32]) -> &Self {
let mut d = Sha512_256::new();
d.update(self.0);
d.update(evt);
self.0.copy_from_slice(d.finalize().as_ref());
self
}
}
impl core::fmt::Debug for Digest {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
for b in &self.0[..] {
write!(f, "{b:02x}")?;
}
Ok(())
}
}
impl core::fmt::Display for Digest {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
for b in &self.0[..] {
write!(f, "{b:02x}")?;
}
Ok(())
}
}
impl DecodeOwned for Digest {
type Output = Digest;
type Error = encdec::Error;
fn decode_owned(buff: &[u8]) -> Result<(Self::Output, usize), Self::Error> {
if buff.len() < 32 {
return Err(encdec::Error::Length);
}
let mut d = [0u8; 32];
d.copy_from_slice(&buff[..32]);
Ok((Self(d), 32))
}
}