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

feat: service for encrypting value #4225

Conversation

therustmonk
Copy link
Contributor

@therustmonk therustmonk commented Jun 22, 2022

Description

  • The PR implements encryption of the EncryptedValue type.
  • The new methods encrypt_value and decrypt_value added to the OutputManagerService (handle).
  • Implemented wallet_ffi methods: encrypted_value_encrypt and encrypted_value_decrypt

Motivation and Context

The part of the BP+ feature.

How Has This Been Tested?

Unit tests + CI

@therustmonk therustmonk force-pushed the service_for_ecrypting_value branch from 8b4e42f to aa2d29e Compare June 22, 2022 23:39
@@ -0,0 +1,70 @@
// Copyright 2022, The Tari Project
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer this file to be under core/src/services

Self {}
}

pub fn encrypt_value(&self, value: MicroTari) -> EncryptedValue {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably needs a secret for the encryption as wel

@therustmonk therustmonk force-pushed the service_for_ecrypting_value branch from aa2d29e to 59ebe59 Compare June 23, 2022 21:42
Copy link
Contributor

@hansieodendaal hansieodendaal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @deniskolodin, some comments below. I think the required functionality is shaping nicely.

Having looked at Aaron's scanning poc together yesterday I believe we can simplify this to follow your original implementation philosophy without the need for a service. An encryption service in the true sense would need to offer more than just the value encryption.

if encrypted_value.is_null() {
error = LibWalletError::from(InterfaceError::NullError("encrypted_value".to_string())).code;
ptr::swap(error_out, &mut error as *mut c_int);
return 0;
}

let encrypted_value = (*encrypted_value).clone();
encrypted_value.todo_decrypt() as c_ulonglong
let value = (*wallet).wallet.encryption_service.decrypt_value(&*encrypted_value);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method will throw an error if the value cannot be decrypted, which must be handled here

Comment on lines 7840 to 7845
let encryption_service = EncryptionServiceHandle::new();
// TODO: Commitment? Encryption Key?
let encryption_key = todo!();
let commitment = todo!();
let expected_encrypted_value =
encryption_service.encrypt_value(&encryption_key, &commitment, amount.into());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not needed, as it is sufficient to test the round trip with encrypted_value_encrypt and encrypted_value_decrypt

EncryptedValue(data)
}

pub fn decrypt_value(&self, value: &EncryptedValue) -> MicroTari {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should throw an error if the value cannot be decrypted, as per Aaron's scanning poc

Self {}
}

pub fn encrypt_value(&self, key: &PrivateKey, commitment: &Commitment, value: MicroTari) -> EncryptedValue {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The encryption_key should be passed into this function

EncryptedValue(data)
}

pub fn decrypt_value(&self, value: &EncryptedValue) -> MicroTari {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The encryption_key should be passed into this function


// TODO: Rename to `EncryptionFactory`
#[derive(Debug, Clone)]
pub struct EncryptionServiceHandle {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I propose to add Aaron's scanning poc code here to encrypt and decrypt the value with a // TODO: note to change it to use the tari_crypto methods when implemented there.

}

#[async_trait]
impl ServiceInitializer for EncryptionServiceInitializer {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See comment above related to this not needing to be a true "service".


// TODO: Rename to `EncryptionFactory`
#[derive(Debug, Clone)]
pub struct EncryptionServiceHandle {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per @stringhandler this should probably not be a true "service". As can be seen from Aaron's scanning poc, the value encryption and decryption is not complex and will only do one thing.


// TODO: Rename to `EncryptionFactory`
#[derive(Debug, Clone)]
pub struct EncryptionServiceHandle {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The encrypt and decrypt methods could probably just move back to EncryptedValue, as the only additional parameter needed will be the encryption_key if Aaron's scanning poc code is implemented directly into those methods.

@therustmonk therustmonk force-pushed the service_for_ecrypting_value branch 12 times, most recently from 9af4010 to 039705c Compare June 26, 2022 06:48

use crate::{
envelope::{DhtMessageFlags, DhtMessageHeader, DhtMessageType, NodeDestination},
outbound::DhtOutboundError,
version::DhtProtocolVersion,
};

#[derive(Debug, Clone, Zeroize, ZeroizeOnDrop)]
#[derive(Debug, Clone, Zeroize)]
#[zeroize(drop)]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In case if we use chacha20poly1305 crate we should use zeroize=1.4 to let cargo solve dependencies.

@therustmonk therustmonk force-pushed the service_for_ecrypting_value branch 8 times, most recently from 9b0f19d to 86bd89d Compare June 27, 2022 15:04
@therustmonk therustmonk marked this pull request as ready for review June 27, 2022 15:09
@therustmonk therustmonk force-pushed the service_for_ecrypting_value branch 2 times, most recently from 0d7de22 to 955e17f Compare June 27, 2022 20:15
Copy link
Contributor

@hansieodendaal hansieodendaal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good apart from the the failing tests, also some comments

@@ -1732,10 +1757,11 @@ where
let blinding_key = PrivateKey::from_bytes(&hash_secret_key(&spending_key))?;
// TODO: This may be usefull for the encrypted value decryption since this is an atomic swap -
// TODO: when fixing 'todo_decrypt'
let _rewind_key = PrivateKey::from_bytes(&hash_secret_key(&blinding_key))?;
let rewind_key = PrivateKey::from_bytes(&hash_secret_key(&blinding_key))?;
let encryption_key = PrivateKey::from_bytes(&hash_secret_key(&rewind_key))?;
// TODO: Fix this logic when 'todo_decrypt' - only commence if the tag is recognized
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// TODO: Fix this logic when 'todo_decrypt' - only commence if the tag is recognized

@@ -1963,15 +1989,21 @@ where
)?;
let rewind_blinding_key = PrivateKey::from_bytes(&hash_secret_key(&spending_key))?;
let recovery_byte_key = PrivateKey::from_bytes(&hash_secret_key(&rewind_blinding_key))?;
let encryption_key = PrivateKey::from_bytes(&hash_secret_key(&recovery_byte_key))?;
// TODO: Fix this logic when 'todo_decrypt' - only commence if the tag is recognized
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// TODO: Fix this logic when 'todo_decrypt' - only commence if the tag is recognized

@@ -97,15 +96,19 @@ where
continue;
}
// TODO: Fix this logic when 'todo_decrypt' - only commence if the tag is recognized
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// TODO: Fix this logic when 'todo_decrypt' - only commence if the tag is recognized

@@ -1732,10 +1757,11 @@ where
let blinding_key = PrivateKey::from_bytes(&hash_secret_key(&spending_key))?;
// TODO: This may be usefull for the encrypted value decryption since this is an atomic swap -
// TODO: when fixing 'todo_decrypt'
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// TODO: when fixing 'todo_decrypt'

@@ -1732,10 +1757,11 @@ where
let blinding_key = PrivateKey::from_bytes(&hash_secret_key(&spending_key))?;
// TODO: This may be usefull for the encrypted value decryption since this is an atomic swap -
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// TODO: This may be usefull for the encrypted value decryption since this is an atomic swap -
// TODO: This may be usefull for the encrypted value decryption since this is an atomic swap

Comment on lines 203 to 204
let encryption_keys = generate_keys();
let encrypted_value = EncryptedValue::encrypt_value(&encryption_keys.k, &commitment, value).unwrap();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should be using the default value here, as faucet UTXOs are not recoverable without respending them.

@therustmonk therustmonk force-pushed the service_for_ecrypting_value branch 3 times, most recently from 2371f85 to b4cd57a Compare June 28, 2022 12:05
@stringhandler stringhandler changed the title feat: service for ecrypting value feat: service for encrypting value Jun 28, 2022
@therustmonk therustmonk force-pushed the service_for_ecrypting_value branch from 09025a3 to 29695cc Compare June 28, 2022 17:35
Copy link
Collaborator

@stringhandler stringhandler left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Happy to merge if we can remove:

  1. The FFI methods, they are not needed (and might even be a security risk)
  2. The output manager handle methods (as far as I can see, they are only used by the FFI)

// Authenticate and decrypt the value
let aead_payload = Payload {
msg: value.as_bytes(),
aad: b"TARI_AAD_SCAN".as_ref(),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes sense to use VALUE here, so that in future we can add extra fields

Suggested change
aad: b"TARI_AAD_SCAN".as_ref(),
aad: b"TARI_AAD_VALUE".as_ref(),

@@ -1144,14 +1144,53 @@ pub unsafe extern "C" fn encrypted_value_as_bytes(
/// memory leak
#[no_mangle]
pub unsafe extern "C" fn encrypted_value_encrypt(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see the need for this method? I think it should be removed from the ffi interface

Copy link
Contributor

@hansieodendaal hansieodendaal Jun 29, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yip, this one was undecided in my head as well when I added it, so agree it can be removed along with the associated output manager handle.

@@ -1168,20 +1207,61 @@ pub unsafe extern "C" fn encrypted_value_encrypt(
/// memory leak
#[no_mangle]
pub unsafe extern "C" fn encrypted_value_decrypt(
wallet: *mut TariWallet,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, this method can be used to arbitrarily decrypt some data

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would argue that we might keep this method. It is very handy for a wallet to be able to detect with a high degree of certainty which UTXOs it owns. That being said, a strategy of detect-ownership-then-request-all-information may very well be completely implemented in the base layer wallet and never touch the front-end.

W.r.t. "arbitrarily decrypt some data"; I think it is equally true or equally difficult for any client and not only clients using the FFI interface.

@therustmonk therustmonk force-pushed the service_for_ecrypting_value branch 10 times, most recently from 5c75d45 to fc0cea9 Compare June 30, 2022 22:22
Copy link
Contributor

@hansieodendaal hansieodendaal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM - all ffi integration tests and all unit tests passed locally

hansieodendaal
hansieodendaal previously approved these changes Jul 1, 2022
Copy link
Contributor

@hansieodendaal hansieodendaal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@therustmonk therustmonk force-pushed the service_for_ecrypting_value branch from fc0cea9 to 04bc65a Compare July 1, 2022 06:52
@stringhandler stringhandler merged commit 6ce6b89 into tari-project:development Jul 1, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants