Skip to content

Commit

Permalink
[tools] support key rotation offer capability in libra-txs (#208)
Browse files Browse the repository at this point in the history
Co-authored-by: coin1111 <celticsnow123@gmail.com>
  • Loading branch information
2 people authored and 0o-de-lally committed Mar 12, 2024
1 parent dd858eb commit d02505b
Show file tree
Hide file tree
Showing 10 changed files with 488 additions and 14 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,7 @@ sccache.log
.idea

# formal verification files
*.bpl
*.bpl

# exclude diem dependency
diem/
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Binary file modified framework/releases/head.mrb
Binary file not shown.
6 changes: 6 additions & 0 deletions private-keys.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
account_address: 058e4b7d6cf1b9cb2b865f76b17073d7da8c6a1b78ea51f33e451420232831d4
account_private_key: "0xbf86f7c31ea8959a9969d8f6c29da1ac3253da2434d3aeb08bd1819ad3509b1d"
consensus_private_key: "0x4c80411f31b8cc4429a1a713e488e28a43667e19a25dbca5acf288e3fbfa31b4"
full_node_network_private_key: "0x90bc05b0f7155e4ee4994acc4edc415ea80ebf0389ec2cd0eaf956aa6560b176"
validator_network_private_key: "0x2885971d054a05d74947efe3716c7b36ee16b77988445358464e96d1b167394d"
7 changes: 7 additions & 0 deletions public-keys.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
account_address: 058e4b7d6cf1b9cb2b865f76b17073d7da8c6a1b78ea51f33e451420232831d4
account_public_key: "0x0e9ff45f96e133323e50cdf65a255cf5078e1332ef6a212e30d811083a5651d7"
consensus_public_key: "0xaba923e2d1646703b9d140c8d3e8623c97d525c2ad96d131195d07fbd7e4dc39788df032bf4129fd464762012d74b692"
consensus_proof_of_possession: "0xa8cc341c57033f806f831e1308c3b6d9711dc7f873ddf29f42b633f918ed0d4aef83967fca5e11b85c4dcf4552a92ec00a43b6a2259ff19a3f32be8de4946d8fd753db4706f2fbe2e41e4c2a363c0ee198b0044e71aaf10cd7189422cd338325"
full_node_network_public_key: "0xe8f084ba20264e3baea8578467f15bc3f534144709adff8adf02d9726eb5ae69"
validator_network_public_key: "0xc8fec65c13af8be06a4d468654f5e9b7635fe862f8c5f501d3b68df669217556"
1 change: 1 addition & 0 deletions tools/txs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ serde_json = { workspace = true }
serde_yaml = { workspace = true }
tokio = { workspace = true }
url = { workspace = true }
serde = { version = "1.0.163", features = ["derive"] }

[dev-dependencies]
diem-temppath = { workspace = true }
Expand Down
178 changes: 165 additions & 13 deletions tools/txs/src/txs_cli_user.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,24 @@
use crate::submit_transaction::Sender;
use diem::common::types::RotationProofChallenge;
use diem_sdk::crypto::ed25519::Ed25519PublicKey;
use diem_sdk::crypto::{PrivateKey, SigningKey, ValidCryptoMaterialStringExt};
use diem_types::{
account_address::AccountAddress, account_config::CORE_CODE_ADDRESS,
transaction::TransactionPayload,
};
use diem_sdk::types::LocalAccount;
use diem_types::account_address::AccountAddress;
use diem_types::{account_config::CORE_CODE_ADDRESS, transaction::TransactionPayload};
use libra_cached_packages::libra_stdlib;
use libra_types::{
exports::{AuthenticationKey, Ed25519PrivateKey},
type_extensions::client_ext::ClientExt,
};
use libra_wallet::account_keys::get_keys_from_prompt;
use serde::{Deserialize, Serialize};
use std::str::FromStr;

#[derive(clap::Subcommand)]
pub enum UserTxs {
RotateKey(RotateKeyTx),
RotationCapability(RotationCapabilityTx),
SetSlow(SetSlowTx),
}

Expand All @@ -38,6 +41,14 @@ impl UserTxs {
);
}
},
UserTxs::RotationCapability(offer_rotation_capability) => {
match offer_rotation_capability.run(sender).await {
Ok(_) => println!("SUCCESS: offered rotation capability"),
Err(e) => {
println!("ERROR: could not offer rotation capability, message: {}", e);
}
}
}
}

Ok(())
Expand All @@ -61,7 +72,12 @@ impl SetSlowTx {
pub struct RotateKeyTx {
#[clap(short, long)]
/// The new authkey to be used
new_private_key: Option<String>, // Dev NOTE: account address has the same bytes as AuthKey
pub new_private_key: Option<String>, // Dev NOTE: account address has the same bytes as AuthKey
#[clap(short, long)]
/// Account address for which rotation is done. It
/// can be different from caller's address if rotation capability has been granted
/// to the caller. Do not specify this if you want to rotate your own key.
pub account_address: Option<String>,
}

impl RotateKeyTx {
Expand All @@ -76,13 +92,30 @@ impl RotateKeyTx {
};

let seq = sender.client().get_sequence_number(user_account).await?;
let payload = rotate_key(
user_account,
sender.local_account.private_key().to_owned(),
sender.local_account.authentication_key(),
seq,
new_private_key,
)?;
let payload = if let Some(account_address) = &self.account_address {
let target_account_address = AccountAddress::from_str(account_address)?;
let target_account = sender
.client()
.get_account(target_account_address)
.await?
.into_inner();
// rotate key for account_address
rotate_key_delegated(
seq,
&target_account_address, // account for which rotation is carried
&target_account.authentication_key, // auth key for an account for which rotation is carried
&new_private_key,
)
} else {
// rotate key for self
rotate_key(
user_account,
sender.local_account.private_key().to_owned(),
sender.local_account.authentication_key(),
seq,
new_private_key,
)
}?;

sender.sign_submit_wait(payload).await?;
Ok(())
Expand All @@ -97,7 +130,7 @@ pub fn rotate_key(
sequence_number: u64,
new_private_key: Ed25519PrivateKey,
) -> anyhow::Result<TransactionPayload> {
// form a rotation proof challence. See account.move
// form a rotation proof challenge. See account.move
let rotation_proof = RotationProofChallenge {
account_address: CORE_CODE_ADDRESS,
module_name: "account".to_string(),
Expand Down Expand Up @@ -132,3 +165,122 @@ pub fn rotate_key(

Ok(payload)
}

/// Create the TransactionPayload for a delegated key transaction using rotation capability
pub fn rotate_key_delegated(
sequence_number: u64,
target_account_address: &AccountAddress, // account for which rotation is carried
target_auth_key: &AuthenticationKey, // auth key for an account for which rotation is carried
new_private_key: &Ed25519PrivateKey,
) -> anyhow::Result<TransactionPayload> {
let new_public_key = Ed25519PublicKey::from(new_private_key);
let rotation_proof = RotationProofChallenge {
account_address: CORE_CODE_ADDRESS,
module_name: String::from("account"),
struct_name: String::from("RotationProofChallenge"),
sequence_number,
originator: *target_account_address,
current_auth_key: AccountAddress::from_bytes(target_auth_key)?,
new_public_key: new_public_key.to_bytes().to_vec(),
};

let rotation_msg = bcs::to_bytes(&rotation_proof)?;

// Signs the struct using the next private key
let rotation_proof_signed_by_new_private_key =
new_private_key.sign_arbitrary_message(&rotation_msg);

let payload = libra_stdlib::account_rotate_authentication_key_with_rotation_capability(
*target_account_address,
0,
new_public_key.to_bytes().to_vec(),
rotation_proof_signed_by_new_private_key.to_bytes().to_vec(),
);

Ok(payload)
}

#[derive(Serialize, Deserialize)]
pub struct RotationCapabilityOfferProofChallengeV2 {
account_address: AccountAddress,
module_name: String,
struct_name: String,
chain_id: u8,
sequence_number: u64,
source_address: AccountAddress,
recipient_address: AccountAddress,
}

/// Offer rotation capability to a delegate address.
/// A delegate address now can rotate a key for this account owner
#[derive(clap::Args)]
pub struct RotationCapabilityTx {
#[clap(short, long)]
pub action: String,

#[clap(short, long)]
pub delegate_address: String,
}
impl RotationCapabilityTx {
pub async fn run(&self, sender: &mut Sender) -> anyhow::Result<()> {
let is_offer = match self.action.to_lowercase().as_str() {
"offer" => true,
"revoke" => false,
_ => return Err(anyhow::anyhow!("Invalid action, allowed: offer, revoke")),
};
let user_account: AccountAddress = sender.local_account.address();
let index_response = sender.client().get_index().await?;
let chain_id = index_response.into_inner().chain_id;

let recipient_address = AccountAddress::from_str(&self.delegate_address)?;
let seq = sender.client().get_sequence_number(user_account).await?;
let payload = if is_offer {
offer_rotation_capability_v2(&sender.local_account, recipient_address, chain_id, seq)
} else {
revoke_rotation_capability(recipient_address)
}?;

sender.sign_submit_wait(payload).await?;
Ok(())
}
}

pub fn offer_rotation_capability_v2(
offerer_account: &LocalAccount,
delegate_account: AccountAddress,
chain_id: u8,
sequence_number: u64,
) -> anyhow::Result<TransactionPayload> {
let rotation_capability_offer_proof = RotationCapabilityOfferProofChallengeV2 {
account_address: CORE_CODE_ADDRESS,
module_name: String::from("account"),
struct_name: String::from("RotationCapabilityOfferProofChallengeV2"),
chain_id,
sequence_number,
source_address: offerer_account.address(),
recipient_address: delegate_account,
};

let rotation_capability_proof_msg = bcs::to_bytes(&rotation_capability_offer_proof);
let rotation_proof_signed = offerer_account
.private_key()
.clone()
.sign_arbitrary_message(&rotation_capability_proof_msg.unwrap());

let payload = libra_stdlib::account_offer_rotation_capability(
rotation_proof_signed.to_bytes().to_vec(),
0,
offerer_account.public_key().to_bytes().to_vec(),
delegate_account,
);

Ok(payload)
}

pub fn revoke_rotation_capability(
delegate_account: AccountAddress,
) -> anyhow::Result<TransactionPayload> {
let payload = libra_stdlib::account_revoke_rotation_capability(delegate_account);

Ok(payload)
}
Loading

0 comments on commit d02505b

Please sign in to comment.