leadcoin.rs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2022 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use darkfi_sdk::{
  19. crypto::{
  20. pedersen::{pedersen_commitment_base, pedersen_commitment_u64},
  21. poseidon_hash,
  22. util::mod_r_p,
  23. MerkleNode, SecretKey,
  24. },
  25. pasta::{arithmetic::CurveAffine, group::Curve, pallas},
  26. };
  27. use halo2_proofs::{arithmetic::Field, circuit::Value};
  28. use incrementalmerkletree::{bridgetree::BridgeTree, Tree};
  29. use log::debug;
  30. use rand::rngs::OsRng;
  31. use super::constants::EPOCH_LENGTH;
  32. use crate::{
  33. consensus::{constants, TransferStx, TxRcpt},
  34. zk::{
  35. proof::{Proof, ProvingKey},
  36. vm::ZkCircuit,
  37. vm_stack::Witness,
  38. },
  39. zkas::ZkBinary,
  40. Result,
  41. };
  42. pub const MERKLE_DEPTH_LEADCOIN: usize = 32;
  43. pub const MERKLE_DEPTH: u8 = 32;
  44. pub const ZERO: pallas::Base = pallas::Base::zero();
  45. pub const ONE: pallas::Base = pallas::Base::one();
  46. pub const PREFIX_EVL: u64 = 2;
  47. pub const PREFIX_SEED: u64 = 3;
  48. pub const PREFIX_CM: u64 = 4;
  49. pub const PREFIX_PK: u64 = 5;
  50. pub const PREFIX_SN: u64 = 6;
  51. // TODO: Unify item names with the names in the ZK proof (those are more descriptive)
  52. /// Structure representing the consensus leader coin
  53. #[derive(Debug, Clone, Copy)]
  54. pub struct LeadCoin {
  55. /// Coin's stake value
  56. pub value: u64,
  57. /// Commitment for coin1
  58. pub coin1_commitment: pallas::Point,
  59. /// Commitment for coin2 (rcpt coin)
  60. pub coin2_commitment: pallas::Point,
  61. /// Coin sk index
  62. pub idx: u32,
  63. /// Coin timestamp as slot index.
  64. pub tau: pallas::Base,
  65. /// Coin nonce
  66. pub nonce: pallas::Base,
  67. /// Merkle root of coin1 commitment
  68. pub coin1_commitment_root: MerkleNode,
  69. /// coin1 sk
  70. pub coin1_sk: pallas::Base,
  71. /// Merkle root of the `coin1` secret key
  72. pub coin1_sk_root: MerkleNode,
  73. /// coin1 sk position in merkle tree
  74. pub coin1_sk_pos: u32,
  75. /// Merkle path to the coin1's commitment
  76. pub coin1_commitment_merkle_path: [MerkleNode; MERKLE_DEPTH_LEADCOIN],
  77. /// Merkle path to the secret key of `coin1`
  78. pub coin1_sk_merkle_path: [MerkleNode; MERKLE_DEPTH_LEADCOIN],
  79. /// coin1 commitment blinding factor
  80. pub coin1_blind: pallas::Scalar,
  81. /// coin2 commitment blinding factor
  82. pub coin2_blind: pallas::Scalar,
  83. /// Leader election nonce derived from eta at onset of epoch
  84. pub y_mu: pallas::Base,
  85. /// Leader election nonce derived from eta at onset of epoch
  86. pub rho_mu: pallas::Base,
  87. /// Coin's secret key
  88. pub secret_key: SecretKey,
  89. /// eta
  90. pub eta: pallas::Base,
  91. /// slot
  92. pub slot: u64,
  93. }
  94. impl LeadCoin {
  95. /// Create a new `LeadCoin` object using given parameters.
  96. pub fn new(
  97. // emulation of global random oracle output from previous epoch randomness.
  98. eta: pallas::Base,
  99. // Stake value
  100. value: u64,
  101. // Slot absolute index
  102. slot_index: u64,
  103. // coin1 sk
  104. coin1_sk: pallas::Base,
  105. // Merkle root of the `coin_1` secret key in the Merkle tree of secret keys
  106. coin1_sk_root: MerkleNode,
  107. // sk pos
  108. coin1_sk_pos: usize,
  109. // Merkle path to the secret key of `coin_1` in the Merkle tree of secret keys
  110. coin1_sk_merkle_path: [MerkleNode; MERKLE_DEPTH_LEADCOIN],
  111. // what's seed supposed to be?
  112. seed: u64,
  113. // what is this SecretKey representing?
  114. secret_key: SecretKey,
  115. // Merkle tree of coin commitments
  116. coin_commitment_tree: &mut BridgeTree<MerkleNode, MERKLE_DEPTH>,
  117. ) -> Self {
  118. // Generate random blinding values for commitments:
  119. let coin1_blind = pallas::Scalar::random(&mut OsRng);
  120. let coin2_blind = pallas::Scalar::random(&mut OsRng);
  121. let tau = pallas::Base::from(slot_index);
  122. // pk
  123. let pk = Self::util_pk(coin1_sk_root, tau);
  124. // Derive the nonce for coin2
  125. let coin2_seed = Self::util_derived_rho(coin1_sk_root, pallas::Base::from(seed));
  126. debug!("coin2_seed[{}]: {:?}", slot_index, coin2_seed);
  127. let coin1_commitment =
  128. Self::commitment(pk, pallas::Base::from(value), pallas::Base::from(seed), coin1_blind);
  129. // Hash its coordinates to get a base field element
  130. let c1_cm_coords = coin1_commitment.to_affine().coordinates().unwrap();
  131. let c1_base_msg = [*c1_cm_coords.x(), *c1_cm_coords.y()];
  132. let coin1_commitment_base = poseidon_hash(c1_base_msg);
  133. // Append the element to the Merkle tree
  134. coin_commitment_tree.append(&MerkleNode::from(coin1_commitment_base));
  135. let leaf_pos = coin_commitment_tree.witness().unwrap();
  136. let coin1_commitment_root = coin_commitment_tree.root(0).unwrap();
  137. let coin1_commitment_merkle_path =
  138. coin_commitment_tree.authentication_path(leaf_pos, &coin1_commitment_root).unwrap();
  139. // Create commitment to coin2
  140. let coin2_commitment = Self::commitment(
  141. pk,
  142. pallas::Base::from(value + constants::REWARD),
  143. pallas::Base::from(coin2_seed),
  144. coin2_blind,
  145. );
  146. // Derive election seeds
  147. let (y_mu, rho_mu) = Self::election_seeds(eta, pallas::Base::from(slot_index));
  148. // Return the object
  149. Self {
  150. value,
  151. coin1_commitment,
  152. coin2_commitment,
  153. // TODO: Should be abs slot
  154. idx: u32::try_from(usize::from(leaf_pos)).unwrap(),
  155. // Assume tau is sl for simplicity
  156. tau,
  157. nonce: pallas::Base::from(seed),
  158. coin1_commitment_root,
  159. coin1_sk,
  160. coin1_sk_root,
  161. coin1_sk_pos: u32::try_from(usize::from(coin1_sk_pos)).unwrap(),
  162. coin1_commitment_merkle_path: coin1_commitment_merkle_path.try_into().unwrap(),
  163. coin1_sk_merkle_path,
  164. coin1_blind,
  165. coin2_blind,
  166. y_mu,
  167. rho_mu,
  168. secret_key,
  169. eta,
  170. slot: slot_index,
  171. }
  172. }
  173. pub fn sn(&self) -> pallas::Base {
  174. let sn_msg = [
  175. pallas::Base::from(PREFIX_SN),
  176. self.coin1_sk_root.inner(),
  177. self.nonce,
  178. pallas::Base::from(ZERO),
  179. ];
  180. poseidon_hash(sn_msg)
  181. }
  182. pub fn election_seeds_u64(eta: pallas::Base, slotu64: u64) -> (pallas::Base, pallas::Base) {
  183. Self::election_seeds(eta, pallas::Base::from(slotu64))
  184. }
  185. /// Derive election seeds from given parameters
  186. pub fn election_seeds(eta: pallas::Base, slot: pallas::Base) -> (pallas::Base, pallas::Base) {
  187. debug!("election_seeds: eta: {:?}, slot: {:?}", eta, slot);
  188. let election_seed_nonce = pallas::Base::from(3);
  189. let election_seed_lead = pallas::Base::from(22);
  190. // mu_y
  191. let lead_msg = [election_seed_lead, eta, slot];
  192. let lead_mu = poseidon_hash(lead_msg);
  193. // mu_rho
  194. let nonce_msg = [election_seed_nonce, eta, slot];
  195. let nonce_mu = poseidon_hash(nonce_msg);
  196. (lead_mu, nonce_mu)
  197. }
  198. /// Create a vector of `pallas::Base` elements from the `LeadCoin` to be
  199. /// used as public inputs for the ZK proof.
  200. pub fn public_inputs(&self, sigma1: pallas::Base, sigma2: pallas::Base) -> Vec<pallas::Base> {
  201. // pk
  202. let pk = self.pk();
  203. // coin 1-2 cm/commitment
  204. let c1_cm = self.coin1_commitment.to_affine().coordinates().unwrap();
  205. let c2_cm = self.coin2_commitment.to_affine().coordinates().unwrap();
  206. // lottery seed
  207. let seed_msg = [
  208. pallas::Base::from(PREFIX_SEED),
  209. self.coin1_sk_root.inner(),
  210. self.nonce,
  211. pallas::Base::from(ZERO),
  212. ];
  213. let seed = poseidon_hash(seed_msg);
  214. // y
  215. let y_msg = [seed, self.y_mu];
  216. let y = poseidon_hash(y_msg);
  217. // rho
  218. let rho_msg = [seed, self.rho_mu];
  219. let rho = poseidon_hash(rho_msg);
  220. let public_inputs = vec![
  221. pk,
  222. *c1_cm.x(),
  223. *c1_cm.y(),
  224. *c2_cm.x(),
  225. *c2_cm.y(),
  226. self.coin1_commitment_root.inner(),
  227. self.coin1_sk_root.inner(),
  228. self.sn(),
  229. self.y_mu,
  230. y,
  231. self.rho_mu,
  232. rho,
  233. sigma1,
  234. sigma2,
  235. ];
  236. public_inputs
  237. }
  238. fn util_pk(sk_root: MerkleNode, tau: pallas::Base) -> pallas::Base {
  239. let pk_msg =
  240. [pallas::Base::from(PREFIX_PK), sk_root.inner(), tau, pallas::Base::from(ZERO)];
  241. let pk = poseidon_hash(pk_msg);
  242. pk
  243. }
  244. /// calculate coin public key: hash of root coin secret key
  245. /// and timestmap.
  246. pub fn pk(&self) -> pallas::Base {
  247. Self::util_pk(self.coin1_sk_root, self.tau)
  248. }
  249. fn util_derived_rho(sk_root: MerkleNode, nonce: pallas::Base) -> pallas::Base {
  250. let rho_msg =
  251. [pallas::Base::from(PREFIX_EVL), sk_root.inner(), nonce, pallas::Base::from(ZERO)];
  252. let rho = poseidon_hash(rho_msg);
  253. rho
  254. }
  255. /// calculate derived coin nonce: hash of root coin secret key
  256. /// and old nonce
  257. pub fn derived_rho(&self) -> pallas::Base {
  258. Self::util_derived_rho(self.coin1_sk_root, self.nonce)
  259. }
  260. pub fn is_leader(&self, sigma1: pallas::Base, sigma2: pallas::Base) -> bool {
  261. let y_exp = [self.coin1_sk_root.inner(), self.nonce];
  262. let y_exp_hash = poseidon_hash(y_exp);
  263. let y_coords = pedersen_commitment_base(y_exp_hash, mod_r_p(self.y_mu))
  264. .to_affine()
  265. .coordinates()
  266. .unwrap();
  267. let y_coords = [*y_coords.x(), *y_coords.y()];
  268. let y = poseidon_hash(y_coords);
  269. let value = pallas::Base::from(self.value);
  270. let target = sigma1 * value + sigma2 * value * value;
  271. debug!("is_leader(): y = {:?}", y);
  272. debug!("is_leader(): T = {:?}", target);
  273. let first_winning = y < target;
  274. first_winning
  275. }
  276. fn commitment(
  277. pk: pallas::Base,
  278. value: pallas::Base,
  279. seed: pallas::Base,
  280. blind: pallas::Scalar,
  281. ) -> pallas::Point {
  282. let commit_msg = [pallas::Base::from(PREFIX_CM), pk, value, seed];
  283. // Create commitment to coin
  284. let commit_v = poseidon_hash(commit_msg);
  285. pedersen_commitment_base(commit_v, blind)
  286. }
  287. /// calculated derived coin commitment
  288. pub fn derived_commitment(&self, blind: pallas::Scalar) -> pallas::Point {
  289. let pk = self.pk();
  290. let rho = self.derived_rho();
  291. Self::commitment(pk, pallas::Base::from(self.value + constants::REWARD.clone()), rho, blind)
  292. }
  293. /// the new coin to be minted after the current coin is spent
  294. /// in lottery.
  295. pub fn derive_coin(
  296. &self,
  297. coin_commitment_tree: &mut BridgeTree<MerkleNode, MERKLE_DEPTH>,
  298. ) -> LeadCoin {
  299. debug!("derive_coin(): Deriving new coin!");
  300. let derived_c1_rho = self.derived_rho();
  301. let blind = pallas::Scalar::random(&mut OsRng);
  302. let derived_c2_cm = Self::commitment(
  303. self.pk(),
  304. pallas::Base::from(self.value + 2 * constants::REWARD),
  305. Self::util_derived_rho(self.coin1_sk_root, derived_c1_rho),
  306. blind,
  307. );
  308. let derived_c1_cm = { self.derived_commitment(self.coin2_blind) };
  309. let derived_c1_cm_coord = derived_c1_cm.to_affine().coordinates().unwrap();
  310. let derived_c1_cm_msg = [*derived_c1_cm_coord.x(), *derived_c1_cm_coord.y()];
  311. let derived_c1_cm_base = poseidon_hash(derived_c1_cm_msg);
  312. coin_commitment_tree.append(&MerkleNode::from(derived_c1_cm_base));
  313. let leaf_pos = coin_commitment_tree.witness().unwrap();
  314. let commitment_root = coin_commitment_tree.root(0).unwrap();
  315. let commitment_merkle_path =
  316. coin_commitment_tree.authentication_path(leaf_pos, &commitment_root).unwrap();
  317. LeadCoin {
  318. value: self.value + constants::REWARD,
  319. coin1_commitment: self.coin2_commitment,
  320. coin2_commitment: derived_c2_cm,
  321. idx: u32::try_from(usize::from(leaf_pos)).unwrap(),
  322. tau: self.tau,
  323. nonce: derived_c1_rho,
  324. coin1_commitment_root: commitment_root,
  325. coin1_sk: self.coin1_sk,
  326. coin1_sk_root: self.coin1_sk_root,
  327. coin1_sk_pos: self.coin1_sk_pos,
  328. coin1_commitment_merkle_path: commitment_merkle_path.try_into().unwrap(),
  329. coin1_sk_merkle_path: self.coin1_sk_merkle_path,
  330. coin1_blind: self.coin2_blind,
  331. coin2_blind: blind,
  332. y_mu: self.y_mu,
  333. rho_mu: self.rho_mu,
  334. secret_key: self.secret_key,
  335. eta: self.eta,
  336. slot: self.slot,
  337. }
  338. }
  339. pub fn coin_commitment_base(&self) -> pallas::Base {
  340. let c1_cm_coord = self.coin1_commitment.to_affine().coordinates().unwrap();
  341. let c1_cm_msg = [*c1_cm_coord.x(), *c1_cm_coord.y()];
  342. poseidon_hash(c1_cm_msg)
  343. }
  344. /// Try to create a ZK proof of consensus leadership
  345. pub fn create_lead_proof(
  346. &self,
  347. sigma1: pallas::Base,
  348. sigma2: pallas::Base,
  349. pk: &ProvingKey,
  350. ) -> (Result<Proof>, Vec<pallas::Base>) {
  351. let bincode = include_bytes!("../../proof/lead.zk.bin");
  352. let zkbin = ZkBinary::decode(bincode).unwrap();
  353. let witnesses = vec![
  354. Witness::MerklePath(Value::known(self.coin1_commitment_merkle_path)),
  355. Witness::Uint32(Value::known(self.idx)),
  356. Witness::Uint32(Value::known(self.coin1_sk_pos)),
  357. Witness::Base(Value::known(self.secret_key.inner())),
  358. Witness::Base(Value::known(self.coin1_sk_root.inner())),
  359. Witness::MerklePath(Value::known(self.coin1_sk_merkle_path)),
  360. Witness::Base(Value::known(self.tau)),
  361. Witness::Base(Value::known(self.nonce)),
  362. Witness::Scalar(Value::known(self.coin1_blind)),
  363. Witness::Base(Value::known(pallas::Base::from(self.value))),
  364. Witness::Scalar(Value::known(self.coin2_blind)),
  365. Witness::Base(Value::known(self.rho_mu)),
  366. Witness::Base(Value::known(self.y_mu)),
  367. Witness::Base(Value::known(sigma1)),
  368. Witness::Base(Value::known(sigma2)),
  369. ];
  370. let circuit = ZkCircuit::new(witnesses, zkbin.clone());
  371. let public_inputs = self.public_inputs(sigma1, sigma2);
  372. (Ok(Proof::create(pk, &[circuit], &public_inputs, &mut OsRng).unwrap()), public_inputs)
  373. }
  374. pub fn create_xfer_proof(
  375. &self,
  376. pk: &ProvingKey,
  377. change_coin: TxRcpt,
  378. change_pk: pallas::Base, //change coin public key
  379. transfered_coin: TxRcpt,
  380. transfered_pk: pallas::Base, // recipient coin's public key
  381. sigma1: pallas::Base,
  382. sigma2: pallas::Base,
  383. ) -> Result<TransferStx> {
  384. assert!(change_coin.value + transfered_coin.value == self.value && self.value > 0);
  385. let bincode = include_bytes!("../../proof/tx.zk.bin");
  386. let zkbin = ZkBinary::decode(bincode)?;
  387. let retval = pallas::Base::from(change_coin.value);
  388. let xferval = pallas::Base::from(transfered_coin.value);
  389. let pos: u32 = self.idx;
  390. let value = pallas::Base::from(self.value);
  391. let witnesses = vec![
  392. // coin (1) burned coin
  393. Witness::Base(Value::known(self.coin1_commitment_root.inner())),
  394. Witness::Base(Value::known(self.coin1_sk_root.inner())),
  395. Witness::Base(Value::known(self.coin1_sk)),
  396. Witness::MerklePath(Value::known(self.coin1_sk_merkle_path)),
  397. Witness::Uint32(Value::known(self.coin1_sk_pos)),
  398. Witness::Base(Value::known(self.nonce)),
  399. Witness::Scalar(Value::known(self.coin1_blind)),
  400. Witness::Base(Value::known(value)),
  401. Witness::MerklePath(Value::known(self.coin1_commitment_merkle_path)),
  402. Witness::Uint32(Value::known(pos)),
  403. Witness::Base(Value::known(self.sn())),
  404. // coin (3)
  405. Witness::Base(Value::known(change_pk)),
  406. Witness::Base(Value::known(change_coin.rho)),
  407. Witness::Scalar(Value::known(change_coin.opening)),
  408. Witness::Base(Value::known(retval)),
  409. // coin (4)
  410. Witness::Base(Value::known(transfered_pk)),
  411. Witness::Base(Value::known(transfered_coin.rho)),
  412. Witness::Scalar(Value::known(transfered_coin.opening)),
  413. Witness::Base(Value::known(xferval)),
  414. ];
  415. let circuit = ZkCircuit::new(witnesses, zkbin.clone());
  416. let proof = Proof::create(pk, &[circuit], &self.public_inputs(sigma1, sigma2), &mut OsRng)?;
  417. let cm3_msg_in = [
  418. pallas::Base::from(PREFIX_CM),
  419. change_pk,
  420. pallas::Base::from(change_coin.value),
  421. change_coin.rho,
  422. ];
  423. let cm3_msg = poseidon_hash(cm3_msg_in);
  424. let cm3 = pedersen_commitment_base(cm3_msg, change_coin.opening);
  425. let cm4_msg_in = [
  426. pallas::Base::from(PREFIX_CM),
  427. transfered_pk,
  428. pallas::Base::from(transfered_coin.value),
  429. transfered_coin.rho,
  430. ];
  431. let cm4_msg = poseidon_hash(cm4_msg_in);
  432. let cm4 = pedersen_commitment_base(cm4_msg, transfered_coin.opening);
  433. let tx = TransferStx {
  434. coin_commitment: self.coin1_commitment,
  435. coin_pk: self.pk(),
  436. coin_root_sk: self.coin1_sk_root,
  437. change_coin_commitment: cm3,
  438. transfered_coin_commitment: cm4,
  439. nullifier: self.sn(),
  440. tau: self.tau,
  441. root: self.coin1_commitment_root,
  442. proof,
  443. };
  444. Ok(tx)
  445. }
  446. }
  447. /// This struct holds the secrets for creating LeadCoins during one epoch.
  448. pub struct LeadCoinSecrets {
  449. pub secret_keys: Vec<SecretKey>,
  450. pub merkle_roots: Vec<MerkleNode>,
  451. pub merkle_paths: Vec<[MerkleNode; MERKLE_DEPTH_LEADCOIN]>,
  452. }
  453. impl LeadCoinSecrets {
  454. /// Generate epoch coins secret keys.
  455. /// First clot coin secret key is sampled at random, while the secret keys of the
  456. /// remaining slots derive from the previous slot secret.
  457. /// Clarification:
  458. /// ```plaintext
  459. /// sk[0] -> random,
  460. /// sk[1] -> derive_function(sk[0]),
  461. /// ...
  462. /// sk[n] -> derive_function(sk[n-1]),
  463. /// ```
  464. pub fn generate() -> Self {
  465. let mut tree = BridgeTree::<MerkleNode, MERKLE_DEPTH>::new(EPOCH_LENGTH);
  466. let mut sks = Vec::with_capacity(EPOCH_LENGTH);
  467. let mut root_sks = Vec::with_capacity(EPOCH_LENGTH);
  468. let mut path_sks = Vec::with_capacity(EPOCH_LENGTH);
  469. let mut prev_sk = SecretKey::from(pallas::Base::one());
  470. for i in 0..EPOCH_LENGTH {
  471. let secret = if i == 0 {
  472. pedersen_commitment_u64(1, pallas::Scalar::random(&mut OsRng))
  473. } else {
  474. pedersen_commitment_u64(1, mod_r_p(prev_sk.inner()))
  475. };
  476. let secret_coords = secret.to_affine().coordinates().unwrap();
  477. let secret_msg = [*secret_coords.x(), *secret_coords.y()];
  478. let secret_key = SecretKey::from(poseidon_hash(secret_msg));
  479. sks.push(secret_key);
  480. prev_sk = secret_key;
  481. let node = MerkleNode::from(secret_key.inner());
  482. tree.append(&node);
  483. let leaf_pos = tree.witness().unwrap();
  484. let root = tree.root(0).unwrap();
  485. let path = tree.authentication_path(leaf_pos, &root).unwrap();
  486. root_sks.push(root);
  487. path_sks.push(path.try_into().unwrap());
  488. }
  489. Self { secret_keys: sks, merkle_roots: root_sks, merkle_paths: path_sks }
  490. }
  491. }