Add support for SLIP39 in Cardano wallet functionality
What changed, and why it matters
This commit adds support for the SLIP39 standard (a way to split a wallet backup into multiple shares) to the Cardano wallet features of a Keystone hardware wallet. It is a feature addition, not a clear security fix. The code changes how Cardano master keys are derived when a SLIP39 wallet is used, and removes several UI blocks that previously disabled Cardano for SLIP39 users. There is no vendor statement or external report saying this commit fixes a vulnerability.
Treat this as a feature commit rather than a security patch. Reviewers should verify that the new SLIP23 implementation matches the SLIP-0023 specification exactly, that the `is_slip39` flag cannot be spoofed by untrusted callers, and that removing the previous Cardano/SLIP39 disable guards does not expose users to derivation-path or key-management edge cases. No urgent patching is indicated by the commit itself.
Security signals we found
New cryptographic key-derivation path added (SLIP-0023) for Cardano
Previous guard that disabled Cardano for SLIP39 wallets removed
Branching logic between BIP39 and SLIP39 master-key derivation in signing functions
Entropy length restricted to 16 or 32 bytes in new `cardano_get_pubkey_by_slip23` FFI
No explicit security bug or vulnerability described in commit message or diff
Evidence from the diff
The patch introduces a new Rust module slip23.rs implementing SLIP-0023 Cardano master-key derivation from a seed, exposes it through FFI, and wires it into address derivation, transaction signing, Catalyst voting, and CIP-8 data signing. It also removes the previous restriction that disabled Cardano (BIP32_ED25519) for SLIP39 wallets in account_public_info.c and in several UI widgets. A helper generate_master_key now branches between the existing Icarus/BIP39 derivation and the new SLIP23 derivation based on an is_slip39 flag. The change also includes minor UI/flash-handling adjustments and a stack-size increase.
Changed components
rust/apps/cardano/src/slip23.rsrust/apps/cardano/src/address.rsrust/apps/cardano/src/errors.rsrust/apps/cardano/src/lib.rsrust/rust_c/src/cardano/mod.rssrc/crypto/account_public_info.csrc/ui/gui_chain/multi/web3/gui_ada.csrc/ui/gui_widgets/multi/gui_key_derivation_request_widgets.csrc/ui/gui_widgets/multi/gui_multi_accounts_receive_widgets.csrc/ui/gui_widgets/multi/web3/gui_connect_wallet_widgets.csrc/ui/gui_widgets/multi/web3/gui_general_home_widgets.cInspect captured patch +340 / −85
diff --git a/rust/apps/cardano/src/address.rs b/rust/apps/cardano/src/address.rs
index 0c76928..605069c 100644
--- a/rust/apps/cardano/src/address.rs
+++ b/rust/apps/cardano/src/address.rs
@@ -1,6 +1,7 @@
use crate::errors::{CardanoError, R};
use alloc::string::{String, ToString};
+use crate::slip23::{from_seed_slip23, from_seed_slip23_path};
use cardano_serialization_lib::protocol_types::credential::*;
use cardano_serialization_lib::protocol_types::{
BaseAddress, Ed25519KeyHash, EnterpriseAddress, RewardAddress,
@@ -9,6 +10,7 @@ use cryptoxide::hashing::blake2b_224;
use ed25519_bip32_core::{DerivationScheme, XPub};
use hex;
use ur_registry::crypto_key_path::CryptoKeyPath;
+
pub enum AddressType {
Base,
Stake,
@@ -255,4 +257,18 @@ mod tests {
"ca0e65d9bb8d0dca5e88adc5e1c644cc7d62e5a139350330281ed7e3a6938d2c"
);
}
+
+ #[test]
+ fn test_address_from_slip39_ms() {
+ let path = "m/1852'/1815'/0'";
+ let seed = hex::decode("c080e9d40873204bb1bb5837dc88886b").unwrap();
+ let xpub = from_seed_slip23_path(&seed, path)
+ .unwrap()
+ .xprv
+ .public()
+ .to_string();
+ let spend_address =
+ derive_address(xpub.to_string(), 0, 0, 0, AddressType::Base, 1).unwrap();
+ assert_eq!("addr1q9jlm0nq3csn7e6hs9ndt8yhwy4pzxtaq5vvs7zqdzyqv0e9wqpqu38y55a5xjx36lvu49apd4ke34q3ajus2ayneqcqqqnxcc", spend_address)
+ }
}
diff --git a/rust/apps/cardano/src/errors.rs b/rust/apps/cardano/src/errors.rs
index 19e4cc6..e7e16f9 100644
--- a/rust/apps/cardano/src/errors.rs
+++ b/rust/apps/cardano/src/errors.rs
@@ -16,6 +16,8 @@ pub enum CardanoError {
UnsupportedTransaction(String),
#[error("error occurs when signing cardano transaction: {0}")]
SigningFailed(String),
+ #[error("invalid seed: {0}")]
+ InvalidSeed(String),
}
pub type R<T> = Result<T, CardanoError>;
@@ -47,4 +49,10 @@ mod tests {
let error = CardanoError::InvalidTransaction("test".to_string());
assert_eq!(error.to_string(), "invalid transaction: test");
}
+
+ #[test]
+ fn test_invalid_seed_error() {
+ let error = CardanoError::InvalidSeed("test".to_string());
+ assert_eq!(error.to_string(), "invalid seed: test");
+ }
}
diff --git a/rust/apps/cardano/src/lib.rs b/rust/apps/cardano/src/lib.rs
index 1b5ad5b..79363ce 100644
--- a/rust/apps/cardano/src/lib.rs
+++ b/rust/apps/cardano/src/lib.rs
@@ -9,5 +9,6 @@ extern crate std;
pub mod address;
pub mod errors;
pub mod governance;
+pub mod slip23;
pub mod structs;
pub mod transaction;
diff --git a/rust/apps/cardano/src/slip23.rs b/rust/apps/cardano/src/slip23.rs
new file mode 100644
index 0000000..72d9e7e
--- /dev/null
+++ b/rust/apps/cardano/src/slip23.rs
@@ -0,0 +1,151 @@
+use crate::errors::{CardanoError, R};
+use alloc::{format, string::ToString, vec::Vec};
+use cryptoxide::hashing::sha512;
+use ed25519_bip32_core::{DerivationScheme, XPrv};
+use keystore::algorithms::crypto::hmac_sha512;
+
+#[derive(Debug, Clone)]
+pub struct CardanoHDNode {
+ pub xprv: XPrv,
+ pub fingerprint: [u8; 4],
+}
+
+impl CardanoHDNode {
+ pub fn new(xprv: XPrv) -> Self {
+ let fingerprint = Self::calculate_fingerprint(&xprv);
+ Self { xprv, fingerprint }
+ }
+
+ fn calculate_fingerprint(xprv: &XPrv) -> [u8; 4] {
+ let pubkey = xprv.public().public_key();
+ let mut fingerprint = [0u8; 4];
+ fingerprint.copy_from_slice(&pubkey[..4]);
+ fingerprint
+ }
+}
+
+// https://github.com/satoshilabs/slips/blob/master/slip-0023.md
+pub fn from_seed_slip23(seed: &[u8]) -> R<CardanoHDNode> {
+ if seed.is_empty() {
+ return Err(CardanoError::InvalidSeed("seed is empty".to_string()));
+ }
+
+ // Step 2: Calculate I := HMAC-SHA512(Key = "ed25519 cardano seed", Data = S)
+ let i = hmac_sha512(b"ed25519 cardano seed", seed);
+
+ // Step 3: Split I into two 32-byte sequences: IL := I[0:32] and IR := I[32:64]
+ let il = &i[0..32];
+ let ir = &i[32..64];
+
+ // Step 4: Let k := SHA-512(IL)
+ let mut k = [0u8; 64];
+ k.copy_from_slice(&sha512(il));
+
+ // Step 5: Modify k by specific bit operations for EdDSA compatibility
+ k[0] = k[0] & 0xf8; // Clear the 3 least significant bits
+ k[31] = (k[31] & 0x1f) | 0x40; // Set the 6th bit and clear the 3 most significant bits
+
+ // Step 6: Construct the 96-byte extended private key
+ let mut extended_key = [0u8; 96];
+
+ // kL := k[0:32] (interpreted as 256-bit integer in little-endian)
+ extended_key[0..32].copy_from_slice(&k[0..32]);
+
+ // kR := k[32:64]
+ extended_key[32..64].copy_from_slice(&k[32..64]);
+
+ // c := IR (root chain code)
+ extended_key[64..96].copy_from_slice(ir);
+
+ // Create XPrv using normalize_bytes_force3rd
+ let xprv = XPrv::normalize_bytes_force3rd(extended_key);
+
+ let hd_node = CardanoHDNode::new(xprv);
+
+ Ok(hd_node)
+}
+
+pub fn from_seed_slip23_path(seed: &[u8], path: &str) -> R<CardanoHDNode> {
+ let root_node = from_seed_slip23(seed)?;
+
+ let components = parse_derivation_path(path)?;
+ let mut current_xprv = root_node.xprv;
+
+ for component in components {
+ current_xprv = current_xprv.derive(DerivationScheme::V2, component);
+ }
+
+ Ok(CardanoHDNode::new(current_xprv))
+}
+
+fn parse_derivation_path(path: &str) -> R<Vec<u32>> {
+ let mut components = Vec::new();
+
+ let path = path.strip_prefix("m/").unwrap_or(path);
+ for part in path.split('/') {
+ if part.is_empty() {
+ continue;
+ }
+
+ let hardened = part.ends_with('\'');
+ let index_str = if hardened {
+ &part[..part.len() - 1]
+ } else {
+ part
+ };
+
+ let index: u32 = index_str.parse().map_err(|_| {
+ CardanoError::DerivationError(format!("Invalid path component: {}", part))
+ })?;
+
+ if hardened {
+ components.push(index + 0x80000000);
+ } else {
+ components.push(index);
+ }
+ }
+
+ Ok(components)
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use hex;
+
+ #[test]
+ fn test_from_seed_slip23() {
+ let seed = hex::decode("578d685d20b602683dc5171df411d3e2").unwrap();
+ let result = from_seed_slip23(&seed);
+ assert!(result.is_ok());
+
+ let pubkey = result.unwrap().xprv.public().public_key();
+ assert_eq!(pubkey.len(), 32);
+ assert_eq!(
+ "83e3ecaf57f90f022c45e10d1b8cb78499c30819515ad9a81ad82139fdb12a90",
+ hex::encode(pubkey)
+ );
+ }
+
+ #[test]
+ fn test_parse_derivation_path() {
+ let path = "m/1852'/1815'/0'/0/0";
+ let result = parse_derivation_path(path);
+ assert!(result.is_ok());
+ assert_eq!(result.unwrap(), vec![2147485500, 2147485463, 2147483648, 0, 0]);
+ }
+
+ #[test]
+ fn test_from_seed_slip23_path() {
+ let seed = hex::decode("578d685d20b602683dc5171df411d3e2").unwrap();
+ let path = "m/1852'/1815'/0'/0/0";
+ let result = from_seed_slip23_path(&seed, path);
+ assert!(result.is_ok());
+ let pubkey = result.unwrap().xprv.public().public_key();
+ assert_eq!(pubkey.len(), 32);
+ assert_eq!(
+ "4510fd55f00653b0dec9153bdc65feba664ccd543a66f5a1438c759a0bc41e1c",
+ hex::encode(pubkey)
+ );
+ }
+}
diff --git a/rust/keystore/src/algorithms/ed25519/slip10_ed25519.rs b/rust/keystore/src/algorithms/ed25519/slip10_ed25519.rs
index 424c0d6..af0f8c7 100644
--- a/rust/keystore/src/algorithms/ed25519/slip10_ed25519.rs
+++ b/rust/keystore/src/algorithms/ed25519/slip10_ed25519.rs
@@ -56,7 +56,7 @@ pub fn sign_message_by_seed(seed: &[u8], path: &String, message: &[u8]) -> Resul
Ok(cryptoxide::ed25519::signature(message, &keypair))
}
-fn get_master_key_by_seed(seed: &[u8]) -> [u8; 64] {
+pub fn get_master_key_by_seed(seed: &[u8]) -> [u8; 64] {
hmac_sha512(b"ed25519 seed", seed)
}
diff --git a/rust/rust_c/src/cardano/mod.rs b/rust/rust_c/src/cardano/mod.rs
index 8056f78..3fbf582 100644
--- a/rust/rust_c/src/cardano/mod.rs
+++ b/rust/rust_c/src/cardano/mod.rs
@@ -360,6 +360,18 @@ pub extern "C" fn cardano_get_path(ptr: PtrUR) -> Ptr<SimpleResponse<c_char>> {
}
}
+fn generate_master_key(
+ entropy: &[u8],
+ passphrase: &str,
+ is_slip39: bool,
+) -> Result<XPrv, CardanoError> {
+ if is_slip39 {
+ app_cardano::slip23::from_seed_slip23(entropy).map(|v| v.xprv)
+ } else {
+ Ok(calc_icarus_master_key(entropy, passphrase.as_bytes()))
+ }
+}
+
fn parse_cardano_root_path(path: String) -> Option<String> {
let root_path = "1852'/1815'/";
match path.strip_prefix(root_path) {
@@ -473,11 +485,15 @@ pub extern "C" fn cardano_sign_catalyst(
entropy: PtrBytes,
entropy_len: u32,
passphrase: PtrString,
+ is_slip39: bool,
) -> PtrT<UREncodeResult> {
let entropy = unsafe { alloc::slice::from_raw_parts(entropy, entropy_len as usize) };
let passphrase = recover_c_char(passphrase);
- let icarus_master_key = calc_icarus_master_key(entropy, passphrase.as_bytes());
- cardano_sign_catalyst_by_icarus(ptr, icarus_master_key)
+ let master_key = match generate_master_key(entropy, &passphrase, is_slip39) {
+ Ok(v) => v,
+ Err(e) => return UREncodeResult::from(e).c_ptr(),
+ };
+ cardano_sign_catalyst_by_icarus(ptr, master_key)
}
fn cardano_sign_catalyst_by_icarus(ptr: PtrUR, icarus_master_key: XPrv) -> PtrT<UREncodeResult> {
@@ -564,11 +580,16 @@ pub extern "C" fn cardano_sign_sign_data(
entropy: PtrBytes,
entropy_len: u32,
passphrase: PtrString,
+ is_slip39: bool,
) -> PtrT<UREncodeResult> {
let entropy = unsafe { alloc::slice::from_raw_parts(entropy, entropy_len as usize) };
let passphrase = recover_c_char(passphrase);
- let icarus_master_key = calc_icarus_master_key(entropy, passphrase.as_bytes());
- cardano_sign_sign_data_by_icarus(ptr, icarus_master_key)
+ let master_key = match generate_master_key(entropy, &passphrase, is_slip39) {
+ Ok(v) => v,
+ Err(e) => return UREncodeResult::from(e).c_ptr(),
+ };
+
+ cardano_sign_sign_data_by_icarus(ptr, master_key)
}
fn cardano_sign_sign_data_by_icarus(ptr: PtrUR, icarus_master_key: XPrv) -> PtrT<UREncodeResult> {
@@ -617,11 +638,16 @@ pub extern "C" fn cardano_sign_sign_cip8_data(
entropy: PtrBytes,
entropy_len: u32,
passphrase: PtrString,
+ is_slip39: bool,
) -> PtrT<UREncodeResult> {
let entropy = unsafe { alloc::slice::from_raw_parts(entropy, entropy_len as usize) };
let passphrase = recover_c_char(passphrase);
- let icarus_master_key = calc_icarus_master_key(entropy, passphrase.as_bytes());
- cardano_sign_sign_cip8_data_by_icarus(ptr, icarus_master_key)
+ let master_key = match generate_master_key(entropy, &passphrase, is_slip39) {
+ Ok(v) => v,
+ Err(e) => return UREncodeResult::from(e).c_ptr(),
+ };
+
+ cardano_sign_sign_cip8_data_by_icarus(ptr, master_key)
}
#[no_mangle]
@@ -685,14 +711,19 @@ pub extern "C" fn cardano_sign_tx(
entropy_len: u32,
passphrase: PtrString,
enable_blind_sign: bool,
+ is_slip39: bool,
) -> PtrT<UREncodeResult> {
let entropy = unsafe { alloc::slice::from_raw_parts(entropy, entropy_len as usize) };
let passphrase = recover_c_char(passphrase);
- let icarus_master_key = calc_icarus_master_key(entropy, passphrase.as_bytes());
+ let master_key = match generate_master_key(entropy, &passphrase, is_slip39) {
+ Ok(v) => v,
+ Err(e) => return UREncodeResult::from(e).c_ptr(),
+ };
+
if enable_blind_sign {
- cardano_sign_tx_hash_by_icarus(ptr, icarus_master_key)
+ cardano_sign_tx_hash_by_icarus(ptr, master_key)
} else {
- cardano_sign_tx_by_icarus(ptr, master_fingerprint, cardano_xpub, icarus_master_key)
+ cardano_sign_tx_by_icarus(ptr, master_fingerprint, cardano_xpub, master_key)
}
}
@@ -718,11 +749,38 @@ pub extern "C" fn cardano_sign_tx_unlimited(
entropy: PtrBytes,
entropy_len: u32,
passphrase: PtrString,
+ is_slip39: bool,
) -> PtrT<UREncodeResult> {
let entropy = unsafe { alloc::slice::from_raw_parts(entropy, entropy_len as usize) };
let passphrase = recover_c_char(passphrase);
- let icarus_master_key = calc_icarus_master_key(entropy, passphrase.as_bytes());
- cardano_sign_tx_by_icarus_unlimited(ptr, master_fingerprint, cardano_xpub, icarus_master_key)
+ let master_key = match generate_master_key(entropy, &passphrase, is_slip39) {
+ Ok(v) => v,
+ Err(e) => return UREncodeResult::from(e).c_ptr(),
+ };
+ cardano_sign_tx_by_icarus_unlimited(ptr, master_fingerprint, cardano_xpub, master_key)
+}
+
+#[no_mangle]
+pub extern "C" fn cardano_get_pubkey_by_slip23(
+ entropy: PtrBytes,
+ entropy_len: u32,
+ path: PtrString,
+) -> *mut SimpleResponse<c_char> {
+ if entropy_len != 16 && entropy_len != 32 {
+ return SimpleResponse::from(RustCError::InvalidData(
+ "Invalid entropy length".to_string(),
+ ))
+ .simple_c_ptr();
+ }
+ let entropy = unsafe { core::slice::from_raw_parts(entropy, entropy_len as usize) };
+ let path = recover_c_char(path).to_lowercase();
+ let xpub = app_cardano::slip23::from_seed_slip23_path(entropy, path.as_str());
+ match xpub {
+ Ok(xpub) => {
+ SimpleResponse::success(convert_c_char(xpub.xprv.public().to_string())).simple_c_ptr()
+ }
+ Err(e) => SimpleResponse::from(e).simple_c_ptr(),
+ }
}
fn cardano_sign_tx_by_icarus(
diff --git a/rust/rust_c/src/common/errors.rs b/rust/rust_c/src/common/errors.rs
index 1c998c1..0c1699a 100644
--- a/rust/rust_c/src/common/errors.rs
+++ b/rust/rust_c/src/common/errors.rs
@@ -386,6 +386,7 @@ impl From<&CardanoError> for ErrorCodes {
CardanoError::DerivationError(_) => Self::KeystoreDerivationError,
CardanoError::UnsupportedTransaction(_) => Self::UnsupportedTransaction,
CardanoError::SigningFailed(_) => Self::SignFailure,
+ CardanoError::InvalidSeed(_) => Self::InvalidData,
}
}
}
diff --git a/src/crypto/account_public_info.c b/src/crypto/account_public_info.c
index 98a8e4e..80ad780 100644
--- a/src/crypto/account_public_info.c
+++ b/src/crypto/account_public_info.c
@@ -303,7 +303,8 @@ static AccountPublicKeyItem_t g_accountPublicInfo[XPUB_TYPE_NUM] = {0};
static uint8_t g_tempPublicKeyAccountIndex = INVALID_ACCOUNT_INDEX;
static bool g_isTempAccount = false;
-static const char g_xpubInfoVersion[] = "1.0.0";
+// 1.0.1 support slip39 for ada
+static const char g_xpubInfoVersion[] = "1.0.1";
static const char g_multiSigInfoVersion[] = "1.0.0";
static const ChainItem_t g_chainTable[] = {
@@ -917,7 +918,7 @@ int32_t AccountPublicSavePublicInfo(uint8_t accountIndex, const char *password,
// slip39 wallet does not support:
// ADA
// Zcash
- if (isSlip39 && (g_chainTable[i].cryptoKey == BIP32_ED25519 || g_chainTable[i].cryptoKey == LEDGER_BITBOX02 || g_chainTable[i].cryptoKey == ZCASH_UFVK_ENCRYPTED)) {
+ if (isSlip39 && (g_chainTable[i].cryptoKey == LEDGER_BITBOX02 || g_chainTable[i].cryptoKey == ZCASH_UFVK_ENCRYPTED)) {
continue;
}
// do not generate public keys for ton-only wallet;
@@ -942,7 +943,11 @@ int32_t AccountPublicSavePublicInfo(uint8_t accountIndex, const char *password,
xPubResult = ProcessKeyType(seed, len, g_chainTable[i].cryptoKey, g_chainTable[i].path, icarusMasterKey, ledgerBitbox02Key);
}
#else
- xPubResult = ProcessKeyType(seed, len, g_chainTable[i].cryptoKey, g_chainTable[i].path, icarusMasterKey, ledgerBitbox02Key);
+ if (g_chainTable[i].cryptoKey == BIP32_ED25519 && isSlip39) {
+ xPubResult = cardano_get_pubkey_by_slip23(seed, len, g_chainTable[i].path);
+ } else {
+ xPubResult = ProcessKeyType(seed, len, g_chainTable[i].cryptoKey, g_chainTable[i].path, icarusMasterKey, ledgerBitbox02Key);
+ }
#endif
if (g_chainTable[i].cryptoKey == RSA_KEY && xPubResult == NULL) {
continue;
@@ -1083,7 +1088,8 @@ int32_t TempAccountPublicInfo(uint8_t accountIndex, const char *password, bool s
for (i = 0; i < NUMBER_OF_ARRAYS(g_chainTable); i++) {
// SLIP32 wallet does not support ADA
- if (isSlip39 && (g_chainTable[i].cryptoKey == BIP32_ED25519 || g_chainTable[i].cryptoKey == LEDGER_BITBOX02 || g_chainTable[i].cryptoKey == ZCASH_UFVK_ENCRYPTED)) {
+ // slip23 for ada
+ if (isSlip39 && (g_chainTable[i].cryptoKey == LEDGER_BITBOX02 || g_chainTable[i].cryptoKey == ZCASH_UFVK_ENCRYPTED)) {
continue;
}
if (g_chainTable[i].cryptoKey == TON_CHECKSUM || g_chainTable[i].cryptoKey == TON_NATIVE) {
@@ -1107,7 +1113,12 @@ int32_t TempAccountPublicInfo(uint8_t accountIndex, const char *password, bool s
xPubResult = ProcessKeyType(seed, len, g_chainTable[i].cryptoKey, g_chainTable[i].path, icarusMasterKey, ledgerBitbox02Key);
}
#else
- xPubResult = ProcessKeyType(seed, len, g_chainTable[i].cryptoKey, g_chainTable[i].path, icarusMasterKey, ledgerBitbox02Key);
+ if (g_chainTable[i].cryptoKey == BIP32_ED25519 && isSlip39) {
+ // ada slip23
+ xPubResult = cardano_get_pubkey_by_slip23(seed, len, g_chainTable[i].path);
+ } else {
+ xPubResult = ProcessKeyType(seed, len, g_chainTable[i].cryptoKey, g_chainTable[i].path, icarusMasterKey, ledgerBitbox02Key);
+ }
#endif
if (g_chainTable[i].cryptoKey == RSA_KEY && xPubResult == NULL) {
continue;
@@ -1675,8 +1686,8 @@ void SetAccountReceiveIndex(const char* chainName, uint32_t index)
cJSON_AddItemToObject(item, "recvIndex", cJSON_CreateNumber(index));
}
- WriteJsonToFlash(addr, rootJson);
if (!PassphraseExist(GetCurrentAccountIndex())) {
+ WriteJsonToFlash(addr, rootJson);
cJSON_Delete(rootJson);
}
}
@@ -1689,6 +1700,19 @@ uint32_t GetAccountReceivePath(const char* chainName)
cJSON *item = cJSON_GetObjectItem(rootJson, chainName);
if (item == NULL) {
printf("GetAccountReceivePath index cannot get %s\r\n", chainName);
+ printf("receive index cannot get %s\r\n", chainName);
+ cJSON *jsonItem = cJSON_CreateObject();
+ cJSON_AddItemToObject(jsonItem, "recvIndex", cJSON_CreateNumber(0)); // recvIndex is the address index
+ cJSON_AddItemToObject(jsonItem, "recvPath", cJSON_CreateNumber(0)); // recvPath is the derivation path type
+ cJSON_AddItemToObject(jsonItem, "firstRecv", cJSON_CreateBool(true)); // firstRecv is the first receive address
+ if (!strcmp(chainName, "TON")) {
+ cJSON_AddItemToObject(jsonItem, "manage", cJSON_CreateBool(true));
+ } else if ((!strcmp(chainName, "BTC") || !strcmp(chainName, "ETH"))) {
+ cJSON_AddItemToObject(jsonItem, "manage", cJSON_CreateBool(true));
+ } else {
+ cJSON_AddItemToObject(jsonItem, "manage", cJSON_CreateBool(false));
+ }
+ cJSON_AddItemToObject(rootJson, chainName, jsonItem);
} else {
cJSON *recvPath = cJSON_GetObjectItem(item, "recvPath");
index = recvPath ? recvPath->valueint : 0;
@@ -1707,7 +1731,16 @@ void SetAccountReceivePath(const char* chainName, uint32_t index)
cJSON *item = cJSON_GetObjectItem(rootJson, chainName);
if (item == NULL) {
printf("SetAccountReceivePath cannot get %s\r\n", chainName);
- cJSON_Delete(rootJson);
+ if (!PassphraseExist(GetCurrentAccountIndex())) {
+ cJSON_Delete(rootJson);
+ } else {
+ cJSON *jsonItem = cJSON_CreateObject();
+ cJSON_AddItemToObject(jsonItem, "recvIndex", cJSON_CreateNumber(0)); // recvIndex is the address index
+ cJSON_AddItemToObject(jsonItem, "recvPath", cJSON_CreateNumber(index)); // recvPath is the derivation path type
+ cJSON_AddItemToObject(jsonItem, "firstRecv", cJSON_CreateBool(false)); // firstRecv is the first receive address
+ cJSON_AddItemToObject(jsonItem, "manage", cJSON_CreateBool(false));
+ cJSON_AddItemToObject(rootJson, chainName, jsonItem);
+ }
return;
}
cJSON *recvPath = cJSON_GetObjectItem(item, "recvPath");
@@ -1969,7 +2002,6 @@ static void WriteJsonToFlash(uint32_t addr, cJSON *rootJson)
Gd25FlashSectorErase(eraseAddr);
}
jsonString = cJSON_PrintBuffered(rootJson, SPI_FLASH_SIZE_USER1_MUTABLE_DATA - 4, false);
- printf("save jsonString=%s\r\n", jsonString);
RemoveFormatChar(jsonString);
size = strlen(jsonString);
Gd25FlashWriteBuffer(addr, (uint8_t *)&size, 4);
diff --git a/src/tasks/ui_display_task.c b/src/tasks/ui_display_task.c
index 587824d..54f3770 100644
--- a/src/tasks/ui_display_task.c
+++ b/src/tasks/ui_display_task.c
@@ -56,7 +56,7 @@ void CreateUiDisplayTask(void)
{
const osThreadAttr_t testtTask_attributes = {
.name = "UiDisplayTask",
- .stack_size = 1024 * 24,
+ .stack_size = 1024 * 26,
.priority = (osPriority_t) osPriorityHigh,
};
g_uiDisplayTaskHandle = osThreadNew(UiDisplayTask, NULL, &testtTask_attributes);
diff --git a/src/ui/gui_chain/multi/web3/gui_ada.c b/src/ui/gui_chain/multi/web3/gui_ada.c
index 0cee6e5..3009ff6 100644
--- a/src/ui/gui_chain/multi/web3/gui_ada.c
+++ b/src/ui/gui_chain/multi/web3/gui_ada.c
@@ -80,6 +80,16 @@ void GuiSetupAdaUrData(URParseResult *urResult, URParseMultiResult *urMultiResul
result = NULL; \
}
+static int32_t GetAccountAdaEntropy(uint8_t accountIndex, uint8_t *entropy, uint8_t *entropyLen, const char *password, bool isSlip39)
+{
+ if (isSlip39) {
+ *entropyLen = GetCurrentAccountEntropyLen();
+ return GetAccountSeed(accountIndex, entropy, password);
+ } else {
+ return GetAccountEntropy(accountIndex, entropy, entropyLen, password);
+ }
+}
+
void *GuiGetAdaData(void)
{
CHECK_FREE_PARSE_RESULT(g_parseResult);
@@ -292,6 +302,9 @@ PtrT_TransactionCheckResult GuiGetAdaCatalystCheckResult(void)
static void Try2FixAdaPathType()
{
+ if (GetMnemonicType() == MNEMONIC_TYPE_SLIP39) {
+ return;
+ }
if (GetAdaXPubType() == LEDGER_ADA) {
SetReceivePageAdaXPubType(STANDARD_ADA);
} else {
@@ -650,13 +663,14 @@ UREncodeResult *GuiGetAdaSignCatalystVotingRegistrationQrCodeData(void)
do {
uint8_t entropy[64];
uint8_t len = 0;
- GetAccountEntropy(GetCurrentAccountIndex(), entropy, &len, SecretCacheGetPassword());
+ bool isSlip39 = GetMnemonicType() == MNEMONIC_TYPE_SLIP39;
+ GetAccountAdaEntropy(GetCurrentAccountIndex(), entropy, &len, SecretCacheGetPassword(), isSlip39);
if (GetAdaXPubType() == LEDGER_ADA) {
char *mnemonic = NULL;
bip39_mnemonic_from_bytes(NULL, entropy, len, &mnemonic);
encodeResult = cardano_sign_catalyst_with_ledger_bitbox02(data, mnemonic, GetPassphrase(GetCurrentAccountIndex()));
} else {
- encodeResult = cardano_sign_catalyst(data, entropy, len, GetPassphrase(GetCurrentAccountIndex()));
+ encodeResult = cardano_sign_catalyst(data, entropy, len, GetPassphrase(GetCurrentAccountIndex()), isSlip39);
}
ClearSecretCache();
CHECK_CHAIN_BREAK(encodeResult);
@@ -677,13 +691,14 @@ UREncodeResult *GuiGetAdaSignSignDataQrCodeData(void)
do {
uint8_t entropy[64];
uint8_t len = 0;
- GetAccountEntropy(GetCurrentAccountIndex(), entropy, &len, SecretCacheGetPassword());
+ bool isSlip39 = GetMnemonicType() == MNEMONIC_TYPE_SLIP39;
+ GetAccountAdaEntropy(GetCurrentAccountIndex(), entropy, &len, SecretCacheGetPassword(), isSlip39);
if (GetAdaXPubType() == LEDGER_ADA) {
char *mnemonic = NULL;
bip39_mnemonic_from_bytes(NULL, entropy, len, &mnemonic);
encodeResult = cardano_sign_sign_data_with_ledger_bitbox02(data, mnemonic, GetPassphrase(GetCurrentAccountIndex()));
} else {
- encodeResult = cardano_sign_sign_data(data, entropy, len, GetPassphrase(GetCurrentAccountIndex()));
+ encodeResult = cardano_sign_sign_data(data, entropy, len, GetPassphrase(GetCurrentAccountIndex()), isSlip39);
}
ClearSecretCache();
CHECK_CHAIN_BREAK(encodeResult);
@@ -704,13 +719,14 @@ UREncodeResult *GuiGetAdaSignSignCip8DataQrCodeData(void)
do {
uint8_t entropy[64];
uint8_t len = 0;
- GetAccountEntropy(GetCurrentAccountIndex(), entropy, &len, SecretCacheGetPassword());
+ bool isSlip39 = GetMnemonicType() == MNEMONIC_TYPE_SLIP39;
+ GetAccountAdaEntropy(GetCurrentAccountIndex(), entropy, &len, SecretCacheGetPassword(), isSlip39);
if (GetAdaXPubType() == LEDGER_ADA) {
char *mnemonic = NULL;
bip39_mnemonic_from_bytes(NULL, entropy, len, &mnemonic);
encodeResult = cardano_sign_sign_cip8_data_with_ledger_bitbox02(data, mnemonic, GetPassphrase(GetCurrentAccountIndex()));
} else {
- encodeResult = cardano_sign_sign_cip8_data(data, entropy, len, GetPassphrase(GetCurrentAccountIndex()));
+ encodeResult = cardano_sign_sign_cip8_data(data, entropy, len, GetPassphrase(GetCurrentAccountIndex()), isSlip39);
}
ClearSecretCache();
CHECK_CHAIN_BREAK(encodeResult);
@@ -731,13 +747,14 @@ UREncodeResult *GuiGetAdaSignQrCodeData(void)
do {
uint8_t entropy[64];
uint8_t len = 0;
- GetAccountEntropy(GetCurrentAccountIndex(), entropy, &len, SecretCacheGetPassword());
+ bool isSlip39 = GetMnemonicType() == MNEMONIC_TYPE_SLIP39;
+ GetAccountAdaEntropy(GetCurrentAccountIndex(), entropy, &len, SecretCacheGetPassword(), isSlip39);
if (GetAdaXPubType() == LEDGER_ADA) {
char *mnemonic = NULL;
bip39_mnemonic_from_bytes(NULL, entropy, len, &mnemonic);
encodeResult = cardano_sign_tx_with_ledger_bitbox02(data, mfp, xpub, mnemonic, GetPassphrase(GetCurrentAccountIndex()), false);
} else {
- encodeResult = cardano_sign_tx(data, mfp, xpub, entropy, len, GetPassphrase(GetCurrentAccountIndex()), false);
+ encodeResult = cardano_sign_tx(data, mfp, xpub, entropy, len, GetPassphrase(GetCurrentAccountIndex()), false, isSlip39);
}
ClearSecretCache();
CHECK_CHAIN_BREAK(encodeResult);
@@ -764,13 +781,14 @@ UREncodeResult *GuiGetAdaSignTxHashQrCodeData(void)
do {
uint8_t entropy[64];
uint8_t len = 0;
- GetAccountEntropy(GetCurrentAccountIndex(), entropy, &len, SecretCacheGetPassword());
+ bool isSlip39 = GetMnemonicType() == MNEMONIC_TYPE_SLIP39;
+ GetAccountAdaEntropy(GetCurrentAccountIndex(), entropy, &len, SecretCacheGetPassword(), isSlip39);
if (GetAdaXPubType() == LEDGER_ADA) {
char *mnemonic = NULL;
bip39_mnemonic_from_bytes(NULL, entropy, len, &mnemonic);
encodeResult = cardano_sign_tx_with_ledger_bitbox02(data, mfp, xpub, mnemonic, GetPassphrase(GetCurrentAccountIndex()), true);
} else {
- encodeResult = cardano_sign_tx(data, mfp, xpub, entropy, len, GetPassphrase(GetCurrentAccountIndex()), true);
+ encodeResult = cardano_sign_tx(data, mfp, xpub, entropy, len, GetPassphrase(GetCurrentAccountIndex()), true, isSlip39);
}
ClearSecretCache();
CHECK_CHAIN_BREAK(encodeResult);
@@ -959,13 +977,14 @@ UREncodeResult *GuiGetAdaSignUrDataUnlimited(void)
do {
uint8_t entropy[64];
uint8_t len = 0;
- GetAccountEntropy(GetCurrentAccountIndex(), entropy, &len, SecretCacheGetPassword());
+ bool isSlip39 = GetMnemonicType() == MNEMONIC_TYPE_SLIP39;
+ GetAccountAdaEntropy(GetCurrentAccountIndex(), entropy, &len, SecretCacheGetPassword(), isSlip39);
if (GetAdaXPubType() == LEDGER_ADA) {
char *mnemonic = NULL;
bip39_mnemonic_from_bytes(NULL, entropy, len, &mnemonic);
encodeResult = cardano_sign_tx_with_ledger_bitbox02_unlimited(data, mfp, xpub, mnemonic, GetPassphrase(GetCurrentAccountIndex()));
} else {
- encodeResult = cardano_sign_tx_unlimited(data, mfp, xpub, entropy, len, GetPassphrase(GetCurrentAccountIndex()));
+ encodeResult = cardano_sign_tx_unlimited(data, mfp, xpub, entropy, len, GetPassphrase(GetCurrentAccountIndex()), isSlip39);
}
ClearSecretCache();
CHECK_CHAIN_BREAK(encodeResult);
diff --git a/src/ui/gui_model/gui_model.c b/src/ui/gui_model/gui_model.c
index c3e10f3..1775e1e 100644
--- a/src/ui/gui_model/gui_model.c
+++ b/src/ui/gui_model/gui_model.c
@@ -1689,7 +1689,7 @@ static int32_t ModelTonForgetPass(const void *inData, uint32_t inDataLen)
ret = ERR_KEYSTORE_MNEMONIC_NOT_MATCH_WALLET;
break;
}
-
+
SetLockScreen(enable);
return ret;
} while (0);
diff --git a/src/ui/gui_widgets/gui_import_share_widgets.c b/src/ui/gui_widgets/gui_import_share_widgets.c
index 63443ec..7292262 100644
--- a/src/ui/gui_widgets/gui_import_share_widgets.c
+++ b/src/ui/gui_widgets/gui_import_share_widgets.c
@@ -66,9 +66,6 @@ void GuiImportShareWriteSe(bool en, int32_t errCode)
if (en == true) {
ClearMnemonicKeyboard(g_importMkb, &g_importMkb->currentId);
} else {
- // if (errCode == ERR_KEYSTORE_MNEMONIC_REPEAT) {
- // } else {
- // }
lv_btnmatrix_set_selected_btn(g_importMkb->btnm, g_importMkb->currentId - 1);
g_importMkb->currentId--;
}
diff --git a/src/ui/gui_widgets/gui_scan_widgets.c b/src/ui/gui_widgets/gui_scan_widgets.c
index 46ea0f4..6c9b9ad 100644
--- a/src/ui/gui_widgets/gui_scan_widgets.c
+++ b/src/ui/gui_widgets/gui_scan_widgets.c
@@ -49,10 +49,6 @@ static bool IsViewTypeSupported(ViewType viewType, ViewType *viewTypeFilter, siz
}
#endif
-#ifdef WEB3_VERSION
-#define IsSlip39WalletNotSupported(viewType) (viewType == CHAIN_ADA)
-#endif
-
#ifdef CYPHERPUNK_VERSION
#define IsSlip39WalletNotSupported(viewType) (viewType == CHAIN_XMR)
#endif
@@ -116,7 +112,7 @@ void GuiScanResult(bool result, void *param)
}
#endif
g_chainType = ViewTypeToChainTypeSwitch(g_qrcodeViewType);
-#ifndef BTC_ONLY
+#ifdef CYPHERPUNK_VERSION
// Not a chain based transaction, e.g. WebAuth
if (GetMnemonicType() == MNEMONIC_TYPE_SLIP39) {
//we don't support ADA & XMR in Slip39 Wallet;
diff --git a/src/ui/gui_widgets/multi/gui_key_derivation_request_widgets.c b/src/ui/gui_widgets/multi/gui_key_derivation_request_widgets.c
index c72b4f9..ddd3e19 100644
--- a/src/ui/gui_widgets/multi/gui_key_derivation_request_widgets.c
+++ b/src/ui/gui_widgets/multi/gui_key_derivation_request_widgets.c
@@ -504,15 +504,6 @@ static HardwareCallResult_t CheckHardwareCallRequestIsLegal(void)
}
}
}
- if (g_hasAda) {
- MnemonicType mnemonicType = GetMnemonicType();
- if (mnemonicType == MNEMONIC_TYPE_SLIP39) {
- SetHardwareCallParamsCheckResult((HardwareCallResult_t) {
- false, _("invaild_derive_type"), _("invalid_slip39_ada_con")
- });
- return g_hardwareCallParamsCheckResult;
- }
- }
SetHardwareCallParamsCheckResult((HardwareCallResult_t) {
true, "Check Pass", "hardware call params check pass"
@@ -549,12 +540,16 @@ static UREncodeResult *ModelGenerateSyncUR(void)
break;
case BIP32_ED25519:
if (selected_ada_derivation_algo == HD_STANDARD_ADA && !g_isUsb) {
- uint8_t entropyLen = 0;
- uint8_t entropy[64];
- GetAccountEntropy(GetCurrentAccountIndex(), entropy, &entropyLen, password);
- SimpleResponse_c_char* cip3_response = get_icarus_master_key(entropy, entropyLen, GetPassphrase(GetCurrentAccountIndex()));
- char* icarusMasterKey = cip3_response->data;
- pubkey[i] = derive_bip32_ed25519_extended_pubkey(icarusMasterKey, path);
+ if (isSlip39) {
+ pubkey[i] = cardano_get_pubkey_by_slip23(seed, seedLen, path);
+ } else {
+ uint8_t entropyLen = 0;
+ uint8_t entropy[64];
+ GetAccountEntropy(GetCurrentAccountIndex(), entropy, &entropyLen, password);
+ SimpleResponse_c_char* cip3_response = get_icarus_master_key(entropy, entropyLen, GetPassphrase(GetCurrentAccountIndex()));
+ char* icarusMasterKey = cip3_response->data;
+ pubkey[i] = derive_bip32_ed25519_extended_pubkey(icarusMasterKey, path);
+ }
} else if (selected_ada_derivation_algo == HD_LEDGER_BITBOX_ADA || g_isUsb) {
// seed -> mnemonic --> master key(m) -> derive key
uint8_t entropyLen = 0;
@@ -1068,7 +1063,7 @@ static void OpenMoreHandler(lv_event_t *e)
{
int height = 84;
int hintboxHeight = 144;
- bool hasChangePath = g_hasAda && g_hardwareCallParamsCheckResult.isLegal;
+ bool hasChangePath = g_hasAda && g_hardwareCallParamsCheckResult.isLegal && (GetMnemonicType() == MNEMONIC_TYPE_BIP39);
if (hasChangePath) {
hintboxHeight += height;
diff --git a/src/ui/gui_widgets/multi/gui_multi_accounts_receive_widgets.c b/src/ui/gui_widgets/multi/gui_multi_accounts_receive_widgets.c
index d30301a..2fa28b9 100644
--- a/src/ui/gui_widgets/multi/gui_multi_accounts_receive_widgets.c
+++ b/src/ui/gui_widgets/multi/gui_multi_accounts_receive_widgets.c
@@ -240,7 +240,6 @@ void GuiMultiAccountsReceiveRefresh(void)
SetMidBtnLabel(g_pageWidget->navBarWidget, NVS_BAR_MID_LABEL, _("derivation_path_change"));
SetNavBarRightBtn(g_pageWidget->navBarWidget, NVS_RIGHT_BUTTON_BUTT, MoreHandler, NULL);
GuiCreateSwitchPathTypeWidget(g_multiAccountsReceiveWidgets.tileSwitchPathType, g_chainCard, PathTypeChangedCb);
- printf("%s %d\n", __func__, __LINE__);
break;
default:
break;
@@ -303,7 +302,7 @@ static void GuiCreateMoreWidgets(lv_obj_t *parent)
lv_obj_align(label, LV_ALIGN_LEFT_MID, 60, 4);
#ifdef WEB3_VERSION
- if (g_chainCard == HOME_WALLET_CARD_ADA) {
+ if (g_chainCard == HOME_WALLET_CARD_ADA && GetMnemonicType() != MNEMONIC_TYPE_SLIP39) {
btn = lv_btn_create(cont);
lv_obj_set_size(btn, 456, 84);
lv_obj_align(btn, LV_ALIGN_TOP_MID, 0, 24 + 476);
@@ -1015,7 +1014,7 @@ static bool IsPathTypeSwitchable()
switch (g_chainCard) {
#ifdef WEB3_VERSION
case HOME_WALLET_CARD_ADA:
- return true;
+ return (GetMnemonicType() == MNEMONIC_TYPE_SLIP39) ? false : true;
#endif
default:
return false;
diff --git a/src/ui/gui_widgets/multi/web3/gui_connect_wallet_widgets.c b/src/ui/gui_widgets/multi/web3/gui_connect_wallet_widgets.c
index 7272684..913e5f1 100644
--- a/src/ui/gui_widgets/multi/web3/gui_connect_wallet_widgets.c
+++ b/src/ui/gui_widgets/multi/web3/gui_connect_wallet_widgets.c
@@ -244,9 +244,7 @@ const static ChangeDerivationItem_t g_adaChangeDerivationList[] = {
{"Ledger/BitBox02", ""},
};
-#define WALLET_FILTER_SLIP39 {"All", "BTC", "ETH", "SOL", "", "· · ·"}
-#define WALLET_FILTER_NORMAL {"All", "BTC", "ETH", "SOL", "ADA", "· · ·"}
-static char *g_walletFilter[6];
+static const char *g_walletFilter[6] = {"All", "BTC", "ETH", "SOL", "ADA", "· · ·"};
static uint8_t g_currentFilter = WALLET_FILTER_ALL;
static uint32_t g_currentSelectedPathIndex[3] = {0};
@@ -332,13 +330,6 @@ static void GuiInitWalletListArray()
enable = (index == WALLET_LIST_TONKEEPER);
} else {
switch (index) {
- case WALLET_LIST_ETERNL:
- case WALLET_LIST_MEDUSA:
- case WALLET_LIST_VESPR:
- case WALLET_LIST_TYPHON:
- case WALLET_LIST_BEGIN:
- enable = !isSLIP39;
- break;
case WALLET_LIST_WANDER:
case WALLET_LIST_BEACON:
enable = !isTempAccount;
@@ -386,6 +377,9 @@ static bool IsSOL(int walletIndex)
static bool IsAda(int walletIndex)
{
+ if (GetMnemonicType() == MNEMONIC_TYPE_SLIP39) {
+ return false;
+ }
switch (walletIndex) {
case WALLET_LIST_VESPR:
case WALLET_LIST_ETERNL:
@@ -670,7 +664,7 @@ static void GuiUpdateWalletListWidget(void)
lv_obj_add_event_cb(img, OpenQRCodeHandler, LV_EVENT_CLICKED,
&g_walletListArray[i]);
j++;
- offsetY = j * 107;
+ offsetY = j * 107;
}
}
@@ -740,9 +734,6 @@ static void GuiCreateSelectWalletWidget(lv_obj_t *parent)
lv_obj_set_style_border_side(btn, LV_BORDER_SIDE_BOTTOM, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_set_style_border_width(btn, i == 0 ? 2 : 0, LV_PART_MAIN | LV_STATE_DEFAULT);
lv_obj_add_event_cb(btn, GuiUpdateConnectWalletHandler, LV_EVENT_CLICKED, g_walletFilter[i]);
- if (i == 4 && isSlip39) {
- lv_obj_add_flag(btn, LV_OBJ_FLAG_HIDDEN);
- }
}
lv_obj_t *line = GuiCreateDividerLine(parent);
@@ -1193,13 +1184,6 @@ static void AddBackpackWalletCoins(void)
void GuiConnectWalletInit(void)
{
g_currentFilter = WALLET_FILTER_ALL;
- static const char *slip39Filters[] = WALLET_FILTER_SLIP39;
- static const char *normalFilters[] = WALLET_FILTER_NORMAL;
- if (GetMnemonicType() == MNEMONIC_TYPE_SLIP39) {
- memcpy_s(g_walletFilter, sizeof(g_walletFilter), slip39Filters, sizeof(slip39Filters));
- } else {
- memcpy_s(g_walletFilter, sizeof(g_walletFilter), normalFilters, sizeof(normalFilters));
- }
GuiInitWalletListArray();
g_pageWidget = CreatePageWidget();
lv_obj_t *cont = g_pageWidget->contentZone;
diff --git a/src/ui/gui_widgets/multi/web3/gui_general_home_widgets.c b/src/ui/gui_widgets/multi/web3/gui_general_home_widgets.c
index dc6de9a..8bc955e 100644
--- a/src/ui/gui_widgets/multi/web3/gui_general_home_widgets.c
+++ b/src/ui/gui_widgets/multi/web3/gui_general_home_widgets.c
@@ -93,7 +93,6 @@ static void GuiInitWalletState(void)
}
g_walletState[HOME_WALLET_CARD_BNB].enable = false;
g_walletState[HOME_WALLET_CARD_DOT].enable = false;
- g_walletState[HOME_WALLET_CARD_ADA].enable = false;
g_walletState[HOME_WALLET_CARD_TON].enable = true;
g_coinFilterNum = 2;
break;
@@ -103,7 +102,6 @@ static void GuiInitWalletState(void)
}
g_walletState[HOME_WALLET_CARD_BNB].enable = false;
g_walletState[HOME_WALLET_CARD_DOT].enable = false;
- g_walletState[HOME_WALLET_CARD_ADA].enable = true;
g_walletState[HOME_WALLET_CARD_TON].enable = true;
g_coinFilterNum = 2;
break;
diff --git a/test/test_cmd.c b/test/test_cmd.c
index e2812e9..4ae10fc 100644
--- a/test/test_cmd.c
+++ b/test/test_cmd.c
@@ -2610,7 +2610,7 @@ static void testCardanoTx(int argc, char *argv[])
uint8_t entropy[64];
uint8_t entropyLen = sizeof(entropy);
GetAccountEntropy(index, entropy, &entropyLen, argv[1]);
- UREncodeResult *sign_result = cardano_sign_tx(result->data, mfp, xpub, entropy, sizeof(entropy), "",false);
+ UREncodeResult *sign_result = cardano_sign_tx(result->data, mfp, xpub, entropy, sizeof(entropy), "",false, false);
if (sign_result->error_code == 0) {
printf("sign result: %s \r\n", sign_result->data);
} else {
Why this scored 27/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.