Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cleanup LegacySwap swap decryption path #4706

Merged
merged 1 commit into from
Jul 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions crates/core/component/dex/src/swap/ciphertext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,13 @@ impl SwapCiphertext {
commitment: note::StateCommitment,
) -> Result<SwapPlaintext> {
let payload_key = PayloadKey::derive_swap(ovk, commitment);
self.decrypt_with_payload_key(&payload_key, commitment)
self.decrypt_with_payload_key(&payload_key)
}

pub fn decrypt_with_payload_key(
&self,
payload_key: &PayloadKey,
commitment: note::StateCommitment,
) -> Result<SwapPlaintext> {
pub fn decrypt_with_payload_key(&self, payload_key: &PayloadKey) -> Result<SwapPlaintext> {
let swap_ciphertext = self.0;
let decryption_result = payload_key
.decrypt_swap(swap_ciphertext.to_vec(), commitment)
.decrypt_swap(swap_ciphertext.to_vec())
.map_err(|_| anyhow::anyhow!("unable to decrypt swap ciphertext"))?;

// TODO: encapsulate plaintext encoding by making this a
Expand Down
44 changes: 8 additions & 36 deletions crates/core/keys/src/symmetric.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,29 +24,15 @@ pub enum PayloadKind {
Memo,
/// Swap is action-scoped.
Swap,
/// A LegacySwap is action-scoped, and is the encryption method
/// used prior to the ECC May 2024 audit. This was added to facilitate
/// decryption of legacy swaps.
LegacySwap,
}

impl PayloadKind {
pub(crate) fn nonce(&self, commitment: Option<StateCommitment>) -> [u8; 12] {
pub(crate) fn nonce(&self) -> [u8; 12] {
match self {
Self::Note => [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
Self::MemoKey => [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
Self::Swap => [2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
Self::Memo => [3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
Self::LegacySwap => {
let mut nonce = [0u8; 12];
nonce[0..12].copy_from_slice(
&commitment
.expect("swaps use the prefix bytes of the swap commitment as a nonce")
.0
.to_bytes()[0..12],
);
nonce
}
}
}
}
Expand Down Expand Up @@ -85,7 +71,7 @@ impl PayloadKey {
/// Encrypt a note, memo, or memo key using the `PayloadKey`.
pub fn encrypt(&self, plaintext: Vec<u8>, kind: PayloadKind) -> Vec<u8> {
let cipher = ChaCha20Poly1305::new(&self.0);
let nonce_bytes = kind.nonce(None);
let nonce_bytes = kind.nonce();
let nonce = Nonce::from_slice(&nonce_bytes);

cipher
Expand All @@ -97,7 +83,7 @@ impl PayloadKey {
pub fn decrypt(&self, ciphertext: Vec<u8>, kind: PayloadKind) -> Result<Vec<u8>> {
let cipher = ChaCha20Poly1305::new(&self.0);

let nonce_bytes = kind.nonce(None);
let nonce_bytes = kind.nonce();
let nonce = Nonce::from_slice(&nonce_bytes);

cipher
Expand All @@ -123,7 +109,7 @@ impl PayloadKey {
/// Encrypt a swap using the `PayloadKey`.
pub fn encrypt_swap(&self, plaintext: Vec<u8>) -> Vec<u8> {
let cipher = ChaCha20Poly1305::new(&self.0);
let nonce_bytes = PayloadKind::Swap.nonce(None);
let nonce_bytes = PayloadKind::Swap.nonce();
let nonce = Nonce::from_slice(&nonce_bytes);

cipher
Expand All @@ -132,28 +118,14 @@ impl PayloadKey {
}

/// Decrypt a swap using the `PayloadKey`.
///
/// In order to decrypt swaps encrypted using the legacy method wherein
/// the nonce used is the first 12 bytes of the swap commitment, we try
/// both decryption methods.
pub fn decrypt_swap(
&self,
ciphertext: Vec<u8>,
commitment: StateCommitment,
) -> Result<Vec<u8>> {
pub fn decrypt_swap(&self, ciphertext: Vec<u8>) -> Result<Vec<u8>> {
let cipher = ChaCha20Poly1305::new(&self.0);

let nonce_bytes = PayloadKind::Swap.nonce(None);
let nonce_bytes = PayloadKind::Swap.nonce();
let nonce = Nonce::from_slice(&nonce_bytes);

// First try new method, then try legacy method
cipher
.decrypt(nonce, ciphertext.as_ref())
.or_else(|_| {
let nonce_bytes = PayloadKind::LegacySwap.nonce(Some(commitment));
let nonce = Nonce::from_slice(&nonce_bytes);
cipher.decrypt(nonce, ciphertext.as_ref())
})
.map_err(|_| anyhow::anyhow!("decryption error"))
}
}
Expand Down Expand Up @@ -242,7 +214,7 @@ impl OutgoingCipherKey {
// References:
// * Section 5.4.3 of the ZCash protocol spec
// * Section 2.3 RFC 7539
let nonce_bytes = kind.nonce(None);
let nonce_bytes = kind.nonce();
let nonce = Nonce::from_slice(&nonce_bytes);

cipher
Expand All @@ -253,7 +225,7 @@ impl OutgoingCipherKey {
/// Decrypt key material using the `OutgoingCipherKey`.
pub fn decrypt(&self, ciphertext: Vec<u8>, kind: PayloadKind) -> Result<Vec<u8>> {
let cipher = ChaCha20Poly1305::new(&self.0);
let nonce_bytes = kind.nonce(None);
let nonce_bytes = kind.nonce();
let nonce = Nonce::from_slice(&nonce_bytes);

cipher
Expand Down
8 changes: 2 additions & 6 deletions crates/core/transaction/src/is_action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -324,12 +324,8 @@ impl IsAction for Swap {

let plaintext = txp.payload_keys.get(&commitment).and_then(|payload_key| {
// Decrypt swap ciphertext
SwapCiphertext::decrypt_with_payload_key(
&self.body.payload.encrypted_swap,
payload_key,
commitment,
)
.ok()
SwapCiphertext::decrypt_with_payload_key(&self.body.payload.encrypted_swap, payload_key)
.ok()
});

ActionView::Swap(match plaintext {
Expand Down
Loading