note.rs 4.1 KB

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