use crate::{error::NonceError, Error};
use core::fmt;
use multi_base::Base;
use multi_codec::Codec;
use multi_trait::{Null, TryDecodeFrom};
use multi_util::{BaseEncoded, CodecInfo, EncodingInfo, Varbytes};
use rand_core::CryptoRng;
pub const SIGIL: Codec = Codec::Nonce;
pub type EncodedNonce = BaseEncoded<Nonce>;
#[derive(Clone, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct Nonce {
pub(crate) nonce: Vec<u8>,
}
impl Nonce {
pub fn len(&self) -> usize {
self.nonce.len()
}
pub fn is_empty(&self) -> bool {
self.nonce.is_empty()
}
}
impl CodecInfo for Nonce {
fn preferred_codec() -> Codec {
SIGIL
}
fn codec(&self) -> Codec {
Self::preferred_codec()
}
}
impl EncodingInfo for Nonce {
fn preferred_encoding() -> Base {
Base::Base16Lower
}
fn encoding(&self) -> Base {
Self::preferred_encoding()
}
}
impl AsRef<[u8]> for Nonce {
fn as_ref(&self) -> &[u8] {
self.nonce.as_ref()
}
}
impl From<Nonce> for Vec<u8> {
fn from(val: Nonce) -> Self {
let mut v = Vec::default();
v.append(&mut SIGIL.into());
v.append(&mut Varbytes::new(val.nonce.clone()).into());
v
}
}
impl<'a> TryFrom<&'a [u8]> for Nonce {
type Error = Error;
fn try_from(s: &'a [u8]) -> Result<Self, Self::Error> {
let (mh, _) = Self::try_decode_from(s)?;
Ok(mh)
}
}
impl<'a> TryDecodeFrom<'a> for Nonce {
type Error = Error;
fn try_decode_from(bytes: &'a [u8]) -> Result<(Self, &'a [u8]), Self::Error> {
let (sigil, ptr) = Codec::try_decode_from(bytes)?;
if sigil != SIGIL {
return Err(NonceError::MissingSigil.into());
}
let (nonce, ptr) = Varbytes::try_decode_from(ptr)?;
Ok((
Self {
nonce: nonce.to_inner(),
},
ptr,
))
}
}
impl Null for Nonce {
fn null() -> Self {
Self::default()
}
fn is_null(&self) -> bool {
*self == Self::null()
}
}
impl fmt::Debug for Nonce {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?} - {}", SIGIL, hex::encode(&self.nonce))
}
}
#[derive(Clone, Debug, Default)]
pub struct Builder {
bytes: Vec<u8>,
base_encoding: Option<Base>,
}
impl Builder {
pub fn new_from_random_bytes(size: usize, rng: &mut impl CryptoRng) -> Self {
let mut bytes = vec![0; size];
bytes.resize(size, 0u8);
rng.fill_bytes(bytes.as_mut());
Self {
bytes,
..Default::default()
}
}
pub fn new_from_bytes(bytes: &[u8]) -> Self {
Self {
bytes: bytes.to_vec(),
..Default::default()
}
}
pub fn with_base_encoding(mut self, base: Base) -> Self {
self.base_encoding = Some(base);
self
}
pub fn try_build_encoded(&self) -> Result<EncodedNonce, Error> {
Ok(EncodedNonce::new(
self.base_encoding.unwrap_or_else(Nonce::preferred_encoding),
self.try_build()?,
))
}
pub fn try_build(&self) -> Result<Nonce, Error> {
Ok(Nonce {
nonce: self.bytes.clone(),
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{mk, Views};
#[test]
fn test_random() {
let mut rng = rand::rng();
let n = Builder::new_from_random_bytes(32, &mut rng)
.try_build()
.unwrap();
assert_eq!(Codec::Nonce, n.codec());
assert_eq!(32, n.len());
}
#[test]
fn test_binary_roundtrip() {
let mut rng = rand::rng();
let n = Builder::new_from_random_bytes(32, &mut rng)
.try_build()
.unwrap();
let v: Vec<u8> = n.clone().into();
assert_eq!(n, Nonce::try_from(v.as_ref()).unwrap());
}
#[test]
fn test_encoded_roundtrip() {
let mut rng = rand::rng();
let n = Builder::new_from_random_bytes(32, &mut rng)
.try_build_encoded()
.unwrap();
let s = n.to_string();
println!("({}) {}", s.len(), s);
let s = n.to_string();
assert_eq!(n, EncodedNonce::try_from(s.as_str()).unwrap());
}
#[test]
fn test_nonce_multisig_roundtrip() {
let mut rng = rand::rng();
let mk = mk::Builder::new_from_random_bytes(Codec::Ed25519Priv, &mut rng)
.unwrap()
.with_comment("test key")
.try_build()
.unwrap();
let msg = hex::decode("8bb78be51ac7cc98f44e38947ff8a128764ec039b89687a790dfa8444ba97682")
.unwrap();
let signmk = mk.sign_view().unwrap();
let signature = signmk.sign(msg.as_slice(), false, None).unwrap();
let s: Vec<u8> = signature.into();
let n = Builder::new_from_bytes(&s).try_build_encoded().unwrap();
let s = n.to_string();
assert_eq!(n, EncodedNonce::try_from(s.as_str()).unwrap());
}
#[test]
fn test_null() {
let n1 = Nonce::null();
assert!(n1.is_null());
let n2 = Nonce::default();
assert_eq!(n1, n2);
assert!(n2.is_null());
}
}