use std::convert::TryInto;
use std::error;
use std::fmt::{self, Debug};
use std::io;
use thiserror::Error;
use tiny_keccak::{Hasher, Keccak};
use crate::consensus::{self, CanonicalBytes, Decodable, Encodable};
#[cfg(feature = "experimental")]
#[cfg_attr(docsrs, doc(cfg(feature = "experimental")))]
pub mod dleq;
#[cfg(feature = "experimental")]
#[cfg_attr(docsrs, doc(cfg(feature = "experimental")))]
pub mod slip10;
#[derive(Error, Debug)]
pub enum Error {
#[error("The key identifier is not supported and the key cannot be derived")]
UnsupportedKey,
#[error("The key or key identifier does not exists or is missing")]
MissingKey,
#[error("The signature does not pass the validation")]
InvalidSignature,
#[error("The adaptor key is not valid")]
InvalidAdaptorKey,
#[error("The adaptor signature does not pass the validation")]
InvalidEncryptedSignature,
#[error("The proof does not pass the validation")]
InvalidProof,
#[error("The commitment does not match the given value")]
InvalidCommitment,
#[error("The Pedersen commitment does not match the given value")]
InvalidPedersenCommitment,
#[error("The ring signature does not recompute")]
InvalidRingSignature,
#[error("The proof of knowledge signature is invalid")]
InvalidProofOfKnowledge,
#[error("SLIP10 error: {0}")]
Slip10(#[from] slip10::Error),
#[error("Cryptographic error: {0}")]
Other(Box<dyn error::Error + Send + Sync>),
}
impl Error {
pub fn new<E>(error: E) -> Self
where
E: Into<Box<dyn error::Error + Send + Sync>>,
{
Self::Other(error.into())
}
pub fn into_inner(self) -> Option<Box<dyn error::Error + Send + Sync>> {
match self {
Self::Other(error) => Some(error),
_ => None,
}
}
}
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Serialize, Deserialize)]
pub struct TaggedElement<T, E> {
tag: T,
elem: E,
}
impl<T, E> TaggedElement<T, E> {
pub fn new(tag: T, elem: E) -> Self {
Self { tag, elem }
}
pub fn tag(&self) -> &T {
&self.tag
}
pub fn elem(&self) -> &E {
&self.elem
}
}
impl<T, E> fmt::Display for TaggedElement<T, E>
where
T: fmt::Display,
E: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "<{}: {}>", self.tag, self.elem)
}
}
impl<T, E> Encodable for TaggedElement<T, E>
where
T: Encodable,
E: CanonicalBytes,
{
#[inline]
fn consensus_encode<S: io::Write>(&self, s: &mut S) -> Result<usize, io::Error> {
let len = self.tag.consensus_encode(s)?;
Ok(len + self.elem.as_canonical_bytes().consensus_encode(s)?)
}
}
impl<T, E> Decodable for TaggedElement<T, E>
where
T: Decodable,
E: CanonicalBytes,
{
#[inline]
fn consensus_decode<D: io::Read>(d: &mut D) -> Result<Self, consensus::Error> {
let tag = T::consensus_decode(d)?;
let elem = E::from_canonical_bytes(unwrap_vec_ref!(d).as_ref())?;
Ok(TaggedElement { tag, elem })
}
}
pub type TaggedElements<T, E> = Vec<TaggedElement<T, E>>;
pub type TaggedExtraKeys<E> = Vec<TaggedElement<u16, E>>;
pub type TaggedSharedKeys<E> = Vec<TaggedElement<SharedKeyId, E>>;
#[derive(Debug, Clone, Copy, Display, Serialize, Deserialize)]
#[display(Debug)]
pub enum ArbitratingKeyId {
Lock,
Buy,
Cancel,
Refund,
Punish,
Extra(u16),
}
#[derive(Debug, Clone, Copy, Display, Serialize, Deserialize)]
#[display(Debug)]
pub enum AccordantKeyId {
Spend,
Extra(u16),
}
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, Display, Serialize, Deserialize)]
#[display(Debug)]
pub struct SharedKeyId(u16);
impl SharedKeyId {
pub fn new(id: u16) -> Self {
Self(id)
}
pub fn id(&self) -> u16 {
self.0
}
}
impl Encodable for SharedKeyId {
#[inline]
fn consensus_encode<S: io::Write>(&self, s: &mut S) -> Result<usize, io::Error> {
self.0.consensus_encode(s)
}
}
impl Decodable for SharedKeyId {
#[inline]
fn consensus_decode<D: io::Read>(d: &mut D) -> Result<Self, consensus::Error> {
Ok(Self(u16::consensus_decode(d)?))
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccordantKeys<PublicKey, SharedSecretKey> {
pub public_spend_key: PublicKey,
pub extra_public_keys: Vec<TaggedElement<u16, PublicKey>>,
pub shared_secret_keys: Vec<TaggedElement<SharedKeyId, SharedSecretKey>>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AccordantKeySet<PublicKey, SharedSecretKey> {
pub alice: AccordantKeys<PublicKey, SharedSecretKey>,
pub bob: AccordantKeys<PublicKey, SharedSecretKey>,
}
fixed_hash::construct_fixed_hash!(
#[derive(Serialize, Deserialize)]
pub struct KeccakCommitment(32);
);
impl KeccakCommitment {
pub fn null_hash() -> Self {
Self([0u8; 32])
}
pub fn new(input: [u8; 32]) -> Self {
Self(input)
}
}
impl CanonicalBytes for KeccakCommitment {
fn as_canonical_bytes(&self) -> Vec<u8> {
(*self).to_fixed_bytes().into()
}
fn from_canonical_bytes(bytes: &[u8]) -> Result<Self, consensus::Error>
where
Self: Sized,
{
Ok(Self::new(bytes.try_into().map_err(consensus::Error::new)?))
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Display)]
#[display(Debug)]
pub struct CommitmentEngine;
impl Commit<KeccakCommitment> for CommitmentEngine {
fn commit_to<T: AsRef<[u8]>>(&self, value: T) -> KeccakCommitment {
let mut out = [0u8; 32];
let mut keccak = Keccak::v256();
keccak.update(value.as_ref());
keccak.finalize(&mut out);
KeccakCommitment::new(out)
}
}
pub trait DeriveKeys {
type PublicKey;
type PrivateKey;
fn extra_public_keys() -> Vec<u16>;
fn extra_shared_private_keys() -> Vec<SharedKeyId>;
}
pub trait KeyGenerator<ArPublicKey, AcPublicKey, ArSharedKey, AcSharedKey, Proof>:
GenerateKey<ArPublicKey, ArbitratingKeyId>
+ GenerateKey<AcPublicKey, AccordantKeyId>
+ ProveCrossGroupDleq<ArPublicKey, AcPublicKey, Proof>
+ GenerateSharedKey<ArSharedKey>
+ GenerateSharedKey<AcSharedKey>
{
}
impl<T, ArPublicKey, AcPublicKey, ArSharedKey, AcSharedKey, Proof>
KeyGenerator<ArPublicKey, AcPublicKey, ArSharedKey, AcSharedKey, Proof> for T
where
T: GenerateKey<ArPublicKey, ArbitratingKeyId>
+ GenerateKey<AcPublicKey, AccordantKeyId>
+ GenerateSharedKey<ArSharedKey>
+ GenerateSharedKey<AcSharedKey>
+ ProveCrossGroupDleq<ArPublicKey, AcPublicKey, Proof>,
{
}
pub trait GenerateKey<PublicKey, KeyId> {
fn get_pubkey(&mut self, key_id: KeyId) -> Result<PublicKey, Error>;
fn get_pubkeys(&mut self, key_ids: Vec<KeyId>) -> Result<Vec<PublicKey>, Error> {
key_ids.into_iter().map(|id| self.get_pubkey(id)).collect()
}
}
pub trait GenerateSharedKey<SharedKey> {
fn get_shared_key(&mut self, key_id: SharedKeyId) -> Result<SharedKey, Error>;
}
pub trait Sign<PublicKey, Message, Signature> {
fn sign(&mut self, key: ArbitratingKeyId, msg: Message) -> Result<Signature, Error>;
fn verify_signature(&self, key: &PublicKey, msg: Message, sig: &Signature)
-> Result<(), Error>;
}
pub trait EncSign<PublicKey, Message, Signature, EncryptedSignature> {
fn encrypt_sign(
&mut self,
signing_key: ArbitratingKeyId,
encryption_key: &PublicKey,
msg: Message,
) -> Result<EncryptedSignature, Error>;
fn verify_encrypted_signature(
&self,
signing_key: &PublicKey,
encryption_key: &PublicKey,
msg: Message,
sig: &EncryptedSignature,
) -> Result<(), Error>;
fn decrypt_signature(
&mut self,
decryption_key: AccordantKeyId,
sig: EncryptedSignature,
) -> Result<Signature, Error>;
}
pub trait RecoverSecret<PublicKey, SecretKey, Signature, EncryptedSignature> {
fn recover_secret_key(
&self,
encrypted_sig: EncryptedSignature,
encryption_key: &PublicKey,
sig: Signature,
) -> SecretKey;
}
pub trait Commit<Commitment> {
fn commit_to<T: AsRef<[u8]>>(&self, value: T) -> Commitment;
fn validate<T: AsRef<[u8]>>(&self, candidate: T, commitment: Commitment) -> Result<(), Error>
where
Commitment: Eq,
{
if self.commit_to(candidate) == commitment {
Ok(())
} else {
Err(Error::InvalidCommitment)
}
}
}
pub trait ProveCrossGroupDleq<EncryptionKey, AccordantSpendKey, Proof> {
fn generate_proof(&mut self) -> Result<(AccordantSpendKey, EncryptionKey, Proof), Error>;
fn get_encryption_key(&mut self) -> Result<EncryptionKey, Error>;
fn verify_proof(
&mut self,
public_spend: &AccordantSpendKey,
encryption_key: &EncryptionKey,
proof: Proof,
) -> Result<(), Error>;
}