-
Notifications
You must be signed in to change notification settings - Fork 219
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
feat: service for encrypting value #4225
Conversation
8b4e42f
to
aa2d29e
Compare
@@ -0,0 +1,70 @@ | |||
// Copyright 2022, The Tari Project |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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
aa2d29e
to
59ebe59
Compare
There was a problem hiding this 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.
base_layer/wallet_ffi/src/lib.rs
Outdated
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); |
There was a problem hiding this comment.
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
base_layer/wallet_ffi/src/lib.rs
Outdated
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()); |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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 {} |
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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 {} |
There was a problem hiding this comment.
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 {} |
There was a problem hiding this comment.
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.
9af4010
to
039705c
Compare
|
||
use crate::{ | ||
envelope::{DhtMessageFlags, DhtMessageHeader, DhtMessageType, NodeDestination}, | ||
outbound::DhtOutboundError, | ||
version::DhtProtocolVersion, | ||
}; | ||
|
||
#[derive(Debug, Clone, Zeroize, ZeroizeOnDrop)] | ||
#[derive(Debug, Clone, Zeroize)] | ||
#[zeroize(drop)] |
There was a problem hiding this comment.
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.
9b0f19d
to
86bd89d
Compare
0d7de22
to
955e17f
Compare
There was a problem hiding this 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// 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' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// 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 - |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// 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 |
applications/test_faucet/src/main.rs
Outdated
let encryption_keys = generate_keys(); | ||
let encrypted_value = EncryptedValue::encrypt_value(&encryption_keys.k, &commitment, value).unwrap(); |
There was a problem hiding this comment.
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.
2371f85
to
b4cd57a
Compare
09025a3
to
29695cc
Compare
There was a problem hiding this 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:
- The FFI methods, they are not needed (and might even be a security risk)
- 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(), |
There was a problem hiding this comment.
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
aad: b"TARI_AAD_SCAN".as_ref(), | |
aad: b"TARI_AAD_VALUE".as_ref(), |
base_layer/wallet_ffi/src/lib.rs
Outdated
@@ -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( |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
base_layer/wallet_ffi/src/lib.rs
Outdated
@@ -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, |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
5c75d45
to
fc0cea9
Compare
There was a problem hiding this 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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
fc0cea9
to
04bc65a
Compare
Description
EncryptedValue
type.encrypt_value
anddecrypt_value
added to theOutputManagerService
(handle).wallet_ffi
methods:encrypted_value_encrypt
andencrypted_value_decrypt
Motivation and Context
The part of the BP+ feature.
How Has This Been Tested?
Unit tests + CI