walletdb.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. use super::WalletApi;
  2. use crate::client::ClientFailed;
  3. use crate::crypto::{
  4. merkle::IncrementalWitness, merkle_node::MerkleNode, note::Note, OwnCoin, OwnCoins,
  5. };
  6. use crate::serial;
  7. use crate::{Error, Result};
  8. use async_std::sync::Arc;
  9. use ff::Field;
  10. use log::*;
  11. use rand::rngs::OsRng;
  12. use rusqlite::{named_params, params, Connection};
  13. use std::path::{Path, PathBuf};
  14. pub type WalletPtr = Arc<WalletDb>;
  15. #[derive(Debug, Clone)]
  16. pub struct Keypair {
  17. pub public: jubjub::SubgroupPoint,
  18. pub private: jubjub::Fr,
  19. }
  20. #[derive(Clone)]
  21. pub struct WalletDb {
  22. pub path: PathBuf,
  23. pub password: String,
  24. }
  25. impl WalletApi for WalletDb {
  26. fn get_password(&self) -> String {
  27. self.password.to_owned()
  28. }
  29. fn get_path(&self) -> PathBuf {
  30. self.path.to_owned()
  31. }
  32. }
  33. impl WalletDb {
  34. pub fn new(path: &Path, password: String) -> Result<WalletPtr> {
  35. debug!(target: "WALLETDB", "new() Constructor called");
  36. Ok(Arc::new(Self {
  37. path: path.to_owned(),
  38. password,
  39. }))
  40. }
  41. pub fn init_db(&self) -> Result<()> {
  42. if !self.password.trim().is_empty() {
  43. let contents = include_str!("../../sql/schema.sql");
  44. let conn = Connection::open(&self.path)?;
  45. debug!(target: "WALLETDB", "OPENED CONNECTION AT PATH {:?}", self.path);
  46. conn.pragma_update(None, "key", &self.password)?;
  47. conn.execute_batch(&contents)?;
  48. } else {
  49. debug!(target: "WALLETDB", "Password is empty. You must set a password to use the wallet.");
  50. return Err(Error::from(ClientFailed::EmptyPassword));
  51. }
  52. Ok(())
  53. }
  54. pub fn key_gen(&self) -> Result<(Vec<u8>, Vec<u8>)> {
  55. debug!(target: "WALLETDB", "Attempting to generate keys...");
  56. let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  57. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  58. let pubkey = serial::serialize(&public);
  59. let privkey = serial::serialize(&secret);
  60. self.put_keypair(pubkey.clone(), privkey.clone())?;
  61. Ok((pubkey, privkey))
  62. }
  63. pub fn put_keypair(&self, key_public: Vec<u8>, key_private: Vec<u8>) -> Result<()> {
  64. let conn = Connection::open(&self.path)?;
  65. conn.pragma_update(None, "key", &self.password)?;
  66. conn.execute(
  67. "INSERT INTO keys(key_public, key_private) VALUES (?1, ?2)",
  68. params![key_public, key_private],
  69. )?;
  70. Ok(())
  71. }
  72. pub fn get_keypairs(&self) -> Result<Vec<Keypair>> {
  73. debug!(target: "WALLETDB", "Returning keys...");
  74. let conn = Connection::open(&self.path)?;
  75. conn.pragma_update(None, "key", &self.password)?;
  76. let mut stmt = conn.prepare("SELECT * FROM keys")?;
  77. // this just gets the first key. maybe we should randomize this
  78. let key_iter = stmt.query_map([], |row| Ok((row.get(1)?, row.get(2)?)))?;
  79. let mut keypairs = Vec::new();
  80. for key in key_iter {
  81. let key = key?;
  82. let public = key.0;
  83. let private = key.1;
  84. let public: jubjub::SubgroupPoint =
  85. self.get_value_deserialized::<jubjub::SubgroupPoint>(public)?;
  86. let private: jubjub::Fr = self.get_value_deserialized::<jubjub::Fr>(private)?;
  87. keypairs.push(Keypair { public, private });
  88. }
  89. if keypairs.is_empty() {
  90. return Err(Error::from(ClientFailed::DoNotHaveKeypair));
  91. }
  92. Ok(keypairs)
  93. }
  94. pub fn get_own_coins(&self) -> Result<OwnCoins> {
  95. // open connection
  96. let conn = Connection::open(&self.path)?;
  97. // unlock database
  98. conn.pragma_update(None, "key", &self.password)?;
  99. let mut coins = conn.prepare("SELECT * FROM coins")?;
  100. let rows = coins.query_map([], |row| {
  101. let coin = self.get_value_deserialized(row.get(1)?).unwrap();
  102. // note
  103. let serial = self.get_value_deserialized(row.get(2)?).unwrap();
  104. let coin_blind = self.get_value_deserialized(row.get(3)?).unwrap();
  105. let valcom_blind = self.get_value_deserialized(row.get(4)?).unwrap();
  106. let value: u64 = row.get(5)?;
  107. let asset_id = self.get_value_deserialized(row.get(6)?).unwrap();
  108. let note = Note {
  109. serial,
  110. value,
  111. asset_id,
  112. coin_blind,
  113. valcom_blind,
  114. };
  115. let witness = self.get_value_deserialized(row.get(7)?).unwrap();
  116. let key_id: u64 = row.get(8)?;
  117. // return key_private from key_id
  118. let mut get_private_key =
  119. conn.prepare("SELECT key_private FROM keys WHERE key_id = :key_id")?;
  120. let rows = get_private_key.query_map(&[(":key_id", &key_id)], |row| row.get(0))?;
  121. let mut secret = Vec::new();
  122. for id in rows {
  123. secret.push(id?)
  124. }
  125. let secret: jubjub::Fr = self
  126. .get_value_deserialized(secret.pop().expect("Load public_key from walletdb"))
  127. .unwrap();
  128. Ok(OwnCoin {
  129. coin,
  130. note,
  131. secret,
  132. witness,
  133. })
  134. })?;
  135. let mut own_coins = Vec::new();
  136. for id in rows {
  137. own_coins.push(id?)
  138. }
  139. Ok(own_coins)
  140. }
  141. pub fn put_own_coins(&self, own_coin: OwnCoin) -> Result<()> {
  142. // prepare the values
  143. let coin = self.get_value_serialized(&own_coin.coin.repr)?;
  144. let serial = self.get_value_serialized(&own_coin.note.serial)?;
  145. let coin_blind = self.get_value_serialized(&own_coin.note.coin_blind)?;
  146. let valcom_blind = self.get_value_serialized(&own_coin.note.valcom_blind)?;
  147. let value: u64 = own_coin.note.value;
  148. let asset_id = self.get_value_serialized(&own_coin.note.asset_id)?;
  149. let witness = self.get_value_serialized(&own_coin.witness)?;
  150. let secret = self.get_value_serialized(&own_coin.secret)?;
  151. // open connection
  152. let conn = Connection::open(&self.path)?;
  153. // unlock database
  154. conn.pragma_update(None, "key", &self.password)?;
  155. // return key_id from key_private
  156. let mut get_id =
  157. conn.prepare("SELECT key_id FROM keys WHERE key_private = :key_private")?;
  158. let rows = get_id.query_map::<u64, _, _>(&[(":key_private", &secret)], |row| row.get(0))?;
  159. let mut key_id = Vec::new();
  160. for id in rows {
  161. key_id.push(id?)
  162. }
  163. conn.execute(
  164. "INSERT INTO coins(coin, serial, value, asset_id, coin_blind, valcom_blind, witness, key_id)
  165. VALUES (:coin, :serial, :value, :asset_id, :coin_blind, :valcom_blind, :witness, :key_id)",
  166. named_params! {
  167. ":coin": coin,
  168. ":serial": serial,
  169. ":value": value,
  170. ":asset_id": asset_id,
  171. ":coin_blind": coin_blind,
  172. ":valcom_blind": valcom_blind,
  173. ":witness": witness,
  174. ":key_id": key_id.pop().expect("Get key_id"),
  175. },
  176. )?;
  177. Ok(())
  178. }
  179. pub fn get_witnesses(&self) -> Result<Vec<(u64, IncrementalWitness<MerkleNode>)>> {
  180. let conn = Connection::open(&self.path)?;
  181. conn.pragma_update(None, "key", &self.password)?;
  182. let mut witnesses = conn.prepare("SELECT coin_id, witness FROM coins;")?;
  183. let rows = witnesses.query_map([], |row| {
  184. let coin_id: u64 = row.get(0)?;
  185. let witness: IncrementalWitness<MerkleNode> =
  186. self.get_value_deserialized(row.get(1)?).unwrap();
  187. Ok((coin_id, witness))
  188. })?;
  189. let mut witnesses = Vec::new();
  190. for i in rows {
  191. witnesses.push(i?)
  192. }
  193. Ok(witnesses)
  194. }
  195. pub fn update_witness(
  196. &self,
  197. coin_id: u64,
  198. witness: IncrementalWitness<MerkleNode>,
  199. ) -> Result<()> {
  200. let conn = Connection::open(&self.path)?;
  201. conn.pragma_update(None, "key", &self.password)?;
  202. let witness = self.get_value_serialized(&witness)?;
  203. conn.execute(
  204. "UPDATE coins SET witness = ?1 WHERE coin_id = ?2;",
  205. params![witness, coin_id],
  206. )?;
  207. Ok(())
  208. }
  209. pub fn put_cashier_pub(&self, key_public: Vec<u8>) -> Result<()> {
  210. debug!(target: "WALLETDB", "Save cashier keys...");
  211. let conn = Connection::open(&self.path)?;
  212. conn.pragma_update(None, "key", &self.password)?;
  213. conn.execute(
  214. "INSERT INTO cashier(key_public) VALUES (?1)",
  215. params![key_public],
  216. )?;
  217. Ok(())
  218. }
  219. pub fn get_cashier_public_keys(&self) -> Result<Vec<jubjub::SubgroupPoint>> {
  220. debug!(target: "WALLETDB", "Returning keys...");
  221. let conn = Connection::open(&self.path)?;
  222. conn.pragma_update(None, "key", &self.password)?;
  223. let mut stmt = conn.prepare("SELECT key_public FROM cashier")?;
  224. let key_iter = stmt.query_map([], |row| row.get(0))?;
  225. let mut pub_keys = Vec::new();
  226. for key in key_iter {
  227. let public: jubjub::SubgroupPoint = self.get_value_deserialized(key?)?;
  228. pub_keys.push(public);
  229. }
  230. if pub_keys.is_empty() {
  231. return Err(Error::from(ClientFailed::DoNotHaveCashierPublicKey));
  232. }
  233. Ok(pub_keys)
  234. }
  235. pub fn test_wallet(&self) -> Result<()> {
  236. let conn = Connection::open(&self.path)?;
  237. conn.pragma_update(None, "key", &self.password)?;
  238. let mut stmt = conn.prepare("SELECT * FROM keys")?;
  239. let _rows = stmt.query([])?;
  240. Ok(())
  241. }
  242. }
  243. #[cfg(test)]
  244. mod tests {
  245. use super::*;
  246. use crate::crypto::{coin::Coin, OwnCoin};
  247. use crate::util::join_config_path;
  248. use ff::PrimeField;
  249. #[test]
  250. pub fn test_save_and_load_keypair() -> Result<()> {
  251. let walletdb_path = join_config_path(&PathBuf::from("test_wallet.db"))?;
  252. let wallet = WalletDb::new(&walletdb_path, "darkfi".into())?;
  253. wallet.init_db()?;
  254. let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  255. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  256. let key_public = serial::serialize(&public);
  257. let key_private = serial::serialize(&secret);
  258. wallet.put_keypair(key_public, key_private)?;
  259. let keypair = wallet.get_keypairs()?[0].clone();
  260. assert_eq!(public, keypair.public);
  261. assert_eq!(secret, keypair.private);
  262. wallet.destroy()?;
  263. std::fs::remove_file(walletdb_path)?;
  264. Ok(())
  265. }
  266. #[test]
  267. pub fn test_put_and_get_own_coins() -> Result<()> {
  268. let walletdb_path = join_config_path(&PathBuf::from("test2_wallet.db"))?;
  269. let wallet = WalletDb::new(&walletdb_path, "darkfi".into())?;
  270. wallet.init_db()?;
  271. let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  272. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  273. let key_public = serial::serialize(&public);
  274. let key_private = serial::serialize(&secret);
  275. wallet.put_keypair(key_public, key_private)?;
  276. let note = Note {
  277. serial: jubjub::Fr::random(&mut OsRng),
  278. value: 110,
  279. asset_id: jubjub::Fr::random(&mut OsRng),
  280. coin_blind: jubjub::Fr::random(&mut OsRng),
  281. valcom_blind: jubjub::Fr::random(&mut OsRng),
  282. };
  283. let coin = Coin::new(bls12_381::Scalar::random(&mut OsRng).to_repr());
  284. let mut tree = crate::crypto::merkle::CommitmentTree::empty();
  285. tree.append(MerkleNode::from_coin(&coin))?;
  286. let witness = IncrementalWitness::from_tree(&tree);
  287. let own_coin = OwnCoin {
  288. coin,
  289. note: note.clone(),
  290. secret,
  291. witness: witness.clone(),
  292. };
  293. wallet.put_own_coins(own_coin.clone())?;
  294. let own_coin = wallet.get_own_coins()?[0].clone();
  295. assert_eq!(&own_coin.note.valcom_blind, &note.valcom_blind);
  296. assert_eq!(&own_coin.note.coin_blind, &note.coin_blind);
  297. assert_eq!(own_coin.secret, secret);
  298. assert_eq!(own_coin.witness.root(), witness.root());
  299. assert_eq!(own_coin.witness.path(), witness.path());
  300. wallet.destroy()?;
  301. std::fs::remove_file(walletdb_path)?;
  302. Ok(())
  303. }
  304. #[test]
  305. pub fn test_get_witnesses_and_update_them() -> Result<()> {
  306. let walletdb_path = join_config_path(&PathBuf::from("test3_wallet.db"))?;
  307. let wallet = WalletDb::new(&walletdb_path, "darkfi".into())?;
  308. wallet.init_db()?;
  309. let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
  310. let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
  311. let key_public = serial::serialize(&public);
  312. let key_private = serial::serialize(&secret);
  313. wallet.put_keypair(key_public, key_private)?;
  314. let mut tree = crate::crypto::merkle::CommitmentTree::empty();
  315. let note = Note {
  316. serial: jubjub::Fr::random(&mut OsRng),
  317. value: 110,
  318. asset_id: jubjub::Fr::random(&mut OsRng),
  319. coin_blind: jubjub::Fr::random(&mut OsRng),
  320. valcom_blind: jubjub::Fr::random(&mut OsRng),
  321. };
  322. let coin = Coin::new(bls12_381::Scalar::random(&mut OsRng).to_repr());
  323. let node = MerkleNode::from_coin(&coin);
  324. tree.append(node)?;
  325. tree.append(node)?;
  326. tree.append(node)?;
  327. tree.append(node)?;
  328. let witness = IncrementalWitness::from_tree(&tree);
  329. let own_coin = OwnCoin {
  330. coin,
  331. note,
  332. secret,
  333. witness,
  334. };
  335. wallet.put_own_coins(own_coin.clone())?;
  336. wallet.put_own_coins(own_coin.clone())?;
  337. wallet.put_own_coins(own_coin.clone())?;
  338. wallet.put_own_coins(own_coin.clone())?;
  339. let coin2 = Coin::new(bls12_381::Scalar::random(&mut OsRng).to_repr());
  340. let node2 = MerkleNode::from_coin(&coin2);
  341. tree.append(node2)?;
  342. for (coin_id, witness) in wallet.get_witnesses()?.iter_mut() {
  343. witness.append(node2).expect("Append to witness");
  344. wallet.update_witness(coin_id.clone(), witness.clone())?;
  345. }
  346. for (_, witness) in wallet.get_witnesses()?.iter() {
  347. assert_eq!(tree.root(), witness.root());
  348. }
  349. wallet.destroy()?;
  350. std::fs::remove_file(walletdb_path)?;
  351. Ok(())
  352. }
  353. }