1use sui_sdk_types::SignatureScheme;
22
23use crate::SignatureError;
24
25fn join_payload(scheme: SignatureScheme, key: &[u8]) -> Vec<u8> {
27 let mut payload = Vec::with_capacity(1 + key.len());
28 payload.push(scheme.to_u8());
29 payload.extend_from_slice(key);
30 payload
31}
32
33fn split_payload(bytes: &[u8]) -> Result<(SignatureScheme, Vec<u8>), SignatureError> {
39 let (flag, key) = bytes
40 .split_first()
41 .ok_or_else(|| SignatureError::from_source("private key payload is empty"))?;
42 let scheme = SignatureScheme::from_byte(*flag).map_err(|e| {
43 SignatureError::from_source(format!("invalid private key scheme flag: {e}"))
44 })?;
45 Ok((scheme, key.to_vec()))
46}
47
48#[cfg(feature = "bech32")]
50const HRP: &str = "suiprivkey";
51
52#[cfg(feature = "bech32")]
53fn hrp() -> bech32::Hrp {
54 bech32::Hrp::parse(HRP).expect("`suiprivkey` is a valid Bech32 HRP")
56}
57
58#[cfg(feature = "bech32")]
60pub(crate) fn encode(scheme: SignatureScheme, key: &[u8]) -> Result<String, SignatureError> {
61 bech32::encode::<bech32::Bech32>(hrp(), &join_payload(scheme, key))
62 .map_err(|e| SignatureError::from_source(format!("bech32 encode failed: {e}")))
63}
64
65#[cfg(feature = "bech32")]
70pub(crate) fn decode(s: &str) -> Result<(SignatureScheme, Vec<u8>), SignatureError> {
71 let parsed = bech32::primitives::decode::CheckedHrpstring::new::<bech32::Bech32>(s)
72 .map_err(|e| SignatureError::from_source(format!("invalid suiprivkey string: {e}")))?;
73
74 if parsed.hrp() != hrp() {
75 return Err(SignatureError::from_source(format!(
76 "expected `{HRP}` human-readable part",
77 )));
78 }
79
80 let bytes: Vec<u8> = parsed.byte_iter().collect();
81 split_payload(&bytes)
82}
83
84pub(crate) fn encode_base64(scheme: SignatureScheme, key: &[u8]) -> String {
86 use base64ct::Encoding;
87
88 base64ct::Base64::encode_string(&join_payload(scheme, key))
89}
90
91pub(crate) fn decode_base64(s: &str) -> Result<(SignatureScheme, Vec<u8>), SignatureError> {
93 use base64ct::Encoding;
94
95 let bytes = base64ct::Base64::decode_vec(s).map_err(|e| {
96 SignatureError::from_source(format!("invalid base64 private key string: {e}"))
97 })?;
98 split_payload(&bytes)
99}