use std::{string::ToString, vec::Vec};
use zeroize::{Zeroize, ZeroizeOnDrop};
use crate::{
commitment::{ExtensionDegree, HomomorphicCommitment},
errors::RangeProofError,
keys::{PublicKey, SecretKey},
};
pub trait ExtendedRangeProofService {
type Proof: Sized;
type K: SecretKey;
type PK: PublicKey<K = Self::K>;
fn construct_proof_with_recovery_seed_nonce(
&self,
mask: &Self::K,
value: u64,
seed_nonce: &Self::K,
) -> Result<Self::Proof, RangeProofError>;
fn recover_mask(
&self,
proof: &Self::Proof,
commitment: &HomomorphicCommitment<Self::PK>,
seed_nonce: &Self::K,
) -> Result<Self::K, RangeProofError>;
fn verify_mask(
&self,
commitment: &HomomorphicCommitment<Self::PK>,
mask: &Self::K,
value: u64,
) -> Result<bool, RangeProofError>;
fn construct_extended_proof(
&self,
extended_witnesses: Vec<ExtendedWitness<Self::K>>,
seed_nonce: Option<Self::K>,
) -> Result<Self::Proof, RangeProofError>;
fn verify_batch_and_recover_masks(
&self,
proofs: Vec<&Self::Proof>,
statements: Vec<&AggregatedPrivateStatement<Self::PK>>,
) -> Result<Vec<Option<ExtendedMask<Self::K>>>, RangeProofError>;
fn verify_batch(
&self,
proofs: Vec<&Self::Proof>,
statements: Vec<&AggregatedPublicStatement<Self::PK>>,
) -> Result<(), RangeProofError>;
fn recover_extended_mask(
&self,
proof: &Self::Proof,
statement: &AggregatedPrivateStatement<Self::PK>,
) -> Result<Option<ExtendedMask<Self::K>>, RangeProofError>;
fn verify_extended_mask(
&self,
commitment: &HomomorphicCommitment<Self::PK>,
extended_mask: &ExtendedMask<Self::K>,
value: u64,
) -> Result<bool, RangeProofError>;
}
#[derive(Debug, Clone, PartialEq, Eq, Zeroize, ZeroizeOnDrop)]
pub struct ExtendedMask<K>
where K: SecretKey
{
secrets: Vec<K>,
}
impl<K> ExtendedMask<K>
where K: SecretKey
{
pub fn assign(extension_degree: ExtensionDegree, secrets: Vec<K>) -> Result<ExtendedMask<K>, RangeProofError> {
if secrets.is_empty() || secrets.len() != extension_degree as usize {
Err(RangeProofError::InitializationError {
reason: "Extended mask length must correspond to the extension degree".to_string(),
})
} else {
Ok(Self { secrets })
}
}
pub fn secrets(&self) -> Vec<K> {
self.secrets.clone()
}
}
#[derive(Clone)]
pub struct Statement<PK>
where PK: PublicKey
{
pub commitment: HomomorphicCommitment<PK>,
pub minimum_value_promise: u64,
}
#[derive(Clone)]
pub struct AggregatedPublicStatement<PK>
where PK: PublicKey
{
pub statements: Vec<Statement<PK>>,
}
impl<PK> AggregatedPublicStatement<PK>
where PK: PublicKey
{
pub fn init(statements: Vec<Statement<PK>>) -> Result<Self, RangeProofError> {
if !statements.len().is_power_of_two() {
return Err(RangeProofError::InitializationError {
reason: "Number of commitments must be a power of two".to_string(),
});
}
Ok(Self { statements })
}
}
#[derive(Clone)]
pub struct AggregatedPrivateStatement<PK>
where PK: PublicKey
{
pub statements: Vec<Statement<PK>>,
pub recovery_seed_nonce: Option<PK::K>,
}
impl<PK> AggregatedPrivateStatement<PK>
where PK: PublicKey
{
pub fn init(statements: Vec<Statement<PK>>, recovery_seed_nonce: Option<PK::K>) -> Result<Self, RangeProofError> {
if recovery_seed_nonce.is_some() && statements.len() > 1 {
return Err(RangeProofError::InitializationError {
reason: "Mask recovery is not supported with an aggregated statement".to_string(),
});
}
if !statements.len().is_power_of_two() {
return Err(RangeProofError::InitializationError {
reason: "Number of commitments must be a power of two".to_string(),
});
}
Ok(Self {
statements,
recovery_seed_nonce,
})
}
}
#[derive(Clone, Zeroize, ZeroizeOnDrop)]
pub struct ExtendedWitness<K>
where K: SecretKey
{
pub mask: ExtendedMask<K>,
pub value: u64,
pub minimum_value_promise: u64,
}
impl<K> ExtendedWitness<K>
where K: SecretKey
{
pub fn new(mask: ExtendedMask<K>, value: u64, minimum_value_promise: u64) -> Self {
Self {
mask,
value,
minimum_value_promise,
}
}
}