1use data_encoding::BASE32_NOPAD;
2use rand::rngs::OsRng;
3use rand::Rng;
4use ring::signature::Ed25519KeyPair as KeyPairType;
5use ring::signature::KeyPair;
6
7use crate::auction::{Bid, SignedBid};
8use crate::crypto::{Address, MultisigAddress, MultisigSignature, MultisigSubsig, Signature};
9use crate::error::{ApiError, Result};
10use crate::models::Ed25519PublicKey;
11use crate::transaction::{SignedTransaction, Transaction};
12
13use sha2::Digest;
14use std::borrow::Borrow;
15
16type ChecksumAlg = sha2::Sha512Trunc256;
17
18pub struct Account {
19 seed: [u8; 32],
20 address: Address,
21 key_pair: KeyPairType,
22}
23
24impl Account {
25 pub fn generate() -> Account {
26 let seed: [u8; 32] = OsRng.gen();
27 Self::from_seed(seed)
28 }
29
30 pub fn from_mnemonic(mnemonic: &str) -> Result<Account> {
32 let seed = crate::mnemonic::to_key(mnemonic)?;
33 Ok(Self::from_seed(seed))
34 }
35
36 pub fn from_seed(seed: [u8; 32]) -> Account {
38 let key_pair = KeyPairType::from_seed_unchecked(&seed).unwrap();
39 let mut pk = [0; 32];
40 pk.copy_from_slice(key_pair.public_key().as_ref());
41 let address = Address::new(pk);
42 Account {
43 seed,
44 address,
45 key_pair,
46 }
47 }
48
49 pub fn address(&self) -> Address {
51 self.address
52 }
53
54 pub fn mnemonic(&self) -> String {
56 crate::mnemonic::from_key(&self.seed).unwrap()
57 }
58
59 pub fn seed(&self) -> [u8; 32] {
61 self.seed
62 }
63
64 fn sign(&self, bytes: &[u8]) -> Signature {
65 let signature = self.key_pair.sign(&bytes);
66 let mut stripped_signature = [0; 64];
68 stripped_signature.copy_from_slice(&signature.as_ref()[..64]);
69 Signature(stripped_signature)
70 }
71
72 pub fn sign_bid(&self, bid: Bid) -> Result<SignedBid> {
74 let encoded_bid = rmp_serde::to_vec_named(&bid)?;
75 let mut prefix_encoded_bid = b"aB".to_vec();
76 prefix_encoded_bid.extend_from_slice(&encoded_bid);
77 let signature = self.sign(&prefix_encoded_bid);
78 Ok(SignedBid {
79 bid,
80 sig: signature,
81 })
82 }
83
84 pub fn sign_transaction(&self, transaction: &Transaction) -> Result<SignedTransaction> {
86 let encoded_tx = rmp_serde::to_vec_named(transaction)?;
87 let mut prefix_encoded_tx = b"TX".to_vec();
88 prefix_encoded_tx.extend_from_slice(&encoded_tx);
89 let signature = self.sign(&prefix_encoded_tx);
90 let id = BASE32_NOPAD.encode(&ChecksumAlg::digest(&signature.0));
91 Ok(SignedTransaction {
92 transaction: transaction.clone(),
93 sig: Some(signature),
94 multisig: None,
95 transaction_id: id,
96 })
97 }
98
99 pub fn sign_multisig_transaction(
101 &self,
102 from: MultisigAddress,
103 transaction: &Transaction,
104 ) -> Result<SignedTransaction> {
105 if from.address() != transaction.sender {
106 return Err(ApiError::InvalidSenderInMultisig.into());
107 }
108 let my_public_key = Ed25519PublicKey(self.address.0);
109 if !from.public_keys.contains(&my_public_key) {
110 return Err(ApiError::InvalidSecretKeyInMultisig.into());
111 }
112 let signed_transaction = self.sign_transaction(transaction)?;
113 let subsigs: Vec<MultisigSubsig> = from
114 .public_keys
115 .iter()
116 .map(|key| {
117 if *key == my_public_key {
118 MultisigSubsig {
119 key: *key,
120 sig: signed_transaction.clone().sig,
121 }
122 } else {
123 MultisigSubsig {
124 key: *key,
125 sig: None,
126 }
127 }
128 })
129 .collect();
130 let multisig = MultisigSignature {
131 version: from.version,
132 threshold: from.threshold,
133 subsigs,
134 };
135 Ok(SignedTransaction {
136 multisig: Some(multisig),
137 sig: None,
138 transaction: transaction.clone(),
139 transaction_id: signed_transaction.transaction_id,
140 })
141 }
142
143 pub fn append_multisig_transaction(
145 &self,
146 from: MultisigAddress,
147 transaction: &SignedTransaction,
148 ) -> Result<SignedTransaction> {
149 let from_transaction = self.sign_multisig_transaction(from, &transaction.transaction)?;
150 Self::merge_multisig_transactions(&[&from_transaction, transaction])
151 }
152
153 pub fn merge_multisig_transactions<T: Borrow<SignedTransaction>>(
155 transactions: &[T],
156 ) -> Result<SignedTransaction> {
157 if transactions.len() < 2 {
158 return Err(ApiError::InsufficientTransactions.into());
159 }
160 let mut merged = transactions[0].borrow().clone();
161 for transaction in transactions {
162 let merged_msig = merged.multisig.as_mut().unwrap();
163 let msig = transaction.borrow().multisig.as_ref().unwrap();
164 if merged_msig.subsigs.len() != msig.subsigs.len() {
165 return Err(ApiError::InvalidNumberOfSubsignatures.into());
166 }
167 assert_eq!(merged_msig.subsigs.len(), msig.subsigs.len());
168 for (merged_subsig, subsig) in merged_msig.subsigs.iter_mut().zip(&msig.subsigs) {
169 if subsig.key != merged_subsig.key {
170 return Err(ApiError::InvalidPublicKeyInMultisig.into());
171 }
172 if merged_subsig.sig.is_none() {
173 merged_subsig.sig = subsig.sig
174 } else if merged_subsig.sig != subsig.sig && subsig.sig.is_some() {
175 return Err(ApiError::MismatchingSignatures.into());
176 }
177 }
178 }
179 Ok(merged)
180 }
181}