Skip to content

Commit

Permalink
feat: add support for additional transaction keys in key image genera…
Browse files Browse the repository at this point in the history
…tion
  • Loading branch information
Charon-Fan committed Dec 11, 2024
1 parent e59e15a commit c78c382
Show file tree
Hide file tree
Showing 2 changed files with 130 additions and 4 deletions.
130 changes: 128 additions & 2 deletions rust/apps/monero/src/key_images.rs
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,29 @@ fn generate_key_image<R: RngCore + CryptoRng>(
keypair: &KeyPair,
tx_pubkey: &[u8; 32],
pubkey: &[u8; 32],
additional_tx_keys: Vec<PublicKey>,
internal_output_index: u64,
major: u32,
minor: u32,
mut rng: R,
) -> KeyImageAndSignature {
let mut additional_tx_pub_key = None;
if additional_tx_keys.len() == 1 {
additional_tx_pub_key = Some(additional_tx_keys[0]);
} else if !additional_tx_keys.is_empty() {
if internal_output_index as usize >= additional_tx_keys.len() {
panic!("Wrong number of additional derivations");
}
additional_tx_pub_key = Some(additional_tx_keys[internal_output_index as usize]);
}

let key_to_use = match additional_tx_pub_key {
Some(key) => &key.as_bytes(),
None => tx_pubkey,
};

let prvkey =
calc_key_image_private_key(keypair, tx_pubkey, internal_output_index, major, minor);
calc_key_image_private_key(keypair, key_to_use, internal_output_index, major, minor);

let image = generate_key_image_from_priavte_key(&prvkey.clone());

Expand Down Expand Up @@ -213,16 +229,34 @@ impl ExportedTransferDetail {
keypair,
&self.tx_pubkey,
&self.pubkey,
self.additional_tx_keys.clone(),
self.internal_output_index,
self.major,
self.minor,
rng,
)
}

pub fn generate_key_image_without_signature(&self, keypair: &KeyPair) -> (PublicKey, Keyimage) {
let mut additional_tx_pub_key = None;
let additional_tx_keys = self.additional_tx_keys.clone();
if additional_tx_keys.len() == 1 {
additional_tx_pub_key = Some(additional_tx_keys[0]);
} else if !additional_tx_keys.is_empty() {
if self.internal_output_index as usize >= additional_tx_keys.len() {
panic!("Wrong number of additional derivations");
}
additional_tx_pub_key = Some(additional_tx_keys[self.internal_output_index as usize]);
}

let key_to_use = match additional_tx_pub_key {
Some(key) => &key.as_bytes(),
None => tx_pubkey,
};

let prvkey = calc_key_image_private_key(
keypair,
&self.tx_pubkey,
key_to_use,
self.internal_output_index,
self.major,
self.minor,
Expand Down Expand Up @@ -356,4 +390,96 @@ mod tests {

assert_eq!(hex::encode(key_images_export_data), "4d6f6e65726f206b657920696d616765206578706f727403a7f77b9eb360d066d49f2eaa597fe16862b5c1c90eba00af226a1e6c43b774b2b468994d6ff7ee2a7d829812c2d6adedcb9131133f043ff98223531f2b721ff7c1468885baea1a7acd4d6c929ea8ce07161c7f443e9e6ed19677c6c6f53185a50a0418f14ce26d7988c2190e09a04809346d6d7aabdfe929ce88bed228531a44d4c9f1ee2826dcd2f4d78900");
}

#[test]
fn test_include_additional_keys() {
let sec_s_key = PrivateKey::from_bytes(
&hex::decode("a57cfb517deb1c35a4b8208847f8e5d54a3a54bc82e72f1b6d21e849934e9e06")
.unwrap(),
);
let sec_v_key = PrivateKey::from_bytes(
&hex::decode("c665da45f363a80a637740721e97b0c8249fe2599c14eeac73131438c0b92503")
.unwrap(),
);
let keypair = crate::key::KeyPair::new(sec_v_key.clone(), sec_s_key.clone());

let rng_seed = [0; 32];
let rng = rand_chacha::ChaCha20Rng::from_seed(rng_seed.try_into().unwrap());
let ki = generate_key_image(
&keypair,
&PublicKey::from_bytes(
&hex::decode("3e2ebe8773322defc39251cdb18f0500398e525b6720815e95aced3b24375fcc")
.unwrap(),
)
.unwrap()
.as_bytes(),
&PublicKey::from_bytes(
&hex::decode("2a6780ff9f7ef4b88e60ee4a5731f359a1b3104580bfa304bc534e786af6f74d")
.unwrap(),
)
.unwrap()
.as_bytes(),
vec![
PublicKey::from_bytes(
&hex::decode(
"2b6b1b1988a9bc82fe611ccaf699b45cdec3171f6fa3f052790ff46d70aea4ea",
)
.unwrap(),
)
.unwrap(),
PublicKey::from_bytes(
&hex::decode(
"36d47bbd7f8ba629faef59ab50f0943f42fd84317d4dd59e65733d8ce1823068",
)
.unwrap(),
)
.unwrap(),
PublicKey::from_bytes(
&hex::decode(
"c0d92d8c0104b1a4b9f1b744f4c0cebc3499bf45e32127720040ead9a8867570",
)
.unwrap(),
)
.unwrap(),
],
1,
0,
0,
rng,
);

assert_eq!(
hex::encode(ki.image.0),
"bd4054a880249da808cf609472f4341b5303cd63fb208f1791492bdd7d7c2a8b"
);
}

#[test]
fn test_include_additional_keys_full() {
let sec_s_key = PrivateKey::from_bytes(
&hex::decode("a57cfb517deb1c35a4b8208847f8e5d54a3a54bc82e72f1b6d21e849934e9e06")
.unwrap(),
);
let sec_v_key = PrivateKey::from_bytes(
&hex::decode("c665da45f363a80a637740721e97b0c8249fe2599c14eeac73131438c0b92503")
.unwrap(),
);
let keypair = crate::key::KeyPair::new(sec_v_key.clone(), sec_s_key.clone());

let request = hex::decode("4d6f6e65726f206f7574707574206578706f7274041b341bf5245ce4695c65269995920d92cf58bbc4db89cab0cb54c1e6551ae7873859b62e1c30e0dd941b5152ed0aa9ed9f07d5112801d25c59ae4f4293f2ea350d16f311f57160f1a102290abcd473809e75f48690c75af61645623b2976efb048cd0645765f94b98d336daa2ae84577eaf9bc8bcb1673a8110a361e26eb252a387f168759276b72ffe6bdb53356e27bdb23e94abe7489630d49462ead062e8646e19589dbd7b42374bc03f0a0aa97880aebb4bab8525eb79ed4a60a9b909698e150c68aefa4f1b21f0765ad81a1a129ab04a306cdbf00ac988674c114e88b7b1561d14bca0d3988eae4c465563e8706ef34ec659a244b4e284619c980011dc5a1ec18ceabae38972eb8ddab6547359282fc704d97c21d3dceeed74f2de80c2954ceabc0c7207b2f03fd9a50bcb0bc31f6e3aebeab79f14615bb9d0a9c6d1e7b202abd85004536d5ffdcc9a1df35380c461f1a3b9786b5d511354d4418c12f0ab7a3c61bf16e79b3bb74b72b9f4891b269d49bf3af8fd660cf03348fa71aed636bb7c6ba0f7b34188c1e008a96d930c93f52fccf2c8cd0bd69cac4a75cf0ee96d006824194ef93fbc2f589627e4b4962c5cacf183295f3b9cf7fd5c692a98fd184566229eafc28582822c23a181108e9fe16e993545cd98942acecdf6ab85b4b057de3a3a00b18e499e8314d00c3ca10a39381496e597731f41576a8541ed26e57882d333e7ed68f9c50f34c294b6b18b196c5722dd20d51bbcc4fc13d247f8002af9fd0c6d378dea77d0b04ac8d76b365a84d44a66d5afc7c75736e87e98643a36bdf331b8944206c9ad2a8674fcdcbba44adbb9eb4611ee159a12c6c5c6a32aeb19cb301f1a6d4f1dde50ceafe437a468acb4ba76de67ce48737077d79a6c74465d761d695e4f24f45bcc9190ba1d7441451a1a1eb68e0c376bd459e0129b74319f677adc7b3e45e959a5a6bed9d158eea830fbcf8ee4daee614ac6b7a6a280fdec9406ae724e2574b6368abe0a1b3bf9b3d175f71d85f01c64fd0185a6ee94181a0b7fb9bed43345b211980bb050f8b903a1352d774b187550ea6c98b7fe5df9f3150342d5c52dea4f57cdf17041a31624a195ce91b42f2502af4ca73cea7a95ce539db1fda8bac49e9b380bf51e760b1a4104f7421b98f965267579bf827bc756c8e062daf1113311dbd55457d57755e1d27a932c3711addceddfe79968652ae4db2aabd249e57130ef52fdc3097f2e0287aad3b9b98fcbaada2fc8379b2684137efe2e98c6a4d83f64e5d095e6a730af1243768e7e1b69e1d116fa8c82faf407b3dac920439babfeb433502f276f3a260b012c70a4f4a4ec441e14ad7c909123ebeb81bd3e20dfe5a399e75aa374cb78a28171d0d").unwrap();
let response = "4d6f6e65726f206b657920696d616765206578706f7274030fa260e0b8424999f9c4400d824de57112f408998e61b5bc174bf0899ecae877f7fd4c621665c9efb650ae75a9d667b78e4e5e985b1d06742f14e2cdbd0d1f0e694701ff48412feadd5d76595ba7d3b1e2ad8c5285e43a5e11674e731b3587d9ecbd19819ef678cd62d2890cb2a88b2296c4d3842b236c6ec108943b7f1d99bded561ac8e90be44cee5133d0d2af73b413d0bf8cec51c20115548998486aedf13ad1fa04967ac9660179e32a15d8287995add8217f8b34640870123755813f0c768016bf55ee83891e4bca53404e0b5ba370ed17e67ce119e3dcd20e4039fa8b4a62d245bf5b75b85fb1aad534ee80f6c76cd1d12fbd570b12e78f12c70af3ba512507bcc2700d6182af7b736581e3b44e98992f4552428f7beff79a64a25899d0d81f891c79b44333963648d125af50f039f22c235cb6675ab636a567ce135f9e9f18c3e64609c49498f274ace86ea36bd37b09032ccf55011e5d9a3d654d95eda7b0cead97fa9f2e038b62e3cc7c97c70e72377f7ef6978f07fbe1d966c573080e38e26239177031aad70be00b24546d7507591d73aa17cf0f8f8636419cc4fba60bc54b9e5d7e780bf61ae273a5d8ce01bea3bfba7c489369a5e8029648ba6a7263ca34ec3bdf0390f61e7ab23c8e630da4afee2b31a47c2b11bb2e2f369c480d13537be479f76f3f7422d2b225af7a9ccf312277395b1afbdc05b50c38f5d6f753c0e7eceb64d8ee77db76eddf05c3f213974c52d21f76be45a44aec7893681c880f886f71b0a7e45f9e7cd4ce826c65ab3fec155c6333db6f770458f840b7287db8a3b63657953e386bf16748842e137a5128249c8618238806a70ec8b13ace8eee64d1d05bfeb0d597a2336d29b58e0dd2ed11d2dacab234d5bfcdfe1cbed511592bc1f7fb610df9c1d281e1d96ebe51590eaea230d7dd9433efc608a36263905936ac27a362c7448b337762cafee262af9ef7a0d37d7763587ddfe7891459f8146b67cb8bd15e261352b12535d0ad3952b37d11194f207b3574559a2ee86e6d4e4ff8c1c9771837ac857f21d8e5079c80d3e2de0339661d56341d7d2375ee8c77cdba7a8990bbb0003e25f413bab2c7a28d57009d537c16821c84fb6afae2fcc428194abf26669605";

let res = generate_export_ur_data(keypair.clone(), request.clone()).unwrap();

let response_data = decrypt_data_with_pvk(
keypair.view.to_bytes(),
hex::decode(response).unwrap(),
KEY_IMAGE_EXPORT_MAGIC,
)
.unwrap();
let data =
decrypt_data_with_pvk(keypair.view.to_bytes(), res, KEY_IMAGE_EXPORT_MAGIC).unwrap();

assert_eq!(hex::encode(data.data), hex::encode(response_data.data));
}
}
4 changes: 2 additions & 2 deletions rust/apps/monero/src/outputs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub struct ExportedTransferDetail {
pub tx_pubkey: [u8; 32],
pub flags: u8,
pub amount: u64,
pub additional_tx_keys: Vec<[u8; 32]>,
pub additional_tx_keys: Vec<PublicKey>,
pub major: u32,
pub minor: u32,
}
Expand Down Expand Up @@ -95,7 +95,7 @@ impl ExportedTransferDetails {
tx_pubkey: tx_pubkey.as_bytes(),
flags,
amount,
additional_tx_keys: Vec::new(),
additional_tx_keys: additional_tx_keys,
major: major as u32,
minor: minor as u32,
});
Expand Down

0 comments on commit c78c382

Please sign in to comment.