rcpt.rs 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2023 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use crypto_api_chachapoly::ChachaPolyIetf;
  19. use darkfi_sdk::{
  20. crypto::{
  21. diffie_hellman::{kdf_sapling, sapling_ka_agree},
  22. keypair::PublicKey,
  23. SecretKey,
  24. },
  25. pasta::pallas,
  26. };
  27. use darkfi_serial::{async_trait, Decodable, Encodable, SerialDecodable, SerialEncodable};
  28. use rand::rngs::OsRng;
  29. use crate::Error;
  30. /// transfered lead coin is rcpt into two coins,
  31. /// first coin is transfered rcpt coin.
  32. /// second coin is the change returning to sender, or different address.
  33. #[derive(Debug, Clone, Copy, Eq, PartialEq, SerialEncodable, SerialDecodable)]
  34. pub struct TxRcpt {
  35. /// rcpt coin nonce
  36. pub rho: pallas::Base,
  37. /// rcpt coin commitment opening
  38. pub opening: pallas::Scalar,
  39. /// rcpt coin value
  40. pub value: u64,
  41. }
  42. pub const PLAINTEXT_SIZE: usize = 32 + 32 + 8;
  43. pub const AEAD_TAG_SIZE: usize = 16;
  44. pub const CIPHER_SIZE: usize = PLAINTEXT_SIZE + AEAD_TAG_SIZE;
  45. impl TxRcpt {
  46. /// encrypt received coin, by recipient public key
  47. pub fn encrypt(&self, public: &PublicKey) -> EncryptedTxRcpt {
  48. let ephem_secret = SecretKey::random(&mut OsRng);
  49. let ephem_public = PublicKey::from_secret(ephem_secret);
  50. let shared_secret = sapling_ka_agree(&ephem_secret, public);
  51. let key = kdf_sapling(&shared_secret, &ephem_public);
  52. let mut input = Vec::new();
  53. self.encode(&mut input).unwrap();
  54. let mut ciphertext = [0u8; CIPHER_SIZE];
  55. assert_eq!(
  56. ChachaPolyIetf::aead_cipher()
  57. .seal_to(&mut ciphertext, &input, &[], key.as_ref(), &[0u8; 12])
  58. .unwrap(),
  59. CIPHER_SIZE
  60. );
  61. EncryptedTxRcpt { ciphertext, ephem_public }
  62. }
  63. }
  64. #[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
  65. pub struct EncryptedTxRcpt {
  66. ciphertext: [u8; CIPHER_SIZE],
  67. ephem_public: PublicKey,
  68. }
  69. impl EncryptedTxRcpt {
  70. pub fn decrypt(&self, secret: &SecretKey) -> TxRcpt {
  71. let shared_secret = sapling_ka_agree(secret, &self.ephem_public);
  72. let key = kdf_sapling(&shared_secret, &self.ephem_public);
  73. let mut plaintext = [0; CIPHER_SIZE];
  74. assert_eq!(
  75. ChachaPolyIetf::aead_cipher()
  76. .open_to(&mut plaintext, &self.ciphertext, &[], key.as_ref(), &[0u8; 12])
  77. .map_err(|_| Error::TxRcptDecryptionError)
  78. .unwrap(),
  79. PLAINTEXT_SIZE
  80. );
  81. TxRcpt::decode(&plaintext[..]).unwrap()
  82. }
  83. }