1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
use chain_crypto::{Ed25519, Ed25519Extended, SecretKey, Signature};
use chain_impl_mockchain::{
    account,
    accounting::account::SpendingCounter,
    block::HeaderId,
    key::SpendingSignature,
    transaction::{TransactionSignDataHash, Witness, WitnessAccountData, WitnessUtxoData},
};
use ed25519_bip32::XPrv;
use hdkeygen::Key;

pub trait WitnessBuilder<SecretKey, WitnessData: AsRef<[u8]>, Signature> {
    fn build_sign_data(
        &self,
        block0: &HeaderId,
        sign_data_hash: &TransactionSignDataHash,
    ) -> WitnessData;

    fn sign(&self, witness_data: WitnessData, secret_key: SecretKey) -> Witness;

    fn build(&self, signature: Signature) -> Witness;
}

pub struct UtxoWitnessBuilder;

#[derive(Clone)]
pub enum AccountSecretKey {
    Ed25519(SecretKey<Ed25519>),
    Ed25519Extended(SecretKey<Ed25519Extended>),
}

pub struct AccountWitnessBuilder(pub SpendingCounter);

impl<D> WitnessBuilder<Key<XPrv, D>, WitnessUtxoData, SpendingSignature<WitnessUtxoData>>
    for UtxoWitnessBuilder
{
    fn build_sign_data(
        &self,
        block0: &HeaderId,
        sign_data_hash: &TransactionSignDataHash,
    ) -> WitnessUtxoData {
        Witness::new_utxo_data(block0, sign_data_hash)
    }

    fn sign(&self, witness_data: WitnessUtxoData, secret_key: Key<XPrv, D>) -> Witness {
        Witness::Utxo(
            Signature::from_binary(
                secret_key
                    .sign::<WitnessUtxoData, &[u8]>(witness_data.as_ref())
                    .as_ref(),
            )
            .unwrap(),
        )
    }

    fn build(&self, signature: SpendingSignature<WitnessUtxoData>) -> Witness {
        Witness::Utxo(signature)
    }
}

impl WitnessBuilder<SecretKey<Ed25519Extended>, WitnessUtxoData, SpendingSignature<WitnessUtxoData>>
    for UtxoWitnessBuilder
{
    fn build_sign_data(
        &self,
        block0: &HeaderId,
        sign_data_hash: &TransactionSignDataHash,
    ) -> WitnessUtxoData {
        Witness::new_utxo_data(block0, sign_data_hash)
    }

    fn sign(
        &self,
        witness_data: WitnessUtxoData,
        secret_key: SecretKey<Ed25519Extended>,
    ) -> Witness {
        Witness::Utxo(secret_key.sign(&witness_data))
    }

    fn build(&self, signature: SpendingSignature<WitnessUtxoData>) -> Witness {
        Witness::Utxo(signature)
    }
}

impl WitnessBuilder<AccountSecretKey, WitnessAccountData, account::Witness>
    for AccountWitnessBuilder
{
    fn build_sign_data(
        &self,
        block0: &HeaderId,
        sign_data_hash: &TransactionSignDataHash,
    ) -> WitnessAccountData {
        Witness::new_account_data(block0, sign_data_hash, self.0)
    }

    fn sign(&self, witness_data: WitnessAccountData, secret_key: AccountSecretKey) -> Witness {
        match secret_key {
            AccountSecretKey::Ed25519(secret_key) => {
                Witness::Account(self.0, secret_key.sign(&witness_data))
            }
            AccountSecretKey::Ed25519Extended(secret_key) => {
                Witness::Account(self.0, secret_key.sign(&witness_data))
            }
        }
    }

    fn build(&self, signature: account::Witness) -> Witness {
        Witness::Account(self.0, signature)
    }
}