add key derivation

This commit is contained in:
Ryan Heywood 2024-11-26 14:24:31 -05:00
parent 40467ce13d
commit 10cda7824c
Signed by: ryan
GPG Key ID: 8E401478A3FBEF72
5 changed files with 87 additions and 14 deletions

2
Cargo.lock generated
View File

@ -1046,7 +1046,9 @@ version = "0.1.0"
dependencies = [
"clap",
"icepick-module",
"keyfork-derive-util",
"keyforkd-client",
"keyforkd-models",
"serde",
"serde_json",
"thiserror 2.0.3",

View File

@ -167,7 +167,7 @@ impl Module for Solana {
match (&fee_payer, &fee_payer_address) {
(Some(payer), Some(address)) => {
// Use the provided account
Some((payer.clone(), Pubkey::from_str_const(address)))
Some((u32::from_str(payer).unwrap(), Pubkey::from_str(address).unwrap()))
}
(None, None) => {
// Use the transaction account
@ -185,19 +185,23 @@ impl Module for Solana {
&hash,
);
let transaction = solana_sdk::transaction::Transaction::new_unsigned(message);
let mut required_derivation_indices = vec![];
// TODO: error handling from_str
let from_account = from_account.and_then(|a| u32::from_str(&a).ok()).unwrap_or(0);
required_derivation_indices.push(from_account);
let mut requested_accounts = vec![];
requested_accounts.push(from_account | 1 << 31);
if let Some((account, _)) = &payer_account_and_pk {
requested_accounts.push(*account | 1 << 31);
}
Ok(serde_json::json!({
"blob": transaction,
"derivation-accounts": requested_accounts,
}))
}
Operation::Sign(Sign {}) => {
let blob = request.blob.expect("passed in instruction blob");
let transaction: solana_sdk::transaction::Transaction =
serde_json::from_value(blob).expect("valid message blob");
dbg!(transaction);
let keys = request.derived_keys.unwrap_or_default();
Ok(serde_json::json!({
"blob": []
}))

View File

@ -6,7 +6,9 @@ edition = "2021"
[dependencies]
clap = { version = "4.5.20", features = ["cargo", "derive", "string"] }
icepick-module = { version = "0.1.0", path = "../icepick-module" }
keyfork-derive-util = { version = "0.2.1", registry = "distrust" }
keyforkd-client = { version = "0.2.1", registry = "distrust" }
keyforkd-models = { version = "0.2.0", registry = "distrust" }
serde = { workspace = true, features = ["derive"] }
serde_json.workspace = true
thiserror = "2.0.3"

View File

@ -18,7 +18,33 @@ pub fn get_command(bin_name: &str) -> (&str, Vec<&str>) {
struct ModuleConfig {
name: String,
command_name: Option<String>,
derivation_prefix: String,
algorithm: keyfork_derive_util::request::DerivationAlgorithm,
#[serde(with = "serde_derivation")]
derivation_prefix: keyfork_derive_util::DerivationPath,
}
mod serde_derivation {
use keyfork_derive_util::DerivationPath;
use serde::{Deserialize, Deserializer, Serializer};
use std::str::FromStr;
pub fn serialize<S>(p: &DerivationPath, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let path = p.to_string();
serializer.serialize_str(&path)
}
pub fn deserialize<'de, D>(deserializer: D) -> Result<DerivationPath, D::Error>
where
D: Deserializer<'de>,
{
use serde::de::Error;
String::deserialize(deserializer).and_then(|string| {
DerivationPath::from_str(&string).map_err(|e| Error::custom(e.to_string()))
})
}
}
#[derive(Serialize, Deserialize, Debug, Default)]
@ -45,7 +71,10 @@ pub fn do_cli_thing() {
// and coin_bin otherwise wouldn't live long enough
for module in &config.modules {
let module_name = &module.name;
let bin = module.command_name.clone().unwrap_or_else(|| format!("icepick-{module_name}"));
let bin = module
.command_name
.clone()
.unwrap_or_else(|| format!("icepick-{module_name}"));
let (command, args) = get_command(&bin);
let mut child = Command::new(command)
.args(args)
@ -93,6 +122,10 @@ pub fn do_cli_thing() {
}
let blob = cli_input.as_ref().and_then(|json| json.get("blob"));
let derivation_accounts = cli_input
.as_ref()
.and_then(|json| json.get("derivation-accounts"));
let matches = icepick_command.get_matches();
if let Some((module, matches)) = matches.subcommand() {
if let Some((subcommand, matches)) = matches.subcommand() {
@ -107,19 +140,50 @@ pub fn do_cli_thing() {
for arg in &operation.arguments {
args.insert(&arg.name, matches.get_one::<String>(&arg.name));
}
let (algo, path) = config.modules.iter().find_map(|fmodule| {
if fmodule.name == module {
return Some((fmodule.algorithm.clone(), fmodule.derivation_prefix.clone()))
}
None
}).unwrap();
let mut derived_keys: Vec<Vec<u8>> = vec![];
if let Some(accounts) = derivation_accounts {
let accounts: Vec<keyfork_derive_util::DerivationIndex> =
serde_json::from_value(accounts.clone())
.expect("valid derivation-accounts");
let mut client =
keyforkd_client::Client::discover_socket().expect("keyforkd started");
for account in accounts {
let request = keyfork_derive_util::request::DerivationRequest::new(algo.clone(), &path.clone().chain_push(account));
let request = keyforkd_models::Request::Derivation(request);
let response = client.request(&request).expect("valid derivation");
match response {
keyforkd_models::Response::Derivation(keyfork_derive_util::request::DerivationResponse { data, .. }) => {
derived_keys.push(data.to_vec());
},
_ => panic!("Unexpected response"),
}
}
}
let json = serde_json::json!({
"operation": subcommand,
"values": args,
"derived-keys": [],
"derived-keys": derived_keys,
"blob": blob,
});
let bin = commands.iter().find_map(|(fmodule, fcommand, _)| {
if fmodule == module {
Some(fcommand)
} else {
None
}
}).expect("previously found module should exist in new search");
let bin = commands
.iter()
.find_map(|(fmodule, fcommand, _)| {
if fmodule == module {
Some(fcommand)
} else {
None
}
})
.expect("previously found module should exist in new search");
let (command, args) = get_command(bin);
let mut child = Command::new(command)
.args(args)

View File

@ -1,3 +1,4 @@
[[module]]
name = "sol"
derivation_prefix = "m/44'/501'"
algorithm = "Ed25519"