1use crate::chain::ergo_state_context::ErgoStateContext;
3use crate::chain::transaction::unsigned::UnsignedTransaction;
4use crate::chain::transaction::Transaction;
5use crate::ergotree_interpreter::eval::reduce_to_crypto;
6use crate::ergotree_interpreter::sigma_protocol::dht_protocol::interactive_prover as dht_interactive_prover;
7use crate::ergotree_interpreter::sigma_protocol::dlog_protocol::interactive_prover as dlog_interactive_prover;
8use crate::ergotree_interpreter::sigma_protocol::proof_tree::ProofTreeLeaf;
9use crate::ergotree_interpreter::sigma_protocol::prover::hint::{
10 CommitmentHint, Hint, HintsBag, OwnCommitment, RealCommitment, RealSecretProof, SecretProven,
11 SimulatedCommitment, SimulatedSecretProof,
12};
13use crate::ergotree_interpreter::sigma_protocol::prover::ProverError;
14use crate::ergotree_interpreter::sigma_protocol::sig_serializer::SigParsingError;
15use crate::ergotree_interpreter::sigma_protocol::unproven_tree::NodePosition;
16use crate::ergotree_interpreter::sigma_protocol::FirstProverMessage;
17use crate::ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean;
18use crate::ergotree_ir::sigma_protocol::sigma_boolean::SigmaConjecture;
19use crate::ergotree_ir::sigma_protocol::sigma_boolean::SigmaConjectureItems;
20use crate::ergotree_ir::sigma_protocol::sigma_boolean::SigmaProofOfKnowledgeTree;
21use crate::wallet::signing::{make_context, TransactionContext, TxSigningError};
22use ergotree_interpreter::sigma_protocol::sig_serializer::parse_sig_compute_challenges;
23use ergotree_interpreter::sigma_protocol::unchecked_tree::UncheckedTree;
24use ergotree_interpreter::sigma_protocol::verifier::compute_commitments;
25use std::collections::HashMap;
26
27use super::signing::update_context;
28use super::tx_context::TransactionContextError;
29
30#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
32#[cfg_attr(
33 feature = "json",
34 serde(
35 try_from = "crate::chain::json::hint::TransactionHintsBagJson",
36 into = "crate::chain::json::hint::TransactionHintsBagJson"
37 )
38)]
39#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
40#[derive(PartialEq, Debug, Clone)]
41pub struct TransactionHintsBag {
42 #[cfg_attr(
43 feature = "arbitrary",
44 proptest(
45 strategy = "proptest::collection::hash_map(proptest::prelude::any::<usize>(), proptest::prelude::any::<HintsBag>(), 0..5)"
46 )
47 )]
48 pub(crate) secret_hints: HashMap<usize, HintsBag>,
49 #[cfg_attr(
50 feature = "arbitrary",
51 proptest(
52 strategy = "proptest::collection::hash_map(proptest::prelude::any::<usize>(), proptest::prelude::any::<HintsBag>(), 0..5)"
53 )
54 )]
55 pub(crate) public_hints: HashMap<usize, HintsBag>,
56}
57
58impl TransactionHintsBag {
59 pub fn empty() -> Self {
61 TransactionHintsBag {
62 secret_hints: HashMap::new(),
63 public_hints: HashMap::new(),
64 }
65 }
66
67 pub fn replace_hints_for_input(&mut self, index: usize, hints_bag: HintsBag) {
69 let public: Vec<Hint> = hints_bag
70 .hints
71 .clone()
72 .into_iter()
73 .filter(|hint| matches!(hint, Hint::CommitmentHint(_)))
74 .collect();
75 let secret: Vec<Hint> = hints_bag
76 .hints
77 .into_iter()
78 .filter(|hint| matches!(hint, Hint::SecretProven(_)))
79 .collect();
80
81 self.secret_hints.insert(index, HintsBag { hints: secret });
82 self.public_hints.insert(index, HintsBag { hints: public });
83 }
84
85 pub fn add_hints_for_input(&mut self, index: usize, hints_bag: HintsBag) {
87 let mut public: Vec<Hint> = hints_bag
88 .hints
89 .clone()
90 .into_iter()
91 .filter(|hint| matches!(hint, Hint::CommitmentHint(_)))
92 .collect();
93 let mut secret: Vec<Hint> = hints_bag
94 .hints
95 .into_iter()
96 .filter(|hint| matches!(hint, Hint::SecretProven(_)))
97 .collect();
98 let secret_bag = HintsBag::empty();
99 let public_bag = HintsBag::empty();
100 let old_secret: &Vec<Hint> = &self.secret_hints.get(&index).unwrap_or(&secret_bag).hints;
101 for hint in old_secret {
102 secret.push(hint.clone());
103 }
104
105 let old_public: &Vec<Hint> = &self.public_hints.get(&index).unwrap_or(&public_bag).hints;
106 for hint in old_public {
107 public.push(hint.clone());
108 }
109 self.secret_hints.insert(index, HintsBag { hints: secret });
110 self.public_hints.insert(index, HintsBag { hints: public });
111 }
112
113 pub fn all_hints_for_input(&self, index: usize) -> HintsBag {
115 let mut hints: Vec<Hint> = Vec::new();
116 let secret_bag = HintsBag::empty();
117 let public_bag = HintsBag::empty();
118 let secrets: &Vec<Hint> = &self.secret_hints.get(&index).unwrap_or(&secret_bag).hints;
119 for hint in secrets {
120 hints.push(hint.clone());
121 }
122 let public: &Vec<Hint> = &self.public_hints.get(&index).unwrap_or(&public_bag).hints;
123 for hint in public {
124 hints.push(hint.clone());
125 }
126 let hints_bag: HintsBag = HintsBag { hints };
127 hints_bag
128 }
129}
130
131pub fn bag_for_multi_sig(
135 sigma_tree: &SigmaBoolean,
136 real_propositions: &[SigmaBoolean],
137 simulated_propositions: &[SigmaBoolean],
138 proof: &[u8],
139) -> Result<HintsBag, SigParsingError> {
140 if let SigmaBoolean::TrivialProp(_) = sigma_tree {
141 return Ok(HintsBag::empty());
142 }
143 let ut = compute_commitments(parse_sig_compute_challenges(sigma_tree, proof.to_owned())?);
144 fn traverse_node(
146 tree: UncheckedTree,
147 real_propositions: &[SigmaBoolean],
148 simulated_propositions: &[SigmaBoolean],
149 position: NodePosition,
150 bag: &mut HintsBag,
151 ) -> Result<(), SigParsingError> {
152 match tree {
153 UncheckedTree::UncheckedConjecture(unchecked_conjecture) => {
154 let items: SigmaConjectureItems<UncheckedTree> =
155 unchecked_conjecture.children_ust();
156 items
157 .iter()
158 .enumerate()
159 .try_for_each(|(i, x)| -> Result<(), SigParsingError> {
160 traverse_node(
161 x.clone(),
162 real_propositions,
163 simulated_propositions,
164 position.child(i),
165 bag,
166 )?;
167 Ok(())
168 })?;
169 }
170 UncheckedTree::UncheckedLeaf(leaf) => {
171 match leaf.commitment_opt() {
172 Some(commitment) => {
173 let real_found = real_propositions.contains(&leaf.proposition());
174 let simulated_found = simulated_propositions.contains(&leaf.proposition());
175 if real_found || simulated_found {
176 if real_found {
177 let real_commitment: Hint = Hint::CommitmentHint(
178 CommitmentHint::RealCommitment(RealCommitment {
179 image: leaf.proposition(),
180 commitment,
181 position: position.clone(),
182 }),
183 );
184 let real_secret_proof: Hint = Hint::SecretProven(
185 SecretProven::RealSecretProof(RealSecretProof {
186 image: leaf.proposition(),
187 challenge: leaf.challenge(),
188 unchecked_tree: UncheckedTree::UncheckedLeaf(leaf),
189 position,
190 }),
191 );
192 bag.add_hint(real_commitment);
193 bag.add_hint(real_secret_proof);
194 } else {
195 let simulated_commitment: Hint = Hint::CommitmentHint(
196 CommitmentHint::SimulatedCommitment(SimulatedCommitment {
197 image: leaf.proposition(),
198 commitment,
199 position: position.clone(),
200 }),
201 );
202 let simulated_secret_proof: Hint = Hint::SecretProven(
203 SecretProven::SimulatedSecretProof(SimulatedSecretProof {
204 image: leaf.proposition(),
205 challenge: leaf.challenge(),
206 unchecked_tree: UncheckedTree::UncheckedLeaf(leaf),
207 position,
208 }),
209 );
210 bag.add_hint(simulated_commitment);
211 bag.add_hint(simulated_secret_proof);
212 }
213 }
214 }
215 None => {
216 return Err(SigParsingError::EmptyCommitment(leaf.proposition()));
217 }
218 };
219 }
220 }
221 Ok(())
222 }
223
224 let mut bag: HintsBag = HintsBag::empty();
225
226 traverse_node(
227 ut,
228 real_propositions,
229 simulated_propositions,
230 NodePosition::crypto_tree_prefix(),
231 &mut bag,
232 )?;
233 Ok(bag)
234}
235
236pub fn generate_commitments(
242 tx_context: TransactionContext<UnsignedTransaction>,
243 state_context: &ErgoStateContext,
244 public_keys: &[SigmaBoolean],
245) -> Result<TransactionHintsBag, TxSigningError> {
246 let tx = tx_context.spending_tx.clone();
247 let mut hints_bag = TransactionHintsBag::empty();
248 let mut ctx = make_context(state_context, &tx_context, 0)?;
249 for (i, input) in tx.inputs.iter().enumerate() {
250 update_context(&mut ctx, &tx_context, i)?;
251 let input_box = tx_context
252 .get_input_box(&input.box_id)
253 .ok_or(TransactionContextError::InputBoxNotFound(i))?;
254 let tree = input_box.ergo_tree.clone();
255 let exp = tree
256 .proposition()
257 .map_err(ProverError::ErgoTreeError)
258 .map_err(|e| TxSigningError::ProverError(e, i))?;
259 let reduction_result = reduce_to_crypto(&exp, &ctx)
260 .map_err(ProverError::EvalError)
261 .map_err(|e| TxSigningError::ProverError(e, i))?;
262
263 let sigma_tree = reduction_result.sigma_prop;
264 hints_bag.add_hints_for_input(i, generate_commitments_for(&sigma_tree, public_keys));
265 }
266 Ok(hints_bag)
267}
268
269pub fn extract_hints(
271 tx_context: &TransactionContext<Transaction>,
272 state_context: &ErgoStateContext,
273 real_secrets_to_extract: Vec<SigmaBoolean>,
274 simulated_secrets_to_extract: Vec<SigmaBoolean>,
275) -> Result<TransactionHintsBag, TxSigningError> {
276 let mut hints_bag = TransactionHintsBag::empty();
277 let mut ctx = make_context(state_context, tx_context, 0)?;
278 for (i, input) in tx_context.spending_tx.inputs.iter().enumerate() {
279 update_context(&mut ctx, tx_context, i)?;
280 let input_box = tx_context
281 .get_input_box(&input.box_id)
282 .ok_or(TransactionContextError::InputBoxNotFound(i))?;
283 let tree = input_box.ergo_tree.clone();
284 let exp = tree
285 .proposition()
286 .map_err(ProverError::ErgoTreeError)
287 .map_err(|e| TxSigningError::ProverError(e, i))?;
288 let reduction_result = reduce_to_crypto(&exp, &ctx)
289 .map_err(ProverError::EvalError)
290 .map_err(|e| TxSigningError::ProverError(e, i))?;
291 let sigma_tree = reduction_result.sigma_prop;
292 let bag = bag_for_multi_sig(
293 &sigma_tree,
294 real_secrets_to_extract.as_slice(),
295 simulated_secrets_to_extract.as_slice(),
296 input.spending_proof.proof.as_ref(),
297 )?;
298 hints_bag.add_hints_for_input(i, bag);
299 }
300
301 Ok(hints_bag)
302}
303
304pub fn generate_commitments_for(
308 sigma_tree: &SigmaBoolean,
309 generate_for: &[SigmaBoolean],
310) -> HintsBag {
311 fn traverse_node(
312 sb: &SigmaBoolean,
313 bag: &mut HintsBag,
314 position: NodePosition,
315 generate_for: &[SigmaBoolean],
316 ) {
317 let sb_clone = sb.clone();
318 match sb {
319 SigmaBoolean::SigmaConjecture(sc) => match sc {
320 SigmaConjecture::Cand(c_and) => {
321 c_and.items.iter().enumerate().for_each(|(i, x)| {
322 traverse_node(x, bag, position.child(i), generate_for);
323 })
324 }
325 SigmaConjecture::Cor(cor) => cor.items.iter().enumerate().for_each(|(i, x)| {
326 traverse_node(x, bag, position.child(i), generate_for);
327 }),
328 SigmaConjecture::Cthreshold(c_threshold) => {
329 c_threshold.children.iter().enumerate().for_each(|(i, x)| {
330 traverse_node(x, bag, position.child(i), generate_for);
331 })
332 }
333 },
334 SigmaBoolean::ProofOfKnowledge(kt) => {
335 if generate_for.contains(&sb_clone) {
336 let kt_clone = kt.clone();
337 if let SigmaProofOfKnowledgeTree::ProveDlog(_pdl) = kt {
338 let (r, a) = dlog_interactive_prover::first_message();
339 let own_commitment: Hint =
340 Hint::CommitmentHint(CommitmentHint::OwnCommitment(OwnCommitment {
341 image: SigmaBoolean::ProofOfKnowledge(kt_clone.clone()),
342 secret_randomness: r,
343 commitment: FirstProverMessage::FirstDlogProverMessage(a.clone()),
344 position: position.clone(),
345 }));
346 let real_commitment: Hint =
347 Hint::CommitmentHint(CommitmentHint::RealCommitment(RealCommitment {
348 image: SigmaBoolean::ProofOfKnowledge(kt_clone),
349 commitment: FirstProverMessage::FirstDlogProverMessage(a),
350 position,
351 }));
352 bag.add_hint(real_commitment);
353 bag.add_hint(own_commitment);
354 } else if let SigmaProofOfKnowledgeTree::ProveDhTuple(pdht) = kt {
355 let (a, b) = dht_interactive_prover::first_message(pdht);
356 let own_commitment: Hint =
357 Hint::CommitmentHint(CommitmentHint::OwnCommitment(OwnCommitment {
358 image: SigmaBoolean::ProofOfKnowledge(kt_clone.clone()),
359 secret_randomness: a,
360 commitment: FirstProverMessage::FirstDhtProverMessage(b.clone()),
361 position: position.clone(),
362 }));
363 let real_commitment: Hint =
364 Hint::CommitmentHint(CommitmentHint::RealCommitment(RealCommitment {
365 image: SigmaBoolean::ProofOfKnowledge(kt_clone),
366 commitment: FirstProverMessage::FirstDhtProverMessage(b),
367 position,
368 }));
369 bag.add_hint(real_commitment);
370 bag.add_hint(own_commitment);
371 }
372 }
373 }
374 _ => (),
375 }
376 }
377 let mut bag = HintsBag::empty();
378 traverse_node(
379 sigma_tree,
380 &mut bag,
381 NodePosition::crypto_tree_prefix(),
382 generate_for,
383 );
384 bag
385}
386
387#[allow(clippy::unwrap_used)]
388#[cfg(test)]
389mod tests {
390 use super::*;
391 use crate::chain::transaction::Transaction;
392 use crate::ergotree_interpreter::eval::context::Context;
393 use crate::ergotree_interpreter::eval::reduce_to_crypto;
394 use crate::ergotree_interpreter::sigma_protocol::private_input::{
395 DlogProverInput, PrivateInput,
396 };
397 use crate::ergotree_interpreter::sigma_protocol::prover::{ProofBytes, Prover, TestProver};
398 use crate::ergotree_interpreter::sigma_protocol::verifier::{TestVerifier, Verifier};
399 use crate::ergotree_ir::chain::address::AddressEncoder;
400 use crate::ergotree_ir::chain::address::{Address, NetworkPrefix};
401 use crate::ergotree_ir::ergo_tree::ErgoTree;
402 use crate::ergotree_ir::mir::expr::Expr;
403 use crate::ergotree_ir::mir::sigma_and::SigmaAnd;
404 use crate::ergotree_ir::serialization::SigmaSerializable;
405 use crate::ergotree_ir::sigma_protocol::sigma_boolean::cand::Cand;
406 use ergo_chain_types::Base16DecodedBytes;
407 use ergotree_interpreter::sigma_protocol::private_input::DhTupleProverInput;
408 use ergotree_interpreter::sigma_protocol::wscalar::Wscalar;
409 use ergotree_ir::mir::atleast::Atleast;
410 use ergotree_ir::mir::constant::{Constant, Literal};
411 use ergotree_ir::mir::sigma_or::SigmaOr;
412 use ergotree_ir::mir::value::CollKind;
413 use ergotree_ir::sigma_protocol::sigma_boolean::SigmaProp;
414 use ergotree_ir::types::stype::SType;
415 use sigma_test_util::force_any_val;
416 use std::convert::{TryFrom, TryInto};
417
418 #[test]
419 fn extract_hint() {
420 let signed_tx = r#"{
421 "id": "6e32d1710816be34fd9710148b73f017bf8e71115cd2d3cf5758f80c2e3010ca",
422 "inputs": [
423 {
424 "boxId": "4c1155fca9bf7785f82eb43f74ef6a24164bac18f6cc35137e0ebf5a08abb8f7",
425 "spendingProof": {
426 "proofBytes": "77d85667cbb360c7ddad4d94c5e50930f3e72f6bdbd576bcce0098ab6547221d6943a49d4f6daaf06b37efc29884337701c16f4a0b9797db3061332b09849274beaa0609f146a468937338792bfe422425dd604b399df221",
427 "extension": {}
428 }
429 }
430 ],
431 "dataInputs": [],
432 "outputs": [
433 {
434 "boxId": "ad3e07a89bd0ec1161c1da54316ceb8efc6734ed08d3f005ade1184bf26d088d",
435 "value": 1000000,
436 "ergoTree": "0008cd039c8404d33f85dd4012e4f3d0719951eeea0015b13b940d67d4990e13de28b154",
437 "assets": [],
438 "additionalRegisters": {},
439 "creationHeight": 0,
440 "transactionId": "6e32d1710816be34fd9710148b73f017bf8e71115cd2d3cf5758f80c2e3010ca",
441 "index": 0
442 },
443 {
444 "boxId": "bcf15dbfd2b7d5e4688cb28d1393356bd1c96d6ef94c2942a2958545a51d2501",
445 "value": 2300000,
446 "ergoTree": "0008cd039c8404d33f85dd4012e4f3d0719951eeea0015b13b940d67d4990e13de28b154",
447 "assets": [],
448 "additionalRegisters": {},
449 "creationHeight": 0,
450 "transactionId": "6e32d1710816be34fd9710148b73f017bf8e71115cd2d3cf5758f80c2e3010ca",
451 "index": 1
452 },
453 {
454 "boxId": "6e473151a782e68cff7fd4f0127eeb43cf71e7a6d7fddf1b25ad4814fb451292",
455 "value": 1100000,
456 "ergoTree": "1005040004000e36100204a00b08cd0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ea02d192a39a8cc7a701730073011001020402d19683030193a38cc7b2a57300000193c2b2a57301007473027303830108cdeeac93b1a57304",
457 "assets": [],
458 "additionalRegisters": {},
459 "creationHeight": 0,
460 "transactionId": "6e32d1710816be34fd9710148b73f017bf8e71115cd2d3cf5758f80c2e3010ca",
461 "index": 2
462 }
463 ]
464 }"#;
465 let bytes_m = Base16DecodedBytes::try_from("100208cd03c847c306a2f9a8087b4ae63261cc5acea9034000ba8d033b0fb033247e8aade908cd02f4b05f44eb9703db7fcf9c94b89566787a7188c7e48964821d485d9ef2f9e4c4ea0273007301").unwrap();
466 let tree_m: ErgoTree = ErgoTree::sigma_parse_bytes(&bytes_m.0).unwrap();
467
468 let contx = force_any_val::<Context>();
469 let exp = tree_m.proposition().unwrap();
470 let reduction_result = reduce_to_crypto(&exp, &contx).unwrap();
471 let sigma_tree = reduction_result.sigma_prop;
472 let stx: Transaction = serde_json::from_str(signed_tx).unwrap();
473 let test: ProofBytes = stx.inputs.first().clone().spending_proof.proof;
474 let proof: Vec<u8> = Vec::from(test);
475 let mut real_proposition: Vec<SigmaBoolean> = Vec::new();
476 let mut simulated_proposition: Vec<SigmaBoolean> = Vec::new();
477 let mut bag: HintsBag = bag_for_multi_sig(
478 &sigma_tree,
479 real_proposition.as_slice(),
480 simulated_proposition.as_slice(),
481 proof.as_slice(),
482 )
483 .unwrap();
484 assert!(bag.hints.is_empty(), "{}", "{}");
485
486 let address_encoder = AddressEncoder::new(NetworkPrefix::Mainnet);
487 let first_address: Address = address_encoder
488 .parse_address_from_str("9hz1anoLGZGf88hjjrQ3y3oSpSE2Kkk15CcfFqCNYXDPWKV6F4i")
489 .unwrap();
490 let second_address = address_encoder
491 .parse_address_from_str("9gNpmNsivNnAKb7EtGVLGF24wRUJWnEqycCnWCeYxwSFZxkKyTZ")
492 .unwrap();
493
494 if let Address::P2Pk(pk) = first_address {
495 {
496 real_proposition.push(SigmaBoolean::ProofOfKnowledge(
497 SigmaProofOfKnowledgeTree::ProveDlog(pk),
498 ));
499 }
500 }
501 if let Address::P2Pk(pk) = second_address {
502 {
503 simulated_proposition.push(SigmaBoolean::ProofOfKnowledge(
504 SigmaProofOfKnowledgeTree::ProveDlog(pk),
505 ));
506 }
507 }
508 bag = bag_for_multi_sig(
509 &sigma_tree,
510 real_proposition.as_slice(),
511 simulated_proposition.as_slice(),
512 proof.as_slice(),
513 )
514 .unwrap();
515 assert!(!bag.hints.is_empty(), "{}", "{}");
516 }
517
518 #[test]
519 fn generating_commitment_two_signer() {
520 let secret1 = DlogProverInput::random();
521 let secret2 = DhTupleProverInput::random();
522 let pk1 = secret1.public_image();
523 let pk2 = secret2.public_image();
524 let mut generate_for: Vec<SigmaBoolean> = vec![SigmaBoolean::ProofOfKnowledge(
525 SigmaProofOfKnowledgeTree::ProveDhTuple(pk2.clone()),
526 )];
527
528 assert_eq!(
529 generate_commitments_for(
530 &SigmaBoolean::ProofOfKnowledge(SigmaProofOfKnowledgeTree::ProveDlog(pk1.clone())),
531 generate_for.as_slice(),
532 )
533 .hints
534 .len(),
535 0
536 );
537 generate_for.clear();
538 let cand = Cand::normalized(
539 vec![
540 pk1.clone().into(),
541 SigmaBoolean::ProofOfKnowledge(SigmaProofOfKnowledgeTree::ProveDhTuple(
542 pk2.clone(),
543 )),
544 ]
545 .try_into()
546 .unwrap(),
547 );
548 generate_for.push(cand.clone());
549 assert!(
550 generate_commitments_for(
551 &SigmaBoolean::ProofOfKnowledge(SigmaProofOfKnowledgeTree::ProveDlog(pk1.clone())),
552 generate_for.as_slice(),
553 )
554 .hints
555 .is_empty(),
556 "{}",
557 "{}"
558 );
559 assert!(
560 generate_commitments_for(&cand, generate_for.as_slice())
561 .hints
562 .is_empty(),
563 "{}",
564 "{}"
565 );
566 generate_for.clear();
567 generate_for.push(SigmaBoolean::ProofOfKnowledge(
568 SigmaProofOfKnowledgeTree::ProveDlog(pk1.clone()),
569 ));
570
571 assert!(
572 !generate_commitments_for(
573 &SigmaBoolean::ProofOfKnowledge(SigmaProofOfKnowledgeTree::ProveDlog(pk1.clone())),
574 generate_for.as_slice(),
575 )
576 .hints
577 .is_empty(),
578 "{}",
579 "{}"
580 );
581 generate_for.clear();
582 generate_for.push(SigmaBoolean::ProofOfKnowledge(
583 SigmaProofOfKnowledgeTree::ProveDlog(pk1.clone()),
584 ));
585 let mut bag = generate_commitments_for(
586 &SigmaBoolean::ProofOfKnowledge(SigmaProofOfKnowledgeTree::ProveDlog(pk1)),
587 generate_for.as_slice(),
588 );
589 assert!(!bag.hints.is_empty(), "{}", "{}");
590 let mut hint = bag.hints[0].clone();
591 let mut a: Option<FirstProverMessage> = None;
592 let mut r: Option<Wscalar> = None;
593 if let Hint::CommitmentHint(CommitmentHint::RealCommitment(comm)) = hint {
594 assert_eq!(comm.position, NodePosition::crypto_tree_prefix());
595 a = Some(comm.commitment);
596 }
597 hint = bag.hints[1].clone();
598 if let Hint::CommitmentHint(CommitmentHint::OwnCommitment(comm)) = hint {
599 assert_eq!(comm.position, NodePosition::crypto_tree_prefix());
600 r = Some(comm.secret_randomness);
601 }
602 use ergo_chain_types::ec_point::{exponentiate, generator};
603 let g_to_r = exponentiate(&generator(), r.unwrap().as_scalar_ref());
604 assert_eq!(
605 FirstProverMessage::FirstDlogProverMessage(g_to_r.into()),
606 a.unwrap()
607 );
608
609 bag = generate_commitments_for(&cand, generate_for.as_slice());
610 assert_eq!(bag.hints.len(), 2);
611 hint = bag.hints[0].clone();
612 if let Hint::CommitmentHint(CommitmentHint::RealCommitment(comm)) = hint {
613 assert_eq!(
614 comm.position,
615 NodePosition {
616 positions: vec![0, 0]
617 }
618 );
619 }
620 hint = bag.hints[1].clone();
621 if let Hint::CommitmentHint(CommitmentHint::OwnCommitment(comm)) = hint {
622 assert_eq!(
623 comm.position,
624 NodePosition {
625 positions: vec![0, 0]
626 }
627 );
628 }
629 generate_for.clear();
630 generate_for.push(SigmaBoolean::ProofOfKnowledge(
631 SigmaProofOfKnowledgeTree::ProveDhTuple(pk2.clone()),
632 ));
633 bag = generate_commitments_for(
634 &SigmaBoolean::ProofOfKnowledge(SigmaProofOfKnowledgeTree::ProveDhTuple(pk2.clone())),
635 generate_for.as_slice(),
636 );
637 assert_ne!(bag.hints.len(), 0);
638 hint = bag.hints[0].clone();
639 if let Hint::CommitmentHint(CommitmentHint::RealCommitment(comm)) = hint {
640 assert_eq!(comm.position, NodePosition::crypto_tree_prefix(),);
641 }
642 hint = bag.hints[1].clone();
643 if let Hint::CommitmentHint(CommitmentHint::OwnCommitment(comm)) = hint {
644 assert_eq!(comm.position, NodePosition::crypto_tree_prefix(),);
645 }
646 hint = bag.hints[0].clone();
647 if let Hint::CommitmentHint(CommitmentHint::RealCommitment(real_commitment)) = hint {
648 if let Hint::CommitmentHint(CommitmentHint::OwnCommitment(own_commitment)) =
649 bag.hints[1].clone()
650 {
651 assert_eq!(real_commitment.commitment, own_commitment.commitment,);
652 }
653 }
654 }
655
656 #[test]
657 fn multi_sig_2() {
658 let ctx = force_any_val::<Context>();
659
660 let secret1 = DlogProverInput::random();
661 let secret2 = DlogProverInput::random();
662 let pk1 = secret1.public_image();
663 let pk2 = secret2.public_image();
664 let prover1 = TestProver {
665 secrets: vec![PrivateInput::DlogProverInput(secret1)],
666 };
667 let prover2 = TestProver {
668 secrets: vec![PrivateInput::DlogProverInput(secret2)],
669 };
670 let expr: Expr = SigmaAnd::new(vec![
671 Expr::Const(pk1.clone().into()),
672 Expr::Const(pk2.clone().into()),
673 ])
674 .unwrap()
675 .into();
676 let tree_and = ErgoTree::try_from(expr.clone()).unwrap();
677
678 let cand = reduce_to_crypto(&expr, &ctx).unwrap().sigma_prop;
679 let generate_for: Vec<SigmaBoolean> = vec![SigmaBoolean::ProofOfKnowledge(
680 SigmaProofOfKnowledgeTree::ProveDlog(pk2),
681 )];
682 let hints_from_bob: HintsBag = generate_commitments_for(&cand, &generate_for);
683 let bag1 = hints_from_bob.real_commitments();
684 let own = hints_from_bob.own_commitments();
685 let message = vec![0u8; 100];
686 let mut bag_a = HintsBag { hints: vec![] };
687 bag_a.add_hint(Hint::CommitmentHint(CommitmentHint::RealCommitment(
688 bag1.first().unwrap().clone(),
689 )));
690
691 let proof1 = prover1
692 .prove(&tree_and, &ctx, message.as_slice(), &bag_a)
693 .unwrap();
694 let proof: Vec<u8> = Vec::from(proof1.proof);
695 let real_proposition: Vec<SigmaBoolean> = vec![SigmaBoolean::ProofOfKnowledge(
696 SigmaProofOfKnowledgeTree::ProveDlog(pk1),
697 )];
698 let simulated_proposition: Vec<SigmaBoolean> = Vec::new();
699 let mut bag_b =
700 bag_for_multi_sig(&cand, &real_proposition, &simulated_proposition, &proof).unwrap();
701 bag_b.add_hint(Hint::CommitmentHint(CommitmentHint::OwnCommitment(
702 own.first().unwrap().clone(),
703 )));
704 let proof2 = prover2
705 .prove(&tree_and, &ctx, message.as_slice(), &bag_b)
706 .unwrap();
707 let proof_byte: ProofBytes = proof2.proof;
708 let verifier = TestVerifier;
709
710 assert!(
711 verifier
712 .verify(&tree_and, &ctx, proof_byte, message.as_slice(),)
713 .unwrap()
714 .result,
715 "{}",
716 "{}"
717 );
718 }
719
720 #[test]
721 fn multi_sig_and_3() {
722 let ctx = force_any_val::<Context>();
723
724 let secret1 = DlogProverInput::random();
725 let secret2 = DlogProverInput::random();
726 let secret3 = DlogProverInput::random();
727 let pk1 = secret1.public_image();
728 let pk2 = secret2.public_image();
729 let pk3 = secret3.public_image();
730 let prover1 = TestProver {
731 secrets: vec![PrivateInput::DlogProverInput(secret1)],
732 };
733 let prover2 = TestProver {
734 secrets: vec![PrivateInput::DlogProverInput(secret2)],
735 };
736 let prover3 = TestProver {
737 secrets: vec![PrivateInput::DlogProverInput(secret3)],
738 };
739
740 let expr: Expr = SigmaAnd::new(vec![
741 Expr::Const(pk1.clone().into()),
742 Expr::Const(pk2.clone().into()),
743 Expr::Const(pk3.clone().into()),
744 ])
745 .unwrap()
746 .into();
747
748 let tree_expr = ErgoTree::try_from(expr.clone()).unwrap();
749
750 let expr_reduced = reduce_to_crypto(&expr, &ctx).unwrap().sigma_prop;
751 let mut generate_for: Vec<SigmaBoolean> = vec![SigmaBoolean::ProofOfKnowledge(
752 SigmaProofOfKnowledgeTree::ProveDlog(pk2),
753 )];
754 let hints_from_bob: HintsBag = generate_commitments_for(&expr_reduced, &generate_for);
755 let bag2 = hints_from_bob.real_commitments();
756 let bob_secret_commitment = hints_from_bob.own_commitments();
757 generate_for = vec![SigmaBoolean::ProofOfKnowledge(
758 SigmaProofOfKnowledgeTree::ProveDlog(pk3.clone()),
759 )];
760 let hints_from_carol: HintsBag = generate_commitments_for(&expr_reduced, &generate_for);
761 let bag3 = hints_from_carol.real_commitments();
762 let carol_secret_commitment = hints_from_carol.own_commitments();
763 let message = vec![0u8; 100];
764 let mut bag_a = HintsBag { hints: vec![] };
765 bag_a.add_hint(Hint::CommitmentHint(CommitmentHint::RealCommitment(
766 bag2.first().unwrap().clone(),
767 )));
768 bag_a.add_hint(Hint::CommitmentHint(CommitmentHint::RealCommitment(
769 bag3.first().unwrap().clone(),
770 )));
771 let proof1 = prover1
772 .prove(&tree_expr, &ctx, message.as_slice(), &bag_a)
773 .unwrap();
774 let mut proof: Vec<u8> = Vec::from(proof1.proof.clone());
775 let proof_byte1: ProofBytes = proof1.proof;
776 let mut real_proposition: Vec<SigmaBoolean> = vec![SigmaBoolean::ProofOfKnowledge(
777 SigmaProofOfKnowledgeTree::ProveDlog(pk1.clone()),
778 )];
779 let simulated_proposition: Vec<SigmaBoolean> = Vec::new();
780 let mut bag_c = bag_for_multi_sig(
781 &expr_reduced,
782 &real_proposition,
783 &simulated_proposition,
784 &proof,
785 )
786 .unwrap();
787 bag_c.add_hint(Hint::CommitmentHint(CommitmentHint::OwnCommitment(
788 carol_secret_commitment.first().unwrap().clone(),
789 )));
790 bag_c.add_hint(Hint::CommitmentHint(CommitmentHint::RealCommitment(
791 bag2.first().unwrap().clone(),
792 )));
793 let proof3 = prover3
794 .prove(&tree_expr, &ctx, message.as_slice(), &bag_c)
795 .unwrap();
796 proof = Vec::from(proof3.proof.clone());
797 let proof_byte3: ProofBytes = proof3.proof;
798 real_proposition = vec![
799 SigmaBoolean::ProofOfKnowledge(SigmaProofOfKnowledgeTree::ProveDlog(pk1)),
800 SigmaBoolean::ProofOfKnowledge(SigmaProofOfKnowledgeTree::ProveDlog(pk3)),
801 ];
802 let mut bag_b = bag_for_multi_sig(
803 &expr_reduced,
804 &real_proposition,
805 &simulated_proposition,
806 &proof,
807 )
808 .unwrap();
809 bag_b.add_hint(Hint::CommitmentHint(CommitmentHint::OwnCommitment(
810 bob_secret_commitment.first().unwrap().clone(),
811 )));
812 let proof2 = prover2
813 .prove(&tree_expr, &ctx, message.as_slice(), &bag_b)
814 .unwrap();
815 let proof_byte2: ProofBytes = proof2.proof;
816 let verifier = TestVerifier;
817
818 assert!(
819 !verifier
820 .verify(&tree_expr, &ctx, proof_byte1, message.as_slice(),)
821 .unwrap()
822 .result,
823 "{}",
824 "{}"
825 );
826
827 assert!(
828 !verifier
829 .verify(&tree_expr, &ctx, proof_byte3, message.as_slice(),)
830 .unwrap()
831 .result,
832 "{}",
833 "{}"
834 );
835
836 assert!(
837 verifier
838 .verify(&tree_expr, &ctx, proof_byte2, message.as_slice(),)
839 .unwrap()
840 .result,
841 "{}",
842 "{}"
843 );
844 }
845
846 #[test]
847 fn multi_dlog_dht() {
848 let ctx = force_any_val::<Context>();
849
850 let secret_alice = DlogProverInput::random();
851 let secret_bob = DlogProverInput::random();
852 let secret_carol = DhTupleProverInput::random();
853 let secret_dave = DhTupleProverInput::random();
854
855 let pk_alice = secret_alice.public_image();
856 let pk_bob = secret_bob.public_image();
857 let pk_carol = secret_carol.public_image();
858 let pk_dave = secret_dave.public_image();
859 let prover_a = TestProver {
860 secrets: vec![PrivateInput::DlogProverInput(secret_alice)],
861 };
862 let _prover_b = TestProver {
863 secrets: vec![PrivateInput::DlogProverInput(secret_bob)],
864 };
865 let _prover_c = TestProver {
866 secrets: vec![PrivateInput::DhTupleProverInput(secret_carol.clone())],
867 };
868 let _prover_d = TestProver {
869 secrets: vec![PrivateInput::DhTupleProverInput(secret_dave.clone())],
870 };
871 let first_expr: Expr = SigmaOr::new(vec![
872 Expr::Const(pk_alice.clone().into()),
873 Expr::Const(pk_bob.clone().into()),
874 ])
875 .unwrap()
876 .into();
877 let second_expr: Expr = SigmaOr::new(vec![
878 Expr::Const(pk_carol.clone().into()),
879 Expr::Const(pk_dave.clone().into()),
880 ])
881 .unwrap()
882 .into();
883 let exp: Expr = SigmaAnd::new(vec![first_expr, second_expr]).unwrap().into();
884 let tree = ErgoTree::try_from(exp.clone()).unwrap();
885 let ctree = reduce_to_crypto(&exp, &ctx).unwrap().sigma_prop;
886 let mut generate_for: Vec<SigmaBoolean> = vec![SigmaBoolean::ProofOfKnowledge(
887 SigmaProofOfKnowledgeTree::ProveDlog(pk_alice.clone()),
888 )];
889 let alice_hints: HintsBag = generate_commitments_for(&ctree, &generate_for);
890 let secret_commitment_alice = alice_hints.own_commitments();
891 generate_for = vec![SigmaBoolean::ProofOfKnowledge(
892 SigmaProofOfKnowledgeTree::ProveDhTuple(pk_dave.clone()),
893 )];
894 let dave_hints: HintsBag = generate_commitments_for(&ctree, &generate_for);
895 let dave_known = dave_hints.real_commitments();
896 let _dave_secret_commitment = dave_hints.own_commitments();
897 let message = vec![0u8; 100];
898 let mut bag_a = HintsBag::empty();
899 bag_a.add_hint(Hint::CommitmentHint(CommitmentHint::OwnCommitment(
900 secret_commitment_alice.first().unwrap().clone(),
901 )));
902 bag_a.add_hint(Hint::CommitmentHint(CommitmentHint::RealCommitment(
903 dave_known.first().unwrap().clone(),
904 )));
905 let proof_a = prover_a
906 .prove(&tree, &ctx, message.as_slice(), &bag_a)
907 .unwrap();
908 let proof: Vec<u8> = Vec::from(proof_a.proof.clone());
909 let proof_byte_a: ProofBytes = proof_a.proof;
910 let verifier = TestVerifier;
911
912 assert!(
913 !verifier
914 .verify(&tree, &ctx, proof_byte_a, message.as_slice(),)
915 .unwrap()
916 .result,
917 "{}",
918 "{}"
919 );
920 let real_proposition: Vec<SigmaBoolean> = vec![SigmaBoolean::ProofOfKnowledge(
921 SigmaProofOfKnowledgeTree::ProveDlog(pk_alice),
922 )];
923 let simulated_proposition: Vec<SigmaBoolean> = vec![
924 SigmaBoolean::ProofOfKnowledge(SigmaProofOfKnowledgeTree::ProveDlog(pk_bob.clone())),
925 SigmaBoolean::ProofOfKnowledge(SigmaProofOfKnowledgeTree::ProveDhTuple(
926 pk_carol.clone(),
927 )),
928 ];
929 println!(
930 "{:?}",
931 SigmaBoolean::ProofOfKnowledge(SigmaProofOfKnowledgeTree::ProveDlog(pk_bob))
932 );
933 let mut bag =
934 bag_for_multi_sig(&ctree, &real_proposition, &simulated_proposition, &proof).unwrap();
935 bag.add_hint(Hint::CommitmentHint(CommitmentHint::OwnCommitment(
936 _dave_secret_commitment.first().unwrap().clone(),
937 )));
938
939 let proof_d = _prover_d
940 .prove(&tree, &ctx, message.as_slice(), &bag)
941 .unwrap();
942 let proof_byte_d: ProofBytes = proof_d.proof;
943
944 assert!(
945 verifier
946 .verify(&tree, &ctx, proof_byte_d, message.as_slice())
947 .unwrap()
948 .result,
949 "{}",
950 "{}"
951 );
952 }
953
954 #[test]
955 fn multi_sig_atleast_2_out_of_3() {
956 let ctx = force_any_val::<Context>();
958
959 let alice_secret = DlogProverInput::random();
960 let bob_secret = DlogProverInput::random();
961 let carol_secret = DlogProverInput::random();
962 let alice_pk = alice_secret.public_image();
963 let bob_pk = bob_secret.public_image();
964 let carol_pk = carol_secret.public_image();
965 let alice_prover = TestProver {
966 secrets: vec![PrivateInput::DlogProverInput(alice_secret)],
967 };
968 let bob_prover = TestProver {
969 secrets: vec![PrivateInput::DlogProverInput(bob_secret)],
970 };
971 let _carol_prover = TestProver {
972 secrets: vec![PrivateInput::DlogProverInput(carol_secret)],
973 };
974
975 let bound = Expr::Const(2i32.into());
976 let inputs = Literal::Coll(
977 CollKind::from_collection(
978 SType::SSigmaProp,
979 [
980 SigmaProp::from(alice_pk.clone()).into(),
981 SigmaProp::from(bob_pk.clone()).into(),
982 SigmaProp::from(carol_pk.clone()).into(),
983 ],
984 )
985 .unwrap(),
986 );
987 let input = Constant {
988 tpe: SType::SColl(SType::SSigmaProp.into()),
989 v: inputs,
990 }
991 .into();
992 let expr: Expr = Atleast::new(bound, input).unwrap().into();
993
994 let tree_expr = ErgoTree::try_from(expr.clone()).unwrap();
995
996 let expr_reduced = reduce_to_crypto(&expr, &ctx).unwrap().sigma_prop;
997 let message = vec![0u8; 100];
998
999 let hints_from_bob: HintsBag = generate_commitments_for(&expr_reduced, &[bob_pk.into()]);
1000
1001 let bob_real_commitment = hints_from_bob.real_commitments();
1002
1003 let mut bag_a = HintsBag { hints: vec![] };
1004 bag_a.add_hint(Hint::CommitmentHint(CommitmentHint::RealCommitment(
1005 bob_real_commitment.first().unwrap().clone(),
1006 )));
1007
1008 let proof_alice = alice_prover
1009 .prove(&tree_expr, &ctx, message.as_slice(), &bag_a)
1010 .unwrap();
1011
1012 let mut bag_b = bag_for_multi_sig(
1013 &expr_reduced,
1014 &[alice_pk.into()],
1015 &[carol_pk.into()],
1016 proof_alice.proof.as_ref(),
1017 )
1018 .unwrap();
1019 bag_b.add_hint(Hint::CommitmentHint(CommitmentHint::OwnCommitment(
1020 hints_from_bob.own_commitments().first().unwrap().clone(),
1021 )));
1022
1023 let proof_bob = bob_prover
1024 .prove(&tree_expr, &ctx, message.as_slice(), &bag_b)
1025 .unwrap();
1026
1027 let verifier = TestVerifier;
1028
1029 assert!(
1030 !verifier
1031 .verify(&tree_expr, &ctx, proof_alice.proof, message.as_slice())
1032 .unwrap()
1033 .result,
1034 "Proof generated by Alice without getting Bob's part is not correct"
1035 );
1036
1037 assert!(
1038 verifier
1039 .verify(&tree_expr, &ctx, proof_bob.proof, message.as_slice())
1040 .unwrap()
1041 .result,
1042 "Compound proof from Bob is correct"
1043 );
1044 }
1045
1046 #[test]
1047 fn multi_sig_atleast_3_out_of_4() {
1048 let ctx = force_any_val::<Context>();
1051
1052 let alice_secret = DlogProverInput::random();
1053 let bob_secret = DlogProverInput::random();
1054 let carol_secret = DlogProverInput::random();
1055 let dave_secret = DlogProverInput::random();
1056 let alice_pk = alice_secret.public_image();
1057 let bob_pk = bob_secret.public_image();
1058 let carol_pk = carol_secret.public_image();
1059 let dave_pk = dave_secret.public_image();
1060 let alice_prover = TestProver {
1061 secrets: vec![PrivateInput::DlogProverInput(alice_secret)],
1062 };
1063 let bob_prover = TestProver {
1064 secrets: vec![PrivateInput::DlogProverInput(bob_secret)],
1065 };
1066 let _carol_prover = TestProver {
1067 secrets: vec![PrivateInput::DlogProverInput(carol_secret)],
1068 };
1069
1070 let bound = Expr::Const(3i32.into());
1071 let inputs = Literal::Coll(
1072 CollKind::from_collection(
1073 SType::SSigmaProp,
1074 [
1075 SigmaProp::from(alice_pk.clone()).into(),
1076 SigmaProp::from(bob_pk.clone()).into(),
1077 SigmaProp::from(carol_pk.clone()).into(),
1078 SigmaProp::from(dave_pk.clone()).into(),
1079 ],
1080 )
1081 .unwrap(),
1082 );
1083 let input = Constant {
1084 tpe: SType::SColl(SType::SSigmaProp.into()),
1085 v: inputs,
1086 }
1087 .into();
1088 let expr: Expr = Atleast::new(bound, input).unwrap().into();
1089
1090 let tree_expr = ErgoTree::try_from(expr.clone()).unwrap();
1091
1092 let expr_reduced = reduce_to_crypto(&expr, &ctx).unwrap().sigma_prop;
1093 let message = vec![0u8; 100];
1094
1095 let bob_hints: HintsBag = generate_commitments_for(&expr_reduced, &[bob_pk.into()]);
1096 let dl_b_known = bob_hints.real_commitments().first().unwrap().clone();
1097
1098 let carol_hints: HintsBag =
1099 generate_commitments_for(&expr_reduced, &[carol_pk.clone().into()]);
1100 let dl_c_known = carol_hints.real_commitments().first().unwrap().clone();
1101
1102 let bag_a = HintsBag {
1103 hints: vec![dl_b_known.clone().into(), dl_c_known.into()],
1104 };
1105
1106 let proof_alice = alice_prover
1107 .prove(&tree_expr, &ctx, message.as_slice(), &bag_a)
1108 .unwrap();
1109
1110 let mut bag_c = bag_for_multi_sig(
1111 &expr_reduced,
1112 &[alice_pk.clone().into()],
1113 &[dave_pk.clone().into()],
1114 proof_alice.proof.as_ref(),
1115 )
1116 .unwrap();
1117 bag_c.hints.push(dl_b_known.into());
1118 bag_c.hints.push(
1119 carol_hints
1120 .own_commitments()
1121 .first()
1122 .unwrap()
1123 .clone()
1124 .into(),
1125 );
1126
1127 let proof_carol = _carol_prover
1128 .prove(&tree_expr, &ctx, message.as_slice(), &bag_c)
1129 .unwrap();
1130
1131 let bag_b_1 = bag_for_multi_sig(
1132 &expr_reduced,
1133 &[alice_pk.into()],
1134 &[dave_pk.into()],
1135 proof_alice.proof.as_ref(),
1136 )
1137 .unwrap();
1138
1139 let bag_b_2 = bag_for_multi_sig(
1140 &expr_reduced,
1141 &[carol_pk.into()],
1142 &[],
1143 proof_carol.proof.as_ref(),
1144 )
1145 .unwrap();
1146
1147 let mut bag_b = HintsBag::from_bags(vec![bag_b_1, bag_b_2]);
1148
1149 bag_b.add_hint(bob_hints.own_commitments().first().unwrap().clone().into());
1150
1151 let proof_bob = bob_prover
1152 .prove(&tree_expr, &ctx, message.as_slice(), &bag_b)
1153 .unwrap();
1154
1155 let verifier = TestVerifier;
1156
1157 assert!(
1158 !verifier
1159 .verify(&tree_expr, &ctx, proof_alice.proof, message.as_slice(),)
1160 .unwrap()
1161 .result,
1162 "Proof generated by Alice without getting Bob's part is not correct"
1163 );
1164
1165 assert!(
1166 !verifier
1167 .verify(&tree_expr, &ctx, proof_carol.proof, message.as_slice(),)
1168 .unwrap()
1169 .result,
1170 "Proof generated by Carol without getting Bob's part is not correct"
1171 );
1172
1173 assert!(
1174 verifier
1175 .verify(&tree_expr, &ctx, proof_bob.proof, message.as_slice())
1176 .unwrap()
1177 .result,
1178 "Compound proof from Bob is correct"
1179 );
1180 }
1181
1182 #[test]
1183 fn multi_sig_atleast_7_out_of_10_i692() {
1184 let ctx = force_any_val::<Context>();
1187
1188 let sk1 = DlogProverInput::random();
1189 let pk1 = sk1.public_image();
1190 let sk2 = DlogProverInput::random();
1191 let pk2 = sk2.public_image();
1192 let sk3 = DlogProverInput::random();
1193 let pk3 = sk3.public_image();
1194 let sk4 = DlogProverInput::random();
1195 let pk4 = sk4.public_image();
1196 let sk5 = DlogProverInput::random();
1197 let pk5 = sk5.public_image();
1198 let sk6 = DlogProverInput::random();
1199 let pk6 = sk6.public_image();
1200 let sk7 = DlogProverInput::random();
1201 let pk7 = sk7.public_image();
1202 let sk8 = DlogProverInput::random();
1203 let pk8 = sk8.public_image();
1204 let sk9 = DlogProverInput::random();
1205 let pk9 = sk9.public_image();
1206 let sk10 = DlogProverInput::random();
1207 let pk10 = sk10.public_image();
1208
1209 let prover1 = TestProver {
1210 secrets: vec![sk1.into()],
1211 };
1212 let prover2 = TestProver {
1213 secrets: vec![sk2.into()],
1214 };
1215 let prover3 = TestProver {
1216 secrets: vec![sk3.into()],
1217 };
1218 let prover4 = TestProver {
1219 secrets: vec![sk4.into()],
1220 };
1221 let prover5 = TestProver {
1222 secrets: vec![sk5.into()],
1223 };
1224 let prover6 = TestProver {
1225 secrets: vec![sk6.into()],
1226 };
1227 let prover7 = TestProver {
1228 secrets: vec![sk7.into()],
1229 };
1230 let bound = Expr::Const(7i32.into());
1241 let input = Constant {
1242 tpe: SType::SColl(SType::SSigmaProp.into()),
1243 v: Literal::Coll(
1244 CollKind::from_collection(
1245 SType::SSigmaProp,
1246 [
1247 SigmaProp::from(pk1.clone()).into(),
1248 SigmaProp::from(pk2.clone()).into(),
1249 SigmaProp::from(pk3.clone()).into(),
1250 SigmaProp::from(pk4.clone()).into(),
1251 SigmaProp::from(pk5.clone()).into(),
1252 SigmaProp::from(pk6.clone()).into(),
1253 SigmaProp::from(pk7.clone()).into(),
1254 SigmaProp::from(pk8.clone()).into(),
1255 SigmaProp::from(pk9.clone()).into(),
1256 SigmaProp::from(pk10.clone()).into(),
1257 ],
1258 )
1259 .unwrap(),
1260 ),
1261 }
1262 .into();
1263 let expr: Expr = Atleast::new(bound, input).unwrap().into();
1264 let tree_expr = ErgoTree::try_from(expr.clone()).unwrap();
1265 let expr_reduced = reduce_to_crypto(&expr, &ctx).unwrap().sigma_prop;
1266 let message = vec![0u8; 100];
1267
1268 let hints_1 = generate_commitments_for(&expr_reduced, &[pk1.clone().into()]);
1271 let dl_1_known = hints_1.real_commitments().first().unwrap().clone();
1272 let secret_cmt_1 = hints_1.own_commitments().first().unwrap().clone();
1273
1274 let hints_2 = generate_commitments_for(&expr_reduced, &[pk2.clone().into()]);
1275 let dl_2_known = hints_2.real_commitments().first().unwrap().clone();
1276 let secret_cmt_2 = hints_2.own_commitments().first().unwrap().clone();
1277
1278 let hints_3 = generate_commitments_for(&expr_reduced, &[pk3.clone().into()]);
1279 let dl_3_known = hints_3.real_commitments().first().unwrap().clone();
1280 let secret_cmt_3 = hints_3.own_commitments().first().unwrap().clone();
1281
1282 let hints_4 = generate_commitments_for(&expr_reduced, &[pk4.clone().into()]);
1283 let dl_4_known = hints_4.real_commitments().first().unwrap().clone();
1284 let secret_cmt_4 = hints_4.own_commitments().first().unwrap().clone();
1285
1286 let hints_5 = generate_commitments_for(&expr_reduced, &[pk5.clone().into()]);
1287 let dl_5_known = hints_5.real_commitments().first().unwrap().clone();
1288 let secret_cmt_5 = hints_5.own_commitments().first().unwrap().clone();
1289
1290 let hints_6 = generate_commitments_for(&expr_reduced, &[pk6.clone().into()]);
1291 let dl_6_known = hints_6.real_commitments().first().unwrap().clone();
1292 let secret_cmt_6 = hints_6.own_commitments().first().unwrap().clone();
1293
1294 let hints_7 = generate_commitments_for(&expr_reduced, &[pk7.clone().into()]);
1295 let secret_cmt_7 = hints_7.own_commitments().first().unwrap().clone();
1296
1297 let bag_7 = HintsBag {
1298 hints: vec![
1299 dl_1_known.clone().into(),
1300 dl_2_known.clone().into(),
1301 dl_3_known.clone().into(),
1302 dl_4_known.clone().into(),
1303 dl_5_known.clone().into(),
1304 dl_6_known.clone().into(),
1305 secret_cmt_7.clone().into(),
1306 ],
1307 };
1308
1309 let proof_7 = prover7.prove(&tree_expr, &ctx, &message, &bag_7).unwrap();
1310
1311 let verifier = TestVerifier;
1312
1313 assert!(
1314 !verifier
1315 .verify(&tree_expr, &ctx, proof_7.proof.clone(), message.as_slice(),)
1316 .unwrap()
1317 .result,
1318 "Proof generated by Prover7 only is not correct"
1319 );
1320
1321 let bag_one = bag_for_multi_sig(
1323 &expr_reduced,
1324 &[pk7.into()],
1325 &[pk8.into(), pk9.into(), pk10.into()],
1326 proof_7.proof.as_ref(),
1327 )
1328 .unwrap();
1329
1330 let mut bag_2 = bag_one.clone();
1332 bag_2.add_hint(secret_cmt_2.clone().into());
1333 bag_2.add_hint(dl_1_known.clone().into());
1334 bag_2.add_hint(dl_3_known.clone().into());
1335 bag_2.add_hint(dl_4_known.clone().into());
1336 bag_2.add_hint(dl_5_known.clone().into());
1337 bag_2.add_hint(dl_6_known.clone().into());
1338 let proof_2 = prover2.prove(&tree_expr, &ctx, &message, &bag_2).unwrap();
1339 let partial_proof_2 =
1340 bag_for_multi_sig(&expr_reduced, &[pk2.into()], &[], proof_2.proof.as_ref())
1341 .unwrap()
1342 .real_proofs()
1343 .first()
1344 .unwrap()
1345 .clone();
1346
1347 let mut bag_1 = bag_one.clone();
1348 bag_1.add_hint(secret_cmt_1.clone().into());
1349 bag_1.add_hint(dl_2_known.clone().into());
1350 bag_1.add_hint(dl_3_known.clone().into());
1351 bag_1.add_hint(dl_4_known.clone().into());
1352 bag_1.add_hint(dl_5_known.clone().into());
1353 bag_1.add_hint(dl_6_known.clone().into());
1354
1355 let proof_1 = prover1.prove(&tree_expr, &ctx, &message, &bag_1).unwrap();
1356 let partial_proof_1 =
1357 bag_for_multi_sig(&expr_reduced, &[pk1.into()], &[], proof_1.proof.as_ref())
1358 .unwrap()
1359 .real_proofs()
1360 .first()
1361 .unwrap()
1362 .clone();
1363
1364 let mut bag_3 = bag_one.clone();
1365 bag_3.add_hint(secret_cmt_3.clone().into());
1366 bag_3.add_hint(dl_1_known.clone().into());
1367 bag_3.add_hint(dl_2_known.clone().into());
1368 bag_3.add_hint(dl_4_known.clone().into());
1369 bag_3.add_hint(dl_5_known.clone().into());
1370 bag_3.add_hint(dl_6_known.clone().into());
1371 let proof_3 = prover3.prove(&tree_expr, &ctx, &message, &bag_3).unwrap();
1372 let partial_proof_3 =
1373 bag_for_multi_sig(&expr_reduced, &[pk3.into()], &[], proof_3.proof.as_ref())
1374 .unwrap()
1375 .real_proofs()
1376 .first()
1377 .unwrap()
1378 .clone();
1379
1380 let mut bag_4 = bag_one.clone();
1381 bag_4.add_hint(secret_cmt_4.clone().into());
1382 bag_4.add_hint(dl_1_known.clone().into());
1383 bag_4.add_hint(dl_2_known.clone().into());
1384 bag_4.add_hint(dl_3_known.clone().into());
1385 bag_4.add_hint(dl_5_known.clone().into());
1386 bag_4.add_hint(dl_6_known.clone().into());
1387 let proof_4 = prover4.prove(&tree_expr, &ctx, &message, &bag_4).unwrap();
1388 let partial_proof_4 =
1389 bag_for_multi_sig(&expr_reduced, &[pk4.into()], &[], proof_4.proof.as_ref())
1390 .unwrap()
1391 .real_proofs()
1392 .first()
1393 .unwrap()
1394 .clone();
1395
1396 let mut bag_5 = bag_one.clone();
1397 bag_5.add_hint(secret_cmt_5.clone().into());
1398 bag_5.add_hint(dl_1_known.clone().into());
1399 bag_5.add_hint(dl_2_known.clone().into());
1400 bag_5.add_hint(dl_3_known.clone().into());
1401 bag_5.add_hint(dl_4_known.clone().into());
1402 bag_5.add_hint(dl_6_known.clone().into());
1403 let proof_5 = prover5.prove(&tree_expr, &ctx, &message, &bag_5).unwrap();
1404 let partial_proof_5 =
1405 bag_for_multi_sig(&expr_reduced, &[pk5.into()], &[], proof_5.proof.as_ref())
1406 .unwrap()
1407 .real_proofs()
1408 .first()
1409 .unwrap()
1410 .clone();
1411
1412 let mut bag_6 = bag_one.clone();
1413 bag_6.add_hint(secret_cmt_6.clone().into());
1414 bag_6.add_hint(dl_1_known.clone().into());
1415 bag_6.add_hint(dl_2_known.clone().into());
1416 bag_6.add_hint(dl_3_known.clone().into());
1417 bag_6.add_hint(dl_4_known.clone().into());
1418 bag_6.add_hint(dl_5_known.clone().into());
1419 let proof_6 = prover6.prove(&tree_expr, &ctx, &message, &bag_6).unwrap();
1420 let partial_proof_6 =
1421 bag_for_multi_sig(&expr_reduced, &[pk6.into()], &[], proof_6.proof.as_ref())
1422 .unwrap()
1423 .real_proofs()
1424 .first()
1425 .unwrap()
1426 .clone();
1427
1428 let mut bag = bag_one;
1429 bag.add_hint(partial_proof_1.into());
1430 bag.add_hint(partial_proof_2.into());
1431 bag.add_hint(partial_proof_3.into());
1432 bag.add_hint(partial_proof_4.into());
1433 bag.add_hint(partial_proof_5.into());
1434 bag.add_hint(partial_proof_6.into());
1435 bag.add_hint(dl_1_known.into());
1436 bag.add_hint(dl_2_known.into());
1437 bag.add_hint(dl_3_known.into());
1438 bag.add_hint(dl_4_known.into());
1439 bag.add_hint(dl_5_known.into());
1440 bag.add_hint(dl_6_known.into());
1441
1442 let mut valid_bag_1 = bag.clone();
1443 valid_bag_1.add_hint(secret_cmt_1.into());
1444 let valid_proof_1 = prover1
1445 .prove(&tree_expr, &ctx, &message, &valid_bag_1)
1446 .unwrap();
1447
1448 assert!(
1449 verifier
1450 .verify(
1451 &tree_expr,
1452 &ctx,
1453 valid_proof_1.proof.clone(),
1454 message.as_slice(),
1455 )
1456 .unwrap()
1457 .result,
1458 );
1459
1460 let mut valid_bag_2 = bag.clone();
1461 valid_bag_2.add_hint(secret_cmt_2.into());
1462 let valid_proof_2 = prover2
1463 .prove(&tree_expr, &ctx, &message, &valid_bag_2)
1464 .unwrap();
1465 assert!(
1466 verifier
1467 .verify(
1468 &tree_expr,
1469 &ctx,
1470 valid_proof_2.proof.clone(),
1471 message.as_slice(),
1472 )
1473 .unwrap()
1474 .result,
1475 );
1476
1477 let mut valid_bag_3 = bag.clone();
1478 valid_bag_3.add_hint(secret_cmt_3.into());
1479 let valid_proof_3 = prover3
1480 .prove(&tree_expr, &ctx, &message, &valid_bag_3)
1481 .unwrap();
1482 assert!(
1483 verifier
1484 .verify(
1485 &tree_expr,
1486 &ctx,
1487 valid_proof_3.proof.clone(),
1488 message.as_slice()
1489 )
1490 .unwrap()
1491 .result
1492 );
1493
1494 let mut valid_bag_4 = bag.clone();
1495 valid_bag_4.add_hint(secret_cmt_4.into());
1496 let valid_proof_4 = prover4
1497 .prove(&tree_expr, &ctx, &message, &valid_bag_4)
1498 .unwrap();
1499 assert!(
1500 verifier
1501 .verify(
1502 &tree_expr,
1503 &ctx,
1504 valid_proof_4.proof.clone(),
1505 message.as_slice()
1506 )
1507 .unwrap()
1508 .result
1509 );
1510
1511 let mut valid_bag_5 = bag.clone();
1512 valid_bag_5.add_hint(secret_cmt_5.into());
1513 let valid_proof_5 = prover5
1514 .prove(&tree_expr, &ctx, &message, &valid_bag_5)
1515 .unwrap();
1516 assert!(
1517 verifier
1518 .verify(
1519 &tree_expr,
1520 &ctx,
1521 valid_proof_5.proof.clone(),
1522 message.as_slice()
1523 )
1524 .unwrap()
1525 .result
1526 );
1527
1528 let mut valid_bag_6 = bag.clone();
1529 valid_bag_6.add_hint(secret_cmt_6.into());
1530 let valid_proof_6 = prover6
1531 .prove(&tree_expr, &ctx, &message, &valid_bag_6)
1532 .unwrap();
1533 assert!(
1534 verifier
1535 .verify(
1536 &tree_expr,
1537 &ctx,
1538 valid_proof_6.proof.clone(),
1539 message.as_slice()
1540 )
1541 .unwrap()
1542 .result
1543 );
1544
1545 let mut valid_bag_7 = bag.clone();
1546 valid_bag_7.add_hint(secret_cmt_7.into());
1547 let valid_proof_7 = prover7
1548 .prove(&tree_expr, &ctx, &message, &valid_bag_7)
1549 .unwrap();
1550 assert!(
1551 verifier
1552 .verify(
1553 &tree_expr,
1554 &ctx,
1555 valid_proof_7.proof.clone(),
1556 message.as_slice()
1557 )
1558 .unwrap()
1559 .result
1560 );
1561
1562 assert_eq!(valid_proof_1.proof, valid_proof_2.proof);
1563 assert_eq!(valid_proof_2.proof, valid_proof_3.proof);
1564 assert_eq!(valid_proof_3.proof, valid_proof_4.proof);
1565 assert_eq!(valid_proof_4.proof, valid_proof_5.proof);
1566 assert_eq!(valid_proof_5.proof, valid_proof_6.proof);
1567 assert_eq!(valid_proof_6.proof, valid_proof_7.proof);
1568 }
1569}