use crate::ValidationError;
use subtle::ConstantTimeEq;
use zeroize::Zeroize;
#[derive(Clone, Copy, Eq)]
pub struct Digest([u8; Self::LEN]);
impl Digest {
pub const LEN: usize = 32;
#[must_use]
pub const fn new(bytes: [u8; Self::LEN]) -> Self {
Self(bytes)
}
#[must_use]
pub const fn as_bytes(&self) -> &[u8; Self::LEN] {
&self.0
}
#[must_use]
pub fn is_zero(&self) -> bool {
bool::from(self.0.ct_eq(&[0u8; Self::LEN]))
}
#[must_use]
pub fn ct_eq(&self, other: &Self) -> bool {
bool::from(self.0.ct_eq(&other.0))
}
}
impl PartialEq for Digest {
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other)
}
}
impl core::hash::Hash for Digest {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
core::hash::Hash::hash(&self.0, state);
}
}
impl core::fmt::Debug for Digest {
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
formatter.write_str("Digest(..)")
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct EventId(Digest);
impl EventId {
pub fn new(digest: Digest) -> Result<Self, ValidationError> {
if digest.is_zero() {
Err(ValidationError::ZeroValue)
} else {
Ok(Self(digest))
}
}
#[must_use]
pub const fn digest(&self) -> Digest {
self.0
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct CapabilityRef(Digest);
impl CapabilityRef {
pub fn new(digest: Digest) -> Result<Self, ValidationError> {
if digest.is_zero() {
Err(ValidationError::ZeroValue)
} else {
Ok(Self(digest))
}
}
#[must_use]
pub const fn digest(&self) -> Digest {
self.0
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct PolicyEpoch(Digest);
impl PolicyEpoch {
pub fn new(digest: Digest) -> Result<Self, ValidationError> {
if digest.is_zero() {
Err(ValidationError::ZeroValue)
} else {
Ok(Self(digest))
}
}
#[must_use]
pub const fn digest(&self) -> Digest {
self.0
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct OperationSequence(u64);
impl OperationSequence {
pub const fn new(value: u64) -> Result<Self, ValidationError> {
if value == 0 {
Err(ValidationError::ZeroValue)
} else {
Ok(Self(value))
}
}
#[must_use]
pub const fn get(self) -> u64 {
self.0
}
pub const fn next(self) -> Result<Self, ValidationError> {
match self.0.checked_add(1) {
Some(value) => Ok(Self(value)),
None => Err(ValidationError::TooLarge),
}
}
#[must_use]
pub const fn immediately_follows(self, previous: Self) -> bool {
match previous.0.checked_add(1) {
Some(expected) => self.0 == expected,
None => false,
}
}
}
#[derive(Eq)]
pub struct Nonce([u8; Self::LEN]);
impl Nonce {
pub const LEN: usize = 16;
pub fn new(bytes: [u8; Self::LEN]) -> Result<Self, ValidationError> {
if bool::from(bytes.ct_eq(&[0u8; Self::LEN])) {
Err(ValidationError::ZeroValue)
} else {
Ok(Self(bytes))
}
}
#[must_use]
pub const fn as_bytes(&self) -> &[u8; Self::LEN] {
&self.0
}
#[must_use]
pub fn ct_eq(&self, other: &Self) -> bool {
bool::from(self.0.ct_eq(&other.0))
}
}
impl PartialEq for Nonce {
fn eq(&self, other: &Self) -> bool {
self.ct_eq(other)
}
}
impl core::hash::Hash for Nonce {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
core::hash::Hash::hash(&self.0, state);
}
}
impl Drop for Nonce {
fn drop(&mut self) {
self.0.zeroize();
}
}
impl core::fmt::Debug for Nonce {
fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
formatter.write_str("Nonce(..)")
}
}