use std::io;
use hex::{FromHex, FromHexError, ToHex};
use crate::serialization::{SerializationError, ZcashDeserialize, ZcashSerialize};
#[cfg(test)]
mod test_vectors;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct CommitmentRandomness(jubjub::Fr);
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)]
pub struct ValueCommitment(pub(crate) [u8; 32]);
impl ValueCommitment {
pub fn commitment(&self) -> Option<sapling_crypto::value::ValueCommitment> {
sapling_crypto::value::ValueCommitment::from_bytes_not_small_order(&self.0).into_option()
}
pub fn to_bytes(&self) -> [u8; 32] {
self.0
}
pub fn is_valid_not_small_order(&self) -> bool {
bool::from(
sapling_crypto::value::ValueCommitment::from_bytes_not_small_order(&self.0).is_some(),
)
}
pub fn bytes_in_display_order(&self) -> [u8; 32] {
let mut reversed_bytes = self.0;
reversed_bytes.reverse();
reversed_bytes
}
}
impl ToHex for &ValueCommitment {
fn encode_hex<T: FromIterator<char>>(&self) -> T {
self.bytes_in_display_order().encode_hex()
}
fn encode_hex_upper<T: FromIterator<char>>(&self) -> T {
self.bytes_in_display_order().encode_hex_upper()
}
}
impl FromHex for ValueCommitment {
type Error = FromHexError;
fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
let mut bytes = <[u8; 32]>::from_hex(hex)?;
bytes.reverse();
Self::zcash_deserialize(io::Cursor::new(&bytes))
.map_err(|_| FromHexError::InvalidStringLength)
}
}
#[cfg(any(test, feature = "proptest-impl"))]
impl From<jubjub::ExtendedPoint> for ValueCommitment {
fn from(extended_point: jubjub::ExtendedPoint) -> Self {
ValueCommitment(jubjub::AffinePoint::from(extended_point).to_bytes())
}
}
impl ZcashDeserialize for sapling_crypto::value::ValueCommitment {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
let mut buf = [0u8; 32];
reader.read_exact(&mut buf)?;
let value_commitment: Option<sapling_crypto::value::ValueCommitment> =
sapling_crypto::value::ValueCommitment::from_bytes_not_small_order(&buf).into_option();
value_commitment.ok_or(SerializationError::Parse("invalid ValueCommitment bytes"))
}
}
impl ZcashDeserialize for ValueCommitment {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
let mut bytes = [0u8; 32];
reader.read_exact(&mut bytes)?;
Ok(Self(bytes))
}
}
impl ZcashSerialize for ValueCommitment {
fn zcash_serialize<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
writer.write_all(&self.0)?;
Ok(())
}
}
impl ZcashDeserialize for sapling_crypto::note::ExtractedNoteCommitment {
fn zcash_deserialize<R: io::Read>(mut reader: R) -> Result<Self, SerializationError> {
let mut buf = [0u8; 32];
reader.read_exact(&mut buf)?;
let extracted_note_commitment: Option<sapling_crypto::note::ExtractedNoteCommitment> =
sapling_crypto::note::ExtractedNoteCommitment::from_bytes(&buf).into_option();
extracted_note_commitment.ok_or(SerializationError::Parse(
"invalid ExtractedNoteCommitment bytes",
))
}
}