diff --git a/ironfish-rust/src/keys/public_address.rs b/ironfish-rust/src/keys/public_address.rs index 2b28fcfdd4..459dac0b83 100644 --- a/ironfish-rust/src/keys/public_address.rs +++ b/ironfish-rust/src/keys/public_address.rs @@ -19,19 +19,21 @@ pub const PUBLIC_ADDRESS_SIZE: usize = 32; /// transmission key. Using the incoming_viewing_key allows /// the creation of a unique public addresses without revealing the viewing key. #[derive(Clone, Copy)] -pub struct PublicAddress { - /// The transmission key is the result of combining the diversifier with the - /// incoming viewing key (a non-reversible operation). Together, the two - /// form a public address to which payments can be sent. - pub(crate) transmission_key: SubgroupPoint, -} +pub struct PublicAddress(pub(crate) SubgroupPoint); impl PublicAddress { /// Initialize a public address from its 32 byte representation. - pub fn new(address_bytes: &[u8; PUBLIC_ADDRESS_SIZE]) -> Result { - let transmission_key = PublicAddress::load_transmission_key(&address_bytes[0..])?; + pub fn new(public_address_bytes: &[u8; PUBLIC_ADDRESS_SIZE]) -> Result { + + assert!(public_address_bytes.len() == 32); + let public_address_non_prime = + SubgroupPoint::from_bytes(public_address_bytes.try_into().unwrap()); - Ok(PublicAddress { transmission_key }) + if public_address_non_prime.is_some().into() { + Ok(PublicAddress(public_address_non_prime.unwrap())) + } else { + Err(IronfishError::new(IronfishErrorKind::InvalidPaymentAddress)) + } } /// Load a public address from a Read implementation (e.g: socket, file) @@ -48,9 +50,7 @@ impl PublicAddress { } pub fn from_view_key(view_key: &IncomingViewKey) -> PublicAddress { - PublicAddress { - transmission_key: *PUBLIC_KEY_GENERATOR * view_key.view_key, - } + PublicAddress(*PUBLIC_KEY_GENERATOR * view_key.view_key) } /// Convert a String of hex values to a PublicAddress. The String must @@ -65,7 +65,7 @@ impl PublicAddress { /// Retrieve the public address in byte form. pub fn public_address(&self) -> [u8; PUBLIC_ADDRESS_SIZE] { - self.transmission_key.to_bytes() + self.0.to_bytes() } /// Retrieve the public address in hex form. @@ -79,20 +79,6 @@ impl PublicAddress { Ok(()) } - - pub(crate) fn load_transmission_key( - transmission_key_bytes: &[u8], - ) -> Result { - assert!(transmission_key_bytes.len() == 32); - let transmission_key_non_prime = - SubgroupPoint::from_bytes(transmission_key_bytes.try_into().unwrap()); - - if transmission_key_non_prime.is_some().into() { - Ok(transmission_key_non_prime.unwrap()) - } else { - Err(IronfishError::new(IronfishErrorKind::InvalidPaymentAddress)) - } - } } impl std::fmt::Debug for PublicAddress { @@ -109,7 +95,10 @@ impl std::cmp::PartialEq for PublicAddress { #[cfg(test)] mod test { - use crate::{keys::PUBLIC_ADDRESS_SIZE, PublicAddress, SaplingKey}; + use crate::{ + keys::{PublicAddress, PUBLIC_ADDRESS_SIZE}, + SaplingKey, + }; #[test] fn public_address_validation() { diff --git a/ironfish-rust/src/keys/test.rs b/ironfish-rust/src/keys/test.rs index f49b4211ad..997785307a 100644 --- a/ironfish-rust/src/keys/test.rs +++ b/ironfish-rust/src/keys/test.rs @@ -27,7 +27,7 @@ fn test_diffie_hellman_shared_key() { let secret_key = key_pair.secret(); let public_key = key_pair.public(); - let shared_secret1 = shared_secret(secret_key, &address1.transmission_key, public_key); + let shared_secret1 = shared_secret(secret_key, &address1.0, public_key); let shared_secret2 = shared_secret(&key1.incoming_viewing_key.view_key, public_key, public_key); assert_eq!(shared_secret1, shared_secret2); } @@ -44,15 +44,11 @@ fn test_diffie_hellman_shared_key_with_other_key() { let secret_key = key_pair.secret(); let public_key = key_pair.public(); - let shared_secret1 = shared_secret(secret_key, &address.transmission_key, public_key); + let shared_secret1 = shared_secret(secret_key, &address.0, public_key); let shared_secret2 = shared_secret(&key.incoming_viewing_key.view_key, public_key, public_key); assert_eq!(shared_secret1, shared_secret2); - let shared_secret_third_party1 = shared_secret( - secret_key, - &third_party_address.transmission_key, - public_key, - ); + let shared_secret_third_party1 = shared_secret(secret_key, &third_party_address.0, public_key); assert_ne!(shared_secret1, shared_secret_third_party1); assert_ne!(shared_secret2, shared_secret_third_party1); @@ -90,8 +86,8 @@ fn test_serialization() { .expect("Should be able to construct address from valid bytes"); assert_eq!( - ExtendedPoint::from(read_back_address.transmission_key).to_affine(), - ExtendedPoint::from(public_address.transmission_key).to_affine() + ExtendedPoint::from(read_back_address.0).to_affine(), + ExtendedPoint::from(public_address.0).to_affine() ) } diff --git a/ironfish-rust/src/merkle_note.rs b/ironfish-rust/src/merkle_note.rs index c28a0cdd88..4d9ac3a4c8 100644 --- a/ironfish-rust/src/merkle_note.rs +++ b/ironfish-rust/src/merkle_note.rs @@ -82,7 +82,7 @@ impl MerkleNote { let public_key = diffie_hellman_keys.public(); let mut key_bytes = [0; 64]; - key_bytes[..32].copy_from_slice(¬e.owner.transmission_key.to_bytes()); + key_bytes[..32].copy_from_slice(¬e.owner.0.to_bytes()); key_bytes[32..].clone_from_slice(secret_key.to_repr().as_ref()); let encryption_key = calculate_key_for_encryption_keys( @@ -131,11 +131,7 @@ impl MerkleNote { let secret_key = diffie_hellman_keys.secret(); let public_key = diffie_hellman_keys.public(); - let encrypted_note = note.encrypt(&shared_secret( - secret_key, - ¬e.owner.transmission_key, - public_key, - )); + let encrypted_note = note.encrypt(&shared_secret(secret_key, ¬e.owner.0, public_key)); MerkleNote { value_commitment: value_commitment.commitment().into(), @@ -204,11 +200,10 @@ impl MerkleNote { let note_encryption_keys: [u8; ENCRYPTED_SHARED_KEY_SIZE] = aead::decrypt(&encryption_key, &self.note_encryption_keys)?; - let transmission_key = PublicAddress::load_transmission_key(¬e_encryption_keys[..32])?; + let public_address = PublicAddress::new(¬e_encryption_keys[..32])?; let secret_key = read_scalar(¬e_encryption_keys[32..])?; - let shared_key = shared_secret(&secret_key, &transmission_key, &self.ephemeral_public_key); - let note = - Note::from_spender_encrypted(transmission_key, &shared_key, &self.encrypted_note)?; + let shared_key = shared_secret(&secret_key, &public_address, &self.ephemeral_public_key); + let note = Note::from_spender_encrypted(public_address, &shared_key, &self.encrypted_note)?; note.verify_commitment(self.note_commitment)?; Ok(note) } diff --git a/ironfish-rust/src/note.rs b/ironfish-rust/src/note.rs index 4468fd4402..a9e0f7cb11 100644 --- a/ironfish-rust/src/note.rs +++ b/ironfish-rust/src/note.rs @@ -201,14 +201,14 @@ impl<'a> Note { /// This function allows the owner to decrypt the note using the derived /// shared secret and their own view key. pub(crate) fn from_spender_encrypted( - transmission_key: SubgroupPoint, + public_address: SubgroupPoint, shared_secret: &[u8; 32], encrypted_bytes: &[u8; ENCRYPTED_NOTE_SIZE + aead::MAC_SIZE], ) -> Result { let (randomness, asset_id, value, memo, sender) = Note::decrypt_note_parts(shared_secret, encrypted_bytes)?; - let owner = PublicAddress { transmission_key }; + let owner = PublicAddress(public_address); Ok(Note { owner, @@ -278,9 +278,9 @@ impl<'a> Note { commitment_full_point( self.asset_generator(), self.value, - self.owner.transmission_key, + self.owner.0, self.randomness, - self.sender.transmission_key, + self.sender.0, ) } @@ -409,8 +409,7 @@ mod test { let dh_secret = diffie_hellman_keys.secret(); let dh_public = diffie_hellman_keys.public(); - let public_shared_secret = - shared_secret(dh_secret, &public_address.transmission_key, dh_public); + let public_shared_secret = shared_secret(dh_secret, &public_address.0, dh_public); let note = Note::new(public_address, 42, "", NATIVE_ASSET, sender_address); let encryption_result = note.encrypt(&public_shared_secret); @@ -434,12 +433,9 @@ mod test { note.sender.public_address() ); - let spender_decrypted = Note::from_spender_encrypted( - note.owner.transmission_key, - &public_shared_secret, - &encryption_result, - ) - .expect("Should be able to load from transmission key"); + let spender_decrypted = + Note::from_spender_encrypted(note.owner.0, &public_shared_secret, &encryption_result) + .expect("Should be able to load from transmission key"); assert!( spender_decrypted.owner.public_address().as_ref() == note.owner.public_address().as_ref() diff --git a/ironfish-rust/src/transaction/mints.rs b/ironfish-rust/src/transaction/mints.rs index a2c3bc5eac..3f4fc57533 100644 --- a/ironfish-rust/src/transaction/mints.rs +++ b/ironfish-rust/src/transaction/mints.rs @@ -201,7 +201,7 @@ impl MintDescription { public_inputs[0] = randomized_public_key_point.get_u(); public_inputs[1] = randomized_public_key_point.get_v(); - let public_address_point = ExtendedPoint::from(self.owner.transmission_key).to_affine(); + let public_address_point = ExtendedPoint::from(self.owner.0).to_affine(); public_inputs[2] = public_address_point.get_u(); public_inputs[3] = public_address_point.get_v(); diff --git a/ironfish-rust/src/transaction/outputs.rs b/ironfish-rust/src/transaction/outputs.rs index 7d7f6ebd55..b5c5fa5709 100644 --- a/ironfish-rust/src/transaction/outputs.rs +++ b/ironfish-rust/src/transaction/outputs.rs @@ -84,7 +84,7 @@ impl OutputBuilder { let circuit = Output { value_commitment: Some(self.value_commitment.clone()), - payment_address: Some(self.note.owner.transmission_key), + payment_address: Some(self.note.owner.0), commitment_randomness: Some(self.note.randomness), esk: Some(*diffie_hellman_keys.secret()), asset_id: *self.note.asset_id().as_bytes(), diff --git a/ironfish-rust/src/transaction/spends.rs b/ironfish-rust/src/transaction/spends.rs index 8fb281ee6c..3ebd4ab631 100644 --- a/ironfish-rust/src/transaction/spends.rs +++ b/ironfish-rust/src/transaction/spends.rs @@ -99,12 +99,12 @@ impl SpendBuilder { let circuit = Spend { value_commitment: Some(self.value_commitment.clone()), proof_generation_key: Some(spender_key.sapling_proof_generation_key()), - payment_address: Some(self.note.owner.transmission_key), + payment_address: Some(self.note.owner.0), auth_path: self.auth_path.clone(), commitment_randomness: Some(self.note.randomness), anchor: Some(self.root_hash), ar: Some(*public_key_randomness), - sender_address: Some(self.note.sender.transmission_key), + sender_address: Some(self.note.sender.0), }; // Proof that the spend was valid and successful for the provided owner