use core::convert::TryInto;
use core::fmt;
use std::io;
use secp256k1_zkp::rand::{CryptoRng, RngCore};
use secp256k1_zkp::{self, Generator, PedersenCommitment, Secp256k1, SecretKey, Signing, Tweak};
#[cfg(feature = "serde")]
use serde::{Deserializer, Serializer};
use crate::confidential::ValueBlindingFactor;
use crate::{encode, encoding};
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct RangeProof {
inner: Option<Box<secp256k1_zkp::RangeProof>>,
}
impl RangeProof {
pub const EMPTY: Self = Self { inner: None };
#[allow(clippy::too_many_arguments)]
pub fn new<C: Signing>(
secp: &Secp256k1<C>,
min_value: u64,
commitment: PedersenCommitment,
value: u64,
commitment_blinding: Tweak,
message: &[u8],
additional_commitment: &[u8],
sk: SecretKey,
exp: i32,
min_bits: u8,
additional_generator: Generator,
) -> Result<Self, secp256k1_zkp::Error> {
secp256k1_zkp::RangeProof::new(
secp,
min_value,
commitment,
value,
commitment_blinding,
message,
additional_commitment,
sk,
exp,
min_bits,
additional_generator,
)
.map(|inner| Self { inner: Some(Box::new(inner)) })
}
pub fn from_slice(sl: &[u8]) -> Result<Self, secp256k1_zkp::Error> {
if sl.is_empty() {
Ok(Self { inner: None })
} else {
secp256k1_zkp::RangeProof::from_slice(sl)
.map(|inner| Self { inner: Some(Box::new(inner)) })
}
}
pub fn blind_value_proof<C: secp256k1_zkp::Signing, R: RngCore + CryptoRng>(
rng: &mut R,
secp: &Secp256k1<C>,
explicit_val: u64,
value_commit: PedersenCommitment,
asset_gen: Generator,
vbf: ValueBlindingFactor,
) -> Result<Self, secp256k1_zkp::Error> {
secp256k1_zkp::RangeProof::new(
secp,
explicit_val, value_commit, explicit_val, vbf.into_inner(), &[], &[], SecretKey::new(rng), -1, 0, asset_gen, )
.map(|inner| Self { inner: Some(Box::new(inner)) })
}
pub fn blind_value_proof_verify<C: secp256k1_zkp::Verification>(
&self,
secp: &Secp256k1<C>,
explicit_val: u64,
asset_gen: Generator,
value_commit: PedersenCommitment,
) -> bool {
let Some(inner) = self.inner.as_deref() else {
return false;
};
if explicit_val == u64::MAX {
return false;
}
let Ok(range) = inner.verify(secp, value_commit, &[], asset_gen) else {
return false;
};
range == (explicit_val..explicit_val + 1)
}
pub fn len(&self) -> usize { self.inner.as_deref().map_or(0, secp256k1_zkp::RangeProof::len) }
pub fn is_empty(&self) -> bool { self.inner.is_none() }
pub fn to_vec(&self) -> Vec<u8> {
match self.inner.as_deref() {
Some(prf) => secp256k1_zkp::RangeProof::serialize(prf),
None => Vec::new(),
}
}
pub fn minimim_value(&self) -> Option<u64> {
let prf = self.to_vec();
let byte0 = prf.first()?;
let has_nonzero_range = byte0 & 64 == 64;
let has_min = byte0 & 32 == 32;
if !has_min {
None
} else if has_nonzero_range {
let bytes: [u8; 8] = prf.get(2..10)?.try_into().ok()?;
Some(u64::from_be_bytes(bytes))
} else {
let bytes: [u8; 8] = prf.get(1..9)?.try_into().ok()?;
Some(u64::from_be_bytes(bytes))
}
}
pub fn as_ref(&self) -> Option<&secp256k1_zkp::RangeProof> { self.inner.as_deref() }
}
impl crate::encode::Encodable for RangeProof {
fn consensus_encode<W: io::Write>(&self, e: W) -> Result<usize, encode::Error> {
self.to_vec().consensus_encode(e)
}
}
impl crate::encode::Decodable for RangeProof {
fn consensus_decode<D: io::Read>(d: D) -> Result<Self, encode::Error> {
let v = Vec::<u8>::consensus_decode(d)?;
if v.is_empty() {
Ok(Self { inner: None })
} else {
secp256k1_zkp::RangeProof::from_slice(&v)
.map(|inner| Self { inner: Some(Box::new(inner)) })
.map_err(encode::Error::Secp256k1zkp)
}
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for RangeProof {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
self.inner.serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for RangeProof {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Option::<secp256k1_zkp::RangeProof>::deserialize(deserializer)
.map(|inner| Self { inner: inner.map(Box::new) })
}
}
encoding::encoder_newtype_exact! {
#[derive(Clone, Debug)]
pub struct Encoder<'e>(super::PrefixedByteVecEncoder);
}
impl encoding::Encode for RangeProof {
type Encoder<'e> = Encoder<'e>;
fn encoder(&self) -> Self::Encoder<'_> {
Encoder::new(super::PrefixedByteVecEncoder::new(self.to_vec()))
}
}
decoder_newtype! {
#[derive(Default)]
pub struct Decoder(encoding::ByteVecDecoder);
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct DecoderError(enum DecoderErrorInner {
Decode(encoding::ByteVecDecoderError),
RangeProof(secp256k1_zkp::Error),
});
impl Decode for RangeProof {
fn convert_inner(v) -> Result<_, DecoderErrorInner> {
Self::Output::from_slice(&v).map_err(DecoderErrorInner::RangeProof)
}
}
}
impl fmt::Display for DecoderError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use DecoderErrorInner as Inner;
match self.0 {
Inner::Decode(..) => f.write_str("error decoding byte vector"),
Inner::RangeProof(..) => f.write_str("error decoding range proof"),
}
}
}
impl std::error::Error for DecoderError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use DecoderErrorInner as Inner;
match self.0 {
Inner::Decode(ref e) => Some(e),
Inner::RangeProof(ref e) => Some(e),
}
}
}