note.rs 4.2 KB

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