note.rs 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. use std::io;
  2. use crypto_api_chachapoly::ChachaPolyIetf;
  3. use rand::rngs::OsRng;
  4. use crate::{
  5. crypto::{
  6. diffie_hellman::{kdf_sapling, sapling_ka_agree},
  7. keypair::{PublicKey, SecretKey},
  8. types::*,
  9. },
  10. util::serial::{Decodable, Encodable, ReadExt, WriteExt},
  11. Error, Result,
  12. };
  13. pub const NOTE_PLAINTEXT_SIZE: usize = 32 + // serial
  14. 8 + // value
  15. 32 + // token_id
  16. 32 + // coin_blind
  17. 32; // value_blind
  18. pub const AEAD_TAG_SIZE: usize = 16;
  19. pub const ENC_CIPHERTEXT_SIZE: usize = NOTE_PLAINTEXT_SIZE + AEAD_TAG_SIZE;
  20. #[derive(Copy, Clone, Debug, PartialEq)]
  21. pub struct Note {
  22. pub serial: DrkSerial,
  23. pub value: u64,
  24. pub token_id: DrkTokenId,
  25. pub coin_blind: DrkCoinBlind,
  26. pub value_blind: DrkValueBlind,
  27. }
  28. impl Encodable for Note {
  29. fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
  30. let mut len = 0;
  31. len += self.serial.encode(&mut s)?;
  32. len += self.value.encode(&mut s)?;
  33. len += self.token_id.encode(&mut s)?;
  34. len += self.coin_blind.encode(&mut s)?;
  35. len += self.value_blind.encode(&mut s)?;
  36. Ok(len)
  37. }
  38. }
  39. impl Decodable for Note {
  40. fn decode<D: io::Read>(mut d: D) -> Result<Self> {
  41. Ok(Self {
  42. serial: Decodable::decode(&mut d)?,
  43. value: Decodable::decode(&mut d)?,
  44. token_id: Decodable::decode(&mut d)?,
  45. coin_blind: Decodable::decode(&mut d)?,
  46. value_blind: Decodable::decode(d)?,
  47. })
  48. }
  49. }
  50. impl Note {
  51. pub fn encrypt(&self, public: &PublicKey) -> Result<EncryptedNote> {
  52. let ephem_secret = SecretKey::random(&mut OsRng);
  53. let ephem_public = PublicKey::from_secret(ephem_secret);
  54. let shared_secret = sapling_ka_agree(&ephem_secret, public);
  55. let key = kdf_sapling(&shared_secret, &ephem_public);
  56. let mut input = Vec::new();
  57. self.encode(&mut input)?;
  58. let mut ciphertext = [0u8; ENC_CIPHERTEXT_SIZE];
  59. assert_eq!(
  60. ChachaPolyIetf::aead_cipher()
  61. .seal_to(&mut ciphertext, &input, &[], key.as_ref(), &[0u8; 12])
  62. .unwrap(),
  63. ENC_CIPHERTEXT_SIZE
  64. );
  65. Ok(EncryptedNote { ciphertext, ephem_public })
  66. }
  67. }
  68. #[derive(Debug)]
  69. pub struct EncryptedNote {
  70. ciphertext: [u8; ENC_CIPHERTEXT_SIZE],
  71. ephem_public: PublicKey,
  72. }
  73. impl Encodable for EncryptedNote {
  74. fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
  75. let mut len = 0;
  76. s.write_slice(&self.ciphertext)?;
  77. len += ENC_CIPHERTEXT_SIZE;
  78. len += self.ephem_public.encode(&mut s)?;
  79. Ok(len)
  80. }
  81. }
  82. impl Decodable for EncryptedNote {
  83. fn decode<D: io::Read>(mut d: D) -> Result<Self> {
  84. let mut ciphertext = [0u8; ENC_CIPHERTEXT_SIZE];
  85. d.read_slice(&mut ciphertext[..])?;
  86. Ok(Self { ciphertext, ephem_public: Decodable::decode(d)? })
  87. }
  88. }
  89. impl EncryptedNote {
  90. pub fn decrypt(&self, secret: &SecretKey) -> Result<Note> {
  91. let shared_secret = sapling_ka_agree(secret, &self.ephem_public);
  92. let key = kdf_sapling(&shared_secret, &self.ephem_public);
  93. let mut plaintext = [0; ENC_CIPHERTEXT_SIZE];
  94. assert_eq!(
  95. ChachaPolyIetf::aead_cipher()
  96. .open_to(&mut plaintext, &self.ciphertext, &[], key.as_ref(), &[0u8; 12])
  97. .map_err(|_| Error::NoteDecryptionFailed)?,
  98. NOTE_PLAINTEXT_SIZE
  99. );
  100. Note::decode(&plaintext[..])
  101. }
  102. }
  103. #[cfg(test)]
  104. mod tests {
  105. use super::*;
  106. use crate::crypto::keypair::Keypair;
  107. use group::ff::Field;
  108. #[test]
  109. fn test_note_encdec() {
  110. let note = Note {
  111. serial: DrkSerial::random(&mut OsRng),
  112. value: 110,
  113. token_id: DrkTokenId::random(&mut OsRng),
  114. coin_blind: DrkCoinBlind::random(&mut OsRng),
  115. value_blind: DrkValueBlind::random(&mut OsRng),
  116. };
  117. let keypair = Keypair::random(&mut OsRng);
  118. let encrypted_note = note.encrypt(&keypair.public).unwrap();
  119. let note2 = encrypted_note.decrypt(&keypair.secret).unwrap();
  120. assert_eq!(note.value, note2.value);
  121. assert_eq!(note.token_id, note2.token_id);
  122. }
  123. }