• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tari-project / tari / 17642503453

11 Sep 2025 11:04AM UTC coverage: 60.947% (-0.01%) from 60.96%
17642503453

push

github

web-flow
chore: refactor multi sig and offline sign (#7487)

Description
---
refactor the multisig and offline sign to be in the transaction
components and not in the console wallet anymore

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- New Features
- Wallet adds full multisig UTXO lifecycle: create multisig UTXOs,
retrieve multisig details, and spend them.

- Changes
- Large transaction payloads now boxed; several response shapes changed
(client updates may be required).
- Offline signing and signing error paths unified for more consistent
workflows.
  - New CreateMultisigUtxo and adjusted GetMultisigUtxoData responses.

- Bug Fixes
  - Output queries now return unspent outputs correctly.

- Performance
  - Difficulty metrics emitted only when metrics feature is enabled.

- Chores
  - Dependency and module reorganization for maintainability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

41 of 497 new or added lines in 9 files covered. (8.25%)

38 existing lines in 9 files now uncovered.

74297 of 121904 relevant lines covered (60.95%)

294227.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

64.86
/base_layer/transaction_components/src/multisig/script.rs
1
// Copyright 2025 The Tari Project
2
//
3
// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
4
// following conditions are met:
5
//
6
// 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
7
// disclaimer.
8
//
9
// 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
10
// following disclaimer in the documentation and/or other materials provided with the distribution.
11
//
12
// 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
13
// products derived from this software without specific prior written permission.
14
//
15
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
16
// INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
18
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
20
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
21
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
use tari_common_types::types::{CompressedPublicKey, PrivateKey, UncompressedPublicKey};
23
use tari_crypto::keys::{PublicKey, SecretKey};
24
use tari_script::{Opcode, TariScript};
25

26
use crate::{
27
    key_manager::{TariKeyId, TransactionKeyManagerInterface},
28
    transaction_components::{one_sided::diffie_hellman_stealth_domain_hasher, TransactionError},
29
};
30

31
pub fn is_multisig_utxo(tari_script: &TariScript) -> bool {
×
32
    tari_script
×
33
        .as_slice()
×
34
        .iter()
×
35
        .any(|op| matches!(op, Opcode::CheckMultiSigVerify(..)))
×
36
}
×
37

NEW
38
pub fn get_multi_sig_script_components(script: &TariScript) -> Option<(Vec<CompressedPublicKey>, u8)> {
×
39
    for op in script.as_slice() {
×
40
        if let Opcode::CheckMultiSigVerify(m, _n, keys, _msg) = op {
×
NEW
41
            return Some((keys.clone(), *m));
×
42
        }
×
43
    }
44

NEW
45
    None
×
46
}
×
47

48
pub async fn derive_multisig_ephemeral_pubkey<KM: TransactionKeyManagerInterface>(
6✔
49
    key_manager: &KM,
6✔
50
    public_key: &CompressedPublicKey,
6✔
51
    sender_offset_key: &TariKeyId,
6✔
52
) -> Result<CompressedPublicKey, TransactionError> {
6✔
53
    let dh_shared_secret = key_manager
6✔
54
        .get_diffie_hellman_shared_secret(sender_offset_key, public_key)
6✔
55
        .await?;
6✔
56

57
    let stealth_hash = diffie_hellman_stealth_domain_hasher(dh_shared_secret);
6✔
58
    let private_key = PrivateKey::from_uniform_bytes(stealth_hash.as_ref())?;
6✔
59

60
    let shared_secret = UncompressedPublicKey::from_secret_key(&private_key);
6✔
61
    Ok(CompressedPublicKey::new_from_pk(
6✔
62
        public_key.to_public_key()? + shared_secret,
6✔
63
    ))
64
}
6✔
65

66
pub async fn derive_multisig_ephemeral_pubkeys<KM: TransactionKeyManagerInterface>(
2✔
67
    key_manager: &KM,
2✔
68
    public_keys: &[CompressedPublicKey],
2✔
69
    sender_offset_key: &TariKeyId,
2✔
70
) -> Result<Vec<CompressedPublicKey>, TransactionError> {
2✔
71
    let mut ephemeral_pubkeys = Vec::new();
2✔
72
    for pub_key in public_keys {
8✔
73
        ephemeral_pubkeys.push(derive_multisig_ephemeral_pubkey(key_manager, pub_key, sender_offset_key).await?);
6✔
74
    }
75
    Ok(ephemeral_pubkeys)
2✔
76
}
2✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc