note.rs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2022 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 chacha20poly1305::{AeadInPlace, ChaCha20Poly1305, KeyInit};
  19. use darkfi_serial::{Decodable, Encodable, SerialDecodable, SerialEncodable};
  20. use rand::rngs::OsRng;
  21. use darkfi::{
  22. crypto::diffie_hellman::{kdf_sapling, sapling_ka_agree},
  23. Error, Result,
  24. };
  25. use darkfi_sdk::{
  26. crypto::{PublicKey, SecretKey},
  27. pasta::pallas,
  28. };
  29. pub const AEAD_TAG_SIZE: usize = 16;
  30. pub fn encrypt<T: Encodable>(note: &T, public: &PublicKey) -> Result<EncryptedNote2> {
  31. let ephem_secret = SecretKey::random(&mut OsRng);
  32. let ephem_public = PublicKey::from_secret(ephem_secret);
  33. let shared_secret = sapling_ka_agree(&ephem_secret, public);
  34. let key = kdf_sapling(&shared_secret, &ephem_public);
  35. let mut input = Vec::new();
  36. note.encode(&mut input)?;
  37. let input_len = input.len();
  38. let mut ciphertext = vec![0_u8; input_len + AEAD_TAG_SIZE];
  39. ciphertext[..input_len].copy_from_slice(&input);
  40. ChaCha20Poly1305::new(key.as_ref().into())
  41. .encrypt_in_place([0u8; 12][..].into(), &[], &mut ciphertext)
  42. .unwrap();
  43. Ok(EncryptedNote2 { ciphertext, ephem_public })
  44. }
  45. #[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
  46. pub struct EncryptedNote2 {
  47. ciphertext: Vec<u8>,
  48. ephem_public: PublicKey,
  49. }
  50. impl EncryptedNote2 {
  51. pub fn decrypt<T: Decodable>(&self, secret: &SecretKey) -> Result<T> {
  52. let shared_secret = sapling_ka_agree(secret, &self.ephem_public);
  53. let key = kdf_sapling(&shared_secret, &self.ephem_public);
  54. let ciphertext_len = self.ciphertext.len();
  55. let mut plaintext = vec![0_u8; ciphertext_len];
  56. plaintext.copy_from_slice(&self.ciphertext);
  57. match ChaCha20Poly1305::new(key.as_ref().into()).decrypt_in_place(
  58. [0u8; 12][..].into(),
  59. &[],
  60. &mut plaintext,
  61. ) {
  62. Ok(()) => {
  63. Ok(T::decode(&plaintext[..ciphertext_len - AEAD_TAG_SIZE]).map_err(Error::from)?)
  64. }
  65. Err(e) => Err(Error::NoteDecryptionFailed(e.to_string())),
  66. }
  67. }
  68. }
  69. #[cfg(test)]
  70. mod tests {
  71. use super::*;
  72. use darkfi::crypto::types::{DrkCoinBlind, DrkSerial, DrkValueBlind};
  73. use darkfi_sdk::{
  74. crypto::{Keypair, TokenId},
  75. pasta::group::ff::Field,
  76. };
  77. #[test]
  78. fn test_note_encdec() {
  79. #[derive(SerialEncodable, SerialDecodable)]
  80. struct MyNote {
  81. serial: DrkSerial,
  82. value: u64,
  83. token_id: TokenId,
  84. coin_blind: DrkCoinBlind,
  85. value_blind: DrkValueBlind,
  86. token_blind: DrkValueBlind,
  87. memo: Vec<u8>,
  88. }
  89. let note = MyNote {
  90. serial: DrkSerial::random(&mut OsRng),
  91. value: 110,
  92. token_id: TokenId::from(pallas::Base::random(&mut OsRng)),
  93. coin_blind: DrkCoinBlind::random(&mut OsRng),
  94. value_blind: DrkValueBlind::random(&mut OsRng),
  95. token_blind: DrkValueBlind::random(&mut OsRng),
  96. memo: vec![32, 223, 231, 3, 1, 1],
  97. };
  98. let keypair = Keypair::random(&mut OsRng);
  99. let encrypted_note = encrypt(&note, &keypair.public).unwrap();
  100. let note2: MyNote = encrypted_note.decrypt(&keypair.secret).unwrap();
  101. assert_eq!(note.value, note2.value);
  102. assert_eq!(note.token_id, note2.token_id);
  103. assert_eq!(note.token_blind, note2.token_blind);
  104. assert_eq!(note.memo, note2.memo);
  105. }
  106. }