mirror of
https://github.com/darkrenaissance/darkfi.git
synced 2026-01-10 07:08:05 -05:00
98 lines
3.2 KiB
Rust
98 lines
3.2 KiB
Rust
/* This file is part of DarkFi (https://dark.fi)
|
|
*
|
|
* Copyright (C) 2020-2023 Dyne.org foundation
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Affero General Public License as
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Affero General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
use async_trait::async_trait;
|
|
use crypto_api_chachapoly::ChachaPolyIetf;
|
|
use darkfi_sdk::{
|
|
crypto::{
|
|
diffie_hellman::{kdf_sapling, sapling_ka_agree},
|
|
keypair::PublicKey,
|
|
SecretKey,
|
|
},
|
|
pasta::pallas,
|
|
};
|
|
use darkfi_serial::{Decodable, Encodable, SerialDecodable, SerialEncodable};
|
|
use rand::rngs::OsRng;
|
|
use smol::io::{AsyncRead, AsyncWrite};
|
|
|
|
use crate::Error;
|
|
|
|
/// transfered lead coin is rcpt into two coins,
|
|
/// first coin is transfered rcpt coin.
|
|
/// second coin is the change returning to sender, or different address.
|
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, SerialEncodable, SerialDecodable)]
|
|
pub struct TxRcpt {
|
|
/// rcpt coin nonce
|
|
pub rho: pallas::Base,
|
|
/// rcpt coin commitment opening
|
|
pub opening: pallas::Scalar,
|
|
/// rcpt coin value
|
|
pub value: u64,
|
|
}
|
|
|
|
pub const PLAINTEXT_SIZE: usize = 32 + 32 + 8;
|
|
pub const AEAD_TAG_SIZE: usize = 16;
|
|
pub const CIPHER_SIZE: usize = PLAINTEXT_SIZE + AEAD_TAG_SIZE;
|
|
|
|
impl TxRcpt {
|
|
/// encrypt received coin, by recipient public key
|
|
pub fn encrypt(&self, public: &PublicKey) -> EncryptedTxRcpt {
|
|
let ephem_secret = SecretKey::random(&mut OsRng);
|
|
let ephem_public = PublicKey::from_secret(ephem_secret);
|
|
let shared_secret = sapling_ka_agree(&ephem_secret, public);
|
|
let key = kdf_sapling(&shared_secret, &ephem_public);
|
|
|
|
let mut input = Vec::new();
|
|
self.encode(&mut input).unwrap();
|
|
|
|
let mut ciphertext = [0u8; CIPHER_SIZE];
|
|
assert_eq!(
|
|
ChachaPolyIetf::aead_cipher()
|
|
.seal_to(&mut ciphertext, &input, &[], key.as_ref(), &[0u8; 12])
|
|
.unwrap(),
|
|
CIPHER_SIZE
|
|
);
|
|
|
|
EncryptedTxRcpt { ciphertext, ephem_public }
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
|
|
pub struct EncryptedTxRcpt {
|
|
ciphertext: [u8; CIPHER_SIZE],
|
|
ephem_public: PublicKey,
|
|
}
|
|
|
|
impl EncryptedTxRcpt {
|
|
pub fn decrypt(&self, secret: &SecretKey) -> TxRcpt {
|
|
let shared_secret = sapling_ka_agree(secret, &self.ephem_public);
|
|
let key = kdf_sapling(&shared_secret, &self.ephem_public);
|
|
|
|
let mut plaintext = [0; CIPHER_SIZE];
|
|
assert_eq!(
|
|
ChachaPolyIetf::aead_cipher()
|
|
.open_to(&mut plaintext, &self.ciphertext, &[], key.as_ref(), &[0u8; 12])
|
|
.map_err(|_| Error::TxRcptDecryptionError)
|
|
.unwrap(),
|
|
PLAINTEXT_SIZE
|
|
);
|
|
|
|
TxRcpt::decode(&plaintext[..]).unwrap()
|
|
}
|
|
}
|