1use candid::CandidType;
2pub use ic_cdk_management_canister::{
3 EcdsaCurve, EcdsaKeyId, EcdsaPublicKeyArgs, EcdsaPublicKeyResult, SignWithEcdsaArgs, SignWithEcdsaResult,
4};
5use serde::{Deserialize, Serialize};
6
7use crate::{identity::CanisterId, types::CanisterCallError};
8
9pub type EcdsaDerivationPath = Vec<Vec<u8>>;
12
13#[derive(CandidType, Serialize, Deserialize, Debug, Clone)]
49pub struct EcdsaIdentity {
50 pub key_id: EcdsaKeyId,
52
53 pub derivation_path: EcdsaDerivationPath,
55}
56
57#[derive(CandidType, Serialize, Deserialize, Debug, Clone)]
59pub struct MessageHash(Vec<u8>);
60
61#[derive(CandidType, Serialize, Deserialize, Debug, Clone)]
63pub struct MessageHashError;
64impl std::fmt::Display for MessageHashError {
65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 write!(f, "Hash of the message with length of 32 bytes.")
67 }
68}
69impl std::error::Error for MessageHashError {}
70impl TryFrom<Vec<u8>> for MessageHash {
71 type Error = MessageHashError;
72
73 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
74 if value.len() != 32 {
75 return Err(MessageHashError);
76 }
77 Ok(MessageHash(value))
78 }
79}
80
81pub async fn ecdsa_public_key(
84 canister_id: Option<CanisterId>, identity: EcdsaIdentity,
86) -> super::types::CanisterCallResult<EcdsaPublicKeyResult> {
87 ic_cdk_management_canister::ecdsa_public_key(&EcdsaPublicKeyArgs {
88 canister_id,
89 derivation_path: identity.derivation_path,
91 key_id: identity.key_id,
92 })
93 .await
94 .map_err(|err| CanisterCallError {
95 canister_id: crate::identity::CanisterId::management_canister(),
96 method: "ic#ecdsa_public_key".to_string(),
97 message: err.to_string(),
98 })
99}
100
101pub async fn sign_with_ecdsa(
104 identity: EcdsaIdentity,
105 message_hash: MessageHash,
106) -> super::types::CanisterCallResult<SignWithEcdsaResult> {
107 ic_cdk_management_canister::sign_with_ecdsa(&SignWithEcdsaArgs {
108 message_hash: message_hash.0,
109 derivation_path: identity.derivation_path,
110 key_id: identity.key_id,
111 })
112 .await
113 .map_err(|err| CanisterCallError {
114 canister_id: crate::identity::CanisterId::management_canister(),
115 method: "ic#sign_with_ecdsa".to_string(),
116 message: err.to_string(),
117 })
118}