use sui_sdk_types::SignatureScheme;
use crate::SignatureError;
fn join_payload(scheme: SignatureScheme, key: &[u8]) -> Vec<u8> {
let mut payload = Vec::with_capacity(1 + key.len());
payload.push(scheme.to_u8());
payload.extend_from_slice(key);
payload
}
fn split_payload(bytes: &[u8]) -> Result<(SignatureScheme, Vec<u8>), SignatureError> {
let (flag, key) = bytes
.split_first()
.ok_or_else(|| SignatureError::from_source("private key payload is empty"))?;
let scheme = SignatureScheme::from_byte(*flag).map_err(|e| {
SignatureError::from_source(format!("invalid private key scheme flag: {e}"))
})?;
Ok((scheme, key.to_vec()))
}
#[cfg(feature = "bech32")]
const HRP: &str = "suiprivkey";
#[cfg(feature = "bech32")]
fn hrp() -> bech32::Hrp {
bech32::Hrp::parse(HRP).expect("`suiprivkey` is a valid Bech32 HRP")
}
#[cfg(feature = "bech32")]
pub(crate) fn encode(scheme: SignatureScheme, key: &[u8]) -> Result<String, SignatureError> {
bech32::encode::<bech32::Bech32>(hrp(), &join_payload(scheme, key))
.map_err(|e| SignatureError::from_source(format!("bech32 encode failed: {e}")))
}
#[cfg(feature = "bech32")]
pub(crate) fn decode(s: &str) -> Result<(SignatureScheme, Vec<u8>), SignatureError> {
let parsed = bech32::primitives::decode::CheckedHrpstring::new::<bech32::Bech32>(s)
.map_err(|e| SignatureError::from_source(format!("invalid suiprivkey string: {e}")))?;
if parsed.hrp() != hrp() {
return Err(SignatureError::from_source(format!(
"expected `{HRP}` human-readable part",
)));
}
let bytes: Vec<u8> = parsed.byte_iter().collect();
split_payload(&bytes)
}
pub(crate) fn encode_base64(scheme: SignatureScheme, key: &[u8]) -> String {
use base64ct::Encoding;
base64ct::Base64::encode_string(&join_payload(scheme, key))
}
pub(crate) fn decode_base64(s: &str) -> Result<(SignatureScheme, Vec<u8>), SignatureError> {
use base64ct::Encoding;
let bytes = base64ct::Base64::decode_vec(s).map_err(|e| {
SignatureError::from_source(format!("invalid base64 private key string: {e}"))
})?;
split_payload(&bytes)
}