#[cfg(feature = "serde")]
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::{io, fmt};
use bitcoin::hashes::sha256d;
use encode::{self, Encodable, Decodable};
macro_rules! impl_confidential_commitment {
($name:ident, $prefixA:expr, $prefixB:expr) => (
impl_confidential_commitment!($name, $prefixA, $prefixB, |x|x);
);
($name:ident, $prefixA:expr, $prefixB:expr, $explicit_fn:expr) => (
impl Default for $name {
fn default() -> Self {
$name::Null
}
}
impl fmt::Display for $name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
$name::Null => f.write_str("null"),
$name::Explicit(n) => write!(f, "{}", n),
$name::Confidential(prefix, bytes) => {
write!(f, "{:02x}", prefix)?;
for b in bytes.iter() {
write!(f, "{:02x}", b)?;
}
Ok(())
}
}
}
}
impl Encodable for $name {
fn consensus_encode<S: io::Write>(&self, mut s: S) -> Result<usize, encode::Error> {
match *self {
$name::Null => 0u8.consensus_encode(s),
$name::Explicit(n) => {
1u8.consensus_encode(&mut s)?;
Ok(1 + $explicit_fn(n).consensus_encode(&mut s)?)
}
$name::Confidential(prefix, bytes) => {
Ok(prefix.consensus_encode(&mut s)? + bytes.consensus_encode(&mut s)?)
}
}
}
}
impl Decodable for $name {
fn consensus_decode<D: io::Read>(mut d: D) -> Result<$name, encode::Error> {
let prefix = u8::consensus_decode(&mut d)?;
match prefix {
0 => Ok($name::Null),
1 => {
let explicit = $explicit_fn(Decodable::consensus_decode(&mut d)?);
Ok($name::Explicit(explicit))
}
x => {
let commitment = <[u8; 32]>::consensus_decode(&mut d)?;
Ok($name::Confidential(x, commitment))
}
}
}
}
#[cfg(feature = "serde")]
impl Serialize for $name {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
use serde::ser::SerializeSeq;
let seq_len = if *self == $name::Null { 1 } else { 2 };
let mut seq = s.serialize_seq(Some(seq_len))?;
match *self {
$name::Null => seq.serialize_element(&0u8)?,
$name::Explicit(n) => {
seq.serialize_element(&1u8)?;
seq.serialize_element(&$explicit_fn(n))?;
}
$name::Confidential(prefix, bytes) => {
seq.serialize_element(&prefix)?;
seq.serialize_element(&bytes)?;
}
}
seq.end()
}
}
#[cfg(feature = "serde")]
impl<'de> Deserialize<'de> for $name {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
use serde::de::{Error, Visitor, SeqAccess};
struct CommitVisitor;
impl <'de> Visitor<'de> for CommitVisitor {
type Value = $name;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("a committed value")
}
fn visit_seq<A: SeqAccess<'de>>(self, mut access: A) -> Result<Self::Value, A::Error> {
let prefix: u8 = if let Some(x) = access.next_element()? {
x
} else {
return Err(A::Error::custom("missing prefix"));
};
match prefix {
0 => Ok($name::Null),
1 => {
match access.next_element()? {
Some(x) => Ok($name::Explicit($explicit_fn(x))),
None => Err(A::Error::custom("missing commitment")),
}
}
x => {
match access.next_element()? {
Some(y) => Ok($name::Confidential(x, y)),
None => Err(A::Error::custom("missing commitment")),
}
}
}
}
}
d.deserialize_seq(CommitVisitor)
}
}
);
}
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub enum Value {
Null,
Explicit(u64),
Confidential(u8, [u8; 32]),
}
impl_confidential_commitment!(Value, 0x08, 0x09, u64::swap_bytes);
impl Value {
pub fn encoded_length(&self) -> usize {
match *self {
Value::Null => 1,
Value::Explicit(..) => 9,
Value::Confidential(..) => 33,
}
}
}
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub enum Asset {
Null,
Explicit(sha256d::Hash),
Confidential(u8, [u8; 32]),
}
impl_confidential_commitment!(Asset, 0x0a, 0x0b);
impl Asset {
pub fn encoded_length(&self) -> usize {
match *self {
Asset::Null => 1,
Asset::Explicit(..) => 33,
Asset::Confidential(..) => 33,
}
}
}
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub enum Nonce {
Null,
Explicit(sha256d::Hash),
Confidential(u8, [u8; 32]),
}
impl_confidential_commitment!(Nonce, 0x02, 0x03);
impl Nonce {
pub fn encoded_length(&self) -> usize {
match *self {
Nonce::Null => 1,
Nonce::Explicit(..) => 33,
Nonce::Confidential(..) => 33,
}
}
}
#[cfg(test)]
mod tests {
use bitcoin::hashes::Hash;
use super::*;
#[test]
fn encode_length() {
let vals = [
Value::Null,
Value::Explicit(1000),
Value::Confidential(0x08, [1; 32]),
];
for v in &vals[..] {
let mut x = vec![];
assert_eq!(v.consensus_encode(&mut x).unwrap(), v.encoded_length());
assert_eq!(x.len(), v.encoded_length());
}
let nonces = [
Nonce::Null,
Nonce::Explicit(sha256d::Hash::from_inner([0; 32])),
Nonce::Confidential(0x02, [1; 32]),
];
for v in &nonces[..] {
let mut x = vec![];
assert_eq!(v.consensus_encode(&mut x).unwrap(), v.encoded_length());
assert_eq!(x.len(), v.encoded_length());
}
let assets = [
Asset::Null,
Asset::Explicit(sha256d::Hash::from_inner([0; 32])),
Asset::Confidential(0x0a, [1; 32]),
];
for v in &assets[..] {
let mut x = vec![];
assert_eq!(v.consensus_encode(&mut x).unwrap(), v.encoded_length());
assert_eq!(x.len(), v.encoded_length());
}
}
}