#[cfg(feature = "serde")]
use serde_with::{serde_as, DisplayFromStr};
use alloc::vec::Vec;
use bytecheck::CheckBytes;
use dusk_bytes::Serializable;
use rand::{CryptoRng, RngCore};
use rkyv::{Archive, Deserialize, Serialize};
use crate::abi::ContractId;
use crate::signatures::bls::{
PublicKey as AccountPublicKey, SecretKey as AccountSecretKey,
Signature as AccountSignature,
};
use crate::signatures::schnorr::{
SecretKey as NoteSecretKey, Signature as NoteSignature,
};
use crate::transfer::phoenix::StealthAddress;
use crate::BlsScalar;
#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize)]
#[archive_attr(derive(CheckBytes))]
#[cfg_attr(feature = "serde", cfg_eval, serde_as)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Withdraw {
pub(super) contract: ContractId,
#[cfg_attr(feature = "serde", serde_as(as = "DisplayFromStr"))]
pub(super) value: u64,
pub(super) receiver: WithdrawReceiver,
token: WithdrawReplayToken,
signature: WithdrawSignature,
}
impl Withdraw {
#[must_use]
pub fn new<'a, R: RngCore + CryptoRng>(
rng: &mut R,
sk: impl Into<WithdrawSecretKey<'a>>,
contract: ContractId,
value: u64,
receiver: WithdrawReceiver,
token: WithdrawReplayToken,
) -> Self {
let mut withdraw = Self {
contract,
value,
receiver,
token,
signature: WithdrawSignature::Moonlight(AccountSignature::default()),
};
let sk = sk.into();
match (&sk, &receiver) {
(WithdrawSecretKey::Phoenix(_), WithdrawReceiver::Moonlight(_)) => {
panic!("Moonlight receiver with phoenix signer");
}
(WithdrawSecretKey::Moonlight(_), WithdrawReceiver::Phoenix(_)) => {
panic!("Phoenix receiver with moonlight signer");
}
_ => {}
}
let msg = withdraw.signature_message();
match sk {
WithdrawSecretKey::Phoenix(sk) => {
let digest = BlsScalar::hash_to_scalar(&msg);
let signature = sk.sign(rng, digest);
withdraw.signature = signature.into();
}
WithdrawSecretKey::Moonlight(sk) => {
let signature = sk.sign(&msg);
withdraw.signature = signature.into();
}
}
withdraw
}
#[must_use]
pub fn contract(&self) -> &ContractId {
&self.contract
}
#[must_use]
pub fn value(&self) -> u64 {
self.value
}
#[must_use]
pub fn receiver(&self) -> &WithdrawReceiver {
&self.receiver
}
#[must_use]
pub fn token(&self) -> &WithdrawReplayToken {
&self.token
}
#[must_use]
pub fn signature(&self) -> &WithdrawSignature {
&self.signature
}
#[must_use]
pub fn signature_message(&self) -> Vec<u8> {
let mut bytes = Vec::new();
bytes.extend(self.contract.as_bytes());
bytes.extend(self.value.to_bytes());
match self.receiver {
WithdrawReceiver::Phoenix(address) => {
bytes.extend(address.to_bytes());
}
WithdrawReceiver::Moonlight(account) => {
bytes.extend(account.to_bytes());
}
}
match &self.token {
WithdrawReplayToken::Phoenix(nullifiers) => {
for n in nullifiers {
bytes.extend(n.to_bytes());
}
}
WithdrawReplayToken::Moonlight(nonce) => {
bytes.extend(nonce.to_bytes());
}
}
bytes
}
#[must_use]
pub fn wrapped_signature_message(&self) -> Vec<u8> {
let mut bytes = self.signature_message();
bytes.extend(self.signature.to_var_bytes());
bytes
}
}
#[derive(Debug, Clone, Copy, PartialEq, Archive, Serialize, Deserialize)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[archive_attr(derive(CheckBytes))]
pub enum WithdrawReceiver {
Phoenix(StealthAddress),
Moonlight(AccountPublicKey),
}
#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize)]
#[archive_attr(derive(CheckBytes))]
#[cfg_attr(feature = "serde", cfg_eval, serde_as)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum WithdrawReplayToken {
Phoenix(Vec<BlsScalar>),
Moonlight(
#[cfg_attr(feature = "serde", serde_as(as = "DisplayFromStr"))] u64,
),
}
#[derive(Debug, Clone, PartialEq)]
pub enum WithdrawSecretKey<'a> {
Phoenix(&'a NoteSecretKey),
Moonlight(&'a AccountSecretKey),
}
impl<'a> From<&'a NoteSecretKey> for WithdrawSecretKey<'a> {
fn from(sk: &'a NoteSecretKey) -> Self {
Self::Phoenix(sk)
}
}
impl<'a> From<&'a AccountSecretKey> for WithdrawSecretKey<'a> {
fn from(sk: &'a AccountSecretKey) -> Self {
Self::Moonlight(sk)
}
}
#[derive(Debug, Clone, PartialEq, Archive, Serialize, Deserialize)]
#[archive_attr(derive(CheckBytes))]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum WithdrawSignature {
Phoenix(NoteSignature),
Moonlight(AccountSignature),
}
impl WithdrawSignature {
fn to_var_bytes(&self) -> Vec<u8> {
match self {
WithdrawSignature::Phoenix(sig) => sig.to_bytes().to_vec(),
WithdrawSignature::Moonlight(sig) => sig.to_bytes().to_vec(),
}
}
}
impl From<NoteSignature> for WithdrawSignature {
fn from(sig: NoteSignature) -> Self {
Self::Phoenix(sig)
}
}
impl From<AccountSignature> for WithdrawSignature {
fn from(sig: AccountSignature) -> Self {
Self::Moonlight(sig)
}
}