use group::{ff::PrimeField, GroupEncoding};
use halo2::pasta::pallas;
use rand_core::{CryptoRng, RngCore};
use crate::{
amount::{Amount, NonNegative},
error::{NoteError, RandError},
};
use super::{address::Address, sinsemilla::extract_p};
mod ciphertexts;
mod nullifiers;
pub use ciphertexts::{EncryptedNote, WrappedNoteKey};
pub use nullifiers::Nullifier;
#[cfg(any(test, feature = "proptest-impl"))]
mod arbitrary;
#[derive(Clone, Copy, Debug)]
#[allow(dead_code)]
pub struct SeedRandomness(pub(crate) [u8; 32]);
impl SeedRandomness {
pub fn new<T>(csprng: &mut T) -> Result<Self, RandError>
where
T: RngCore + CryptoRng,
{
let mut bytes = [0u8; 32];
csprng
.try_fill_bytes(&mut bytes)
.map_err(|_| RandError::FillBytes)?;
Ok(Self(bytes))
}
}
#[derive(Clone, Debug)]
pub struct Rho(pub(crate) pallas::Base);
impl From<Rho> for [u8; 32] {
fn from(rho: Rho) -> Self {
rho.0.to_repr()
}
}
impl From<Nullifier> for Rho {
fn from(nf: Nullifier) -> Self {
Self(nf.0)
}
}
impl Rho {
pub fn new<T>(csprng: &mut T) -> Result<Self, NoteError>
where
T: RngCore + CryptoRng,
{
let mut bytes = [0u8; 32];
csprng
.try_fill_bytes(&mut bytes)
.map_err(|_| NoteError::from(RandError::FillBytes))?;
let possible_point = pallas::Point::from_bytes(&bytes);
if possible_point.is_some().into() {
Ok(Self(extract_p(possible_point.unwrap())))
} else {
Err(NoteError::InvalidRho)
}
}
}
#[derive(Clone, Debug)]
pub struct Psi(pub(crate) pallas::Base);
impl From<Psi> for [u8; 32] {
fn from(psi: Psi) -> Self {
psi.0.to_repr()
}
}
#[derive(Clone, Debug)]
pub struct Note {
pub address: Address,
pub value: Amount<NonNegative>,
pub rho: Rho,
pub rseed: SeedRandomness,
}
impl Note {
pub fn new<T>(
csprng: &mut T,
address: Address,
value: Amount<NonNegative>,
nf_old: Nullifier,
) -> Result<Self, RandError>
where
T: RngCore + CryptoRng,
{
Ok(Self {
address,
value,
rho: nf_old.into(),
rseed: SeedRandomness::new(csprng)?,
})
}
}