Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion include/URRegistryFFI/lib_ur_registry_ffi.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,8 @@ const char* parse_cardano_signature(struct ExternError*, const char* ur_type, co
// Zcash
const char* parse_zcash_accounts(struct ExternError*, const char* ur_type, const char* cbor_hex);
const char* parse_zcash_pczt(struct ExternError*, const char* ur_type, const char* cbor_hex);
const char* generate_zcash_pczt(struct ExternError*, const char* pczt_hex);
const char* generate_zcash_pczt(struct ExternError*, const char* pczt_hex);

// Kaspa PSKT
const char* generate_kaspa_pskt(struct ExternError*, const char* pskt_hex);
const char* parse_kaspa_pskt(struct ExternError*, const char* ur_type, const char* cbor_hex);
Comment thread
Qkin-Keystone marked this conversation as resolved.
89 changes: 89 additions & 0 deletions libs/ur-registry-ffi/src/kaspa/kaspa_pskt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use crate::{export, util_internal::string_helper::remove_prefix_0x};
use anyhow::{format_err, Error};
use serde_json::json;
use ur_registry::{registry_types::KASPA_PSKT, kaspa::kaspa_pskt::KaspaPskt};
use core::convert::TryInto;

export! {
@Java_com_keystone_sdk_KeystoneNativeSDK_generateKaspaPskt
fn generate_kaspa_pskt(
data: &str
) -> String {
if data.is_empty() {
return json!({"error": "data is required"}).to_string();
}

let bytes = match hex::decode(remove_prefix_0x(data)) {
Ok(v) => v,
Err(_) => return json!({"error": "data is invalid hex"}).to_string(),
};

let cbor_bytes: Vec<u8> = match KaspaPskt::new(bytes).try_into() {
Ok(v) => v,
Err(_) => return json!({"error": "CBOR encode failed"}).to_string(),
};

let cbor_hex = hex::encode(cbor_bytes);
json!({
"type": KASPA_PSKT.get_type(),
"cbor": cbor_hex,
}).to_string()
}

@Java_com_keystone_sdk_KeystoneNativeSDK_parseKaspaPskt
fn parse_kaspa_pskt(ur_type: &str, cbor_hex: &str) -> String {
if KASPA_PSKT.get_type() != ur_type {
return json!({"error": "type not match"}).to_string();
}

let parse = || -> Result<String, Error> {
let cbor = hex::decode(remove_prefix_0x(cbor_hex).to_string())?;
let pskt = KaspaPskt::try_from(cbor).map_err(|_| format_err!("decode failed"))?;
let pskt_hex = hex::encode(pskt.get_pskt());
Ok(pskt_hex)
};

match parse() {
Ok(v) => json!({ "pskt": v }).to_string(),
Err(_) => json!({"error": "PSKT is invalid"}).to_string(),
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn test_generate_kaspa_pskt() {
let data = "0102030405";
let result = generate_kaspa_pskt(data);
let json_result: serde_json::Value = serde_json::from_str(&result).unwrap();

assert_eq!(json_result["type"], "kaspa-pskt");
assert!(json_result["cbor"].as_str().unwrap().starts_with("a1"));

assert!(generate_kaspa_pskt("").contains("data is required"));
}

#[test]
fn test_parse_kaspa_pskt() {
let data = "0102030405";
let gen_res = generate_kaspa_pskt(data);
let json_gen: serde_json::Value = serde_json::from_str(&gen_res).unwrap();
let cbor_hex = json_gen["cbor"].as_str().unwrap();

let parse_res = parse_kaspa_pskt("kaspa-pskt", cbor_hex);
let json_parse: serde_json::Value = serde_json::from_str(&parse_res).unwrap();
assert_eq!(json_parse["pskt"], data);
}

#[test]
fn test_kaspa_pskt_error_cases() {
assert!(generate_kaspa_pskt("0102030G").contains("invalid hex"));

assert!(parse_kaspa_pskt("wrong-type", "a101...").contains("type not match"));

assert!(parse_kaspa_pskt("kaspa-pskt", "ffff").contains("invalid"));
}
}
1 change: 1 addition & 0 deletions libs/ur-registry-ffi/src/kaspa/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod kaspa_pskt;
1 change: 1 addition & 0 deletions libs/ur-registry-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@ mod util_internal;
pub mod utils;
pub mod zcash;
pub mod ergo;
pub mod kaspa;

ffi_support::define_string_destructor!(keystone_sdk_destroy_string);
72 changes: 72 additions & 0 deletions libs/ur-registry/src/kaspa/kaspa_pskt.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use alloc::string::ToString;
use minicbor::data::Int;
use crate::{
cbor::cbor_map,
impl_template_struct,
registry_types::{RegistryType, KASPA_PSKT},
traits::{MapSize, RegistryItem},
types::Bytes,
};

const PSKT: u8 = 1;

impl_template_struct!(KaspaPskt { pskt: Bytes });

impl MapSize for KaspaPskt {
fn map_size(&self) -> u64 {
1
}
}

impl RegistryItem for KaspaPskt {
fn get_registry_type() -> RegistryType<'static> {
KASPA_PSKT
}
}

impl<C> minicbor::Encode<C> for KaspaPskt {
fn encode<W: minicbor::encode::Write>(
&self,
e: &mut minicbor::Encoder<W>,
_ctx: &mut C,
) -> Result<(), minicbor::encode::Error<W::Error>> {
e.map(self.map_size())?;
e.int(Int::from(PSKT))?.bytes(&self.pskt)?;
Ok(())
}
}

impl<'b, C> minicbor::Decode<'b, C> for KaspaPskt {
fn decode(d: &mut minicbor::Decoder<'b>, _ctx: &mut C) -> Result<Self, minicbor::decode::Error> {
let mut result = KaspaPskt::default();
cbor_map(d, &mut result, |key, obj, d| {
let key = u8::try_from(key)
.map_err(|e| minicbor::decode::Error::message(e.to_string()))?;
match key {
PSKT => {
obj.pskt = d.bytes()?.to_vec();
}
_ => {}
}
Ok(())
})?;
Ok(result)
}
}

#[cfg(test)]
mod tests {
use super::*;
use alloc::vec;

#[test]
fn test_kaspa_pskt_encode_decode() {
let data = vec![1, 2, 3, 4, 5];
let pskt = KaspaPskt::new(data.clone());

let cbor = minicbor::to_vec(&pskt).expect("Failed to encode");
let decoded: KaspaPskt = minicbor::decode(&cbor).expect("Failed to decode");

assert_eq!(decoded.get_pskt(), data);
}
}
1 change: 1 addition & 0 deletions libs/ur-registry/src/kaspa/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod kaspa_pskt;
1 change: 1 addition & 0 deletions libs/ur-registry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub mod error;
pub mod ethereum;
pub mod extend;
pub mod iota;
pub mod kaspa;
pub mod keystone;
mod macros;
mod macros_impl;
Expand Down
2 changes: 2 additions & 0 deletions libs/ur-registry/src/macros_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ use crate::{
use crate::{impl_cbor_bytes, impl_ur_try_from_cbor_bytes, impl_ur_try_into_cbor_bytes};
use alloc::string::ToString;
use alloc::vec::Vec;
use crate::kaspa::kaspa_pskt::KaspaPskt;

impl_cbor_bytes!(
Bytes,
Expand Down Expand Up @@ -133,4 +134,5 @@ impl_cbor_bytes!(
IotaSignRequest,
IotaSignHashRequest,
IotaSignature,
KaspaPskt,
);
6 changes: 6 additions & 0 deletions libs/ur-registry/src/registry_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub enum URType {
SolSignature(String),
TronSignRequest(String),
TronSignature(String),
KaspaPskt(String),
}

impl URType {
Expand Down Expand Up @@ -84,6 +85,7 @@ impl URType {
"iota-sign-request" => Ok(URType::IotaSignRequest(type_str.to_string())),
"ergo-sign-request" => Ok(URType::ErgoSignRequest(type_str.to_string())),
"sol-signature" => Ok(URType::SolSignature(type_str.to_string())),
"kaspa-pskt" => Ok(URType::KaspaPskt(type_str.to_string())),
_ => Err(URError::NotSupportURTypeError(type_str.to_string())),
}
}
Expand Down Expand Up @@ -125,6 +127,7 @@ impl URType {
URType::IotaSignHashRequest(type_str) => type_str.to_string(),
URType::ErgoSignRequest(type_str) => type_str.to_string(),
URType::SolSignature(type_str) => type_str.to_string(),
URType::KaspaPskt(type_str) => type_str.to_string(),
}
}
}
Expand Down Expand Up @@ -243,6 +246,9 @@ pub const IOTA_SIGN_REQUEST: RegistryType = RegistryType("iota-sign-request", So
pub const IOTA_SIGNATURE: RegistryType = RegistryType("iota-signature", Some(8502));
pub const IOTA_SIGN_HASH_REQUEST: RegistryType = RegistryType("iota-sign-hash-request", Some(8503));

// Kaspa
pub const KASPA_PSKT: RegistryType = RegistryType("kaspa-pskt", Some(8601));

// Zcash
pub const ZCASH_ACCOUNTS: RegistryType = RegistryType("zcash-accounts", Some(49201));
pub const ZCASH_FULL_VIEWING_KEY: RegistryType =
Expand Down
Loading