use crate::{
commitment::{HomomorphicCommitment, HomomorphicCommitmentFactory},
keys::{PublicKey, SecretKey},
};
use serde::{Deserialize, Serialize};
use std::{
cmp::Ordering,
hash::{Hash, Hasher},
ops::{Add, Mul},
};
use tari_utilities::ByteArray;
use thiserror::Error;
#[derive(Clone, Debug, Error, PartialEq, Eq, Deserialize, Serialize)]
pub enum CommitmentSignatureError {
#[error("An invalid challenge was provided")]
InvalidChallenge,
}
#[allow(non_snake_case)]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CommitmentSignature<P, K> {
public_nonce: HomomorphicCommitment<P>,
u: K,
v: K,
}
impl<P, K> CommitmentSignature<P, K>
where
P: PublicKey<K = K>,
K: SecretKey,
{
pub fn new(public_nonce: HomomorphicCommitment<P>, u: K, v: K) -> Self {
CommitmentSignature { public_nonce, u, v }
}
pub fn calc_signature_verifier<C>(&self, factory: &C) -> HomomorphicCommitment<P>
where C: HomomorphicCommitmentFactory<P = P> {
factory.commit(&self.u, &self.v)
}
pub fn sign<C>(
secret_a: K,
secret_x: K,
nonce_a: K,
nonce_x: K,
challenge: &[u8],
factory: &C,
) -> Result<Self, CommitmentSignatureError>
where
K: Mul<P, Output = P>,
for<'a> &'a K: Add<&'a K, Output = K>,
for<'a> &'a K: Mul<&'a K, Output = K>,
C: HomomorphicCommitmentFactory<P = P>,
{
let e = match K::from_bytes(challenge) {
Ok(e) => e,
Err(_) => return Err(CommitmentSignatureError::InvalidChallenge),
};
let ea = &e * &secret_a;
let ex = &e * &secret_x;
let v = &nonce_a + &ea;
let u = &nonce_x + &ex;
let public_commitment_nonce = factory.commit(&nonce_x, &nonce_a);
Ok(Self::new(public_commitment_nonce, u, v))
}
pub fn verify_challenge<'a, C>(
&self,
public_commitment: &'a HomomorphicCommitment<P>,
challenge: &[u8],
factory: &C,
) -> bool
where
for<'b> &'a HomomorphicCommitment<P>: Mul<&'b K, Output = HomomorphicCommitment<P>>,
for<'b> &'b HomomorphicCommitment<P>: Add<&'b HomomorphicCommitment<P>, Output = HomomorphicCommitment<P>>,
C: HomomorphicCommitmentFactory<P = P>,
{
let e = match K::from_bytes(&challenge) {
Ok(e) => e,
Err(_) => return false,
};
self.verify(public_commitment, &e, factory)
}
pub fn verify<'a, C>(&self, public_commitment: &'a HomomorphicCommitment<P>, challenge: &K, factory: &C) -> bool
where
for<'b> &'a HomomorphicCommitment<P>: Mul<&'b K, Output = HomomorphicCommitment<P>>,
for<'b> &'b HomomorphicCommitment<P>: Add<&'b HomomorphicCommitment<P>, Output = HomomorphicCommitment<P>>,
C: HomomorphicCommitmentFactory<P = P>,
{
let lhs = self.calc_signature_verifier(factory);
let rhs = &self.public_nonce + &(public_commitment * challenge);
lhs == rhs
}
#[inline]
pub fn complete_signature_tuple(&self) -> (&HomomorphicCommitment<P>, &K, &K) {
(&self.public_nonce, &self.u, &self.v)
}
#[inline]
pub fn u(&self) -> &K {
&self.u
}
#[inline]
pub fn v(&self) -> &K {
&self.v
}
#[inline]
pub fn public_nonce(&self) -> &HomomorphicCommitment<P> {
&self.public_nonce
}
pub fn to_vec(&self) -> Vec<u8> {
let mut buf = Vec::with_capacity(P::key_length() + K::key_length() + K::key_length());
buf.extend_from_slice(self.public_nonce().as_bytes());
buf.extend_from_slice(self.u().as_bytes());
buf.extend_from_slice(self.v().as_bytes());
buf
}
}
impl<'a, 'b, P, K> Add<&'b CommitmentSignature<P, K>> for &'a CommitmentSignature<P, K>
where
P: PublicKey<K = K>,
&'a HomomorphicCommitment<P>: Add<&'b HomomorphicCommitment<P>, Output = HomomorphicCommitment<P>>,
K: SecretKey,
&'a K: Add<&'b K, Output = K>,
{
type Output = CommitmentSignature<P, K>;
fn add(self, rhs: &'b CommitmentSignature<P, K>) -> CommitmentSignature<P, K> {
let r_sum = self.public_nonce() + rhs.public_nonce();
let s_u_sum = self.u() + rhs.u();
let s_v_sum = self.v() + rhs.v();
CommitmentSignature::new(r_sum, s_u_sum, s_v_sum)
}
}
impl<'a, P, K> Add<CommitmentSignature<P, K>> for &'a CommitmentSignature<P, K>
where
P: PublicKey<K = K>,
for<'b> &'a HomomorphicCommitment<P>: Add<&'b HomomorphicCommitment<P>, Output = HomomorphicCommitment<P>>,
K: SecretKey,
for<'b> &'a K: Add<&'b K, Output = K>,
{
type Output = CommitmentSignature<P, K>;
fn add(self, rhs: CommitmentSignature<P, K>) -> CommitmentSignature<P, K> {
let r_sum = self.public_nonce() + rhs.public_nonce();
let s_u_sum = self.u() + rhs.u();
let s_v_sum = self.v() + rhs.v();
CommitmentSignature::new(r_sum, s_u_sum, s_v_sum)
}
}
impl<P, K> Default for CommitmentSignature<P, K>
where
P: PublicKey<K = K>,
K: SecretKey,
{
fn default() -> Self {
CommitmentSignature::new(HomomorphicCommitment::<P>::default(), K::default(), K::default())
}
}
impl<P, K> Ord for CommitmentSignature<P, K>
where
P: PublicKey<K = K>,
K: SecretKey,
{
fn cmp(&self, other: &Self) -> Ordering {
match self.public_nonce().cmp(&other.public_nonce()) {
Ordering::Equal => {
let this_u = self.u().as_bytes();
let that_u = other.u().as_bytes();
match this_u.cmp(&that_u) {
Ordering::Equal => {
let this = self.v().as_bytes();
let that = other.v().as_bytes();
this.cmp(&that)
},
v => v,
}
},
v => v,
}
}
}
impl<P, K> PartialOrd for CommitmentSignature<P, K>
where
P: PublicKey<K = K>,
K: SecretKey,
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl<P, K> PartialEq for CommitmentSignature<P, K>
where
P: PublicKey<K = K>,
K: SecretKey,
{
fn eq(&self, other: &Self) -> bool {
self.public_nonce().eq(other.public_nonce()) && self.u().eq(other.u()) && self.v().eq(other.v())
}
}
impl<P, K> Eq for CommitmentSignature<P, K>
where
P: PublicKey<K = K>,
K: SecretKey,
{
}
impl<P, K> Hash for CommitmentSignature<P, K>
where
P: PublicKey<K = K>,
K: SecretKey,
{
fn hash<H: Hasher>(&self, state: &mut H) {
state.write(&self.to_vec())
}
}