| 653 | } |
| 654 | |
| 655 | std::optional<CPubKey> GetPubKey(int pos, const SigningProvider& arg, FlatSigningProvider& out, const DescriptorCache* read_cache = nullptr, DescriptorCache* write_cache = nullptr) const override |
| 656 | { |
| 657 | FlatSigningProvider dummy; |
| 658 | // If the participants are not ranged, we can compute and cache the aggregate pubkey by creating a PubkeyProvider for it |
| 659 | if (!m_aggregate_provider && !m_ranged_participants) { |
| 660 | // Retrieve the pubkeys from the providers |
| 661 | std::vector<CPubKey> pubkeys; |
| 662 | for (const auto& prov : m_participants) { |
| 663 | std::optional<CPubKey> pubkey = prov->GetPubKey(0, arg, dummy, read_cache, write_cache); |
| 664 | if (!pubkey.has_value()) { |
| 665 | return std::nullopt; |
| 666 | } |
| 667 | pubkeys.push_back(pubkey.value()); |
| 668 | } |
| 669 | std::sort(pubkeys.begin(), pubkeys.end()); |
| 670 | |
| 671 | // Aggregate the pubkey |
| 672 | m_aggregate_pubkey = MuSig2AggregatePubkeys(pubkeys); |
| 673 | if (!Assume(m_aggregate_pubkey.has_value())) return std::nullopt; |
| 674 | |
| 675 | // Make our pubkey provider |
| 676 | if (IsRangedDerivation() || !m_path.empty()) { |
| 677 | // Make the synthetic xpub and construct the BIP32PubkeyProvider |
| 678 | CExtPubKey extpub = CreateMuSig2SyntheticXpub(m_aggregate_pubkey.value()); |
| 679 | m_aggregate_provider = std::make_unique<BIP32PubkeyProvider>(m_expr_index, extpub, m_path, m_derive, /*apostrophe=*/false); |
| 680 | } else { |
| 681 | m_aggregate_provider = std::make_unique<ConstPubkeyProvider>(m_expr_index, m_aggregate_pubkey.value(), /*xonly=*/false); |
| 682 | } |
| 683 | } |
| 684 | |
| 685 | // Retrieve all participant pubkeys |
| 686 | std::vector<CPubKey> pubkeys; |
| 687 | for (const auto& prov : m_participants) { |
| 688 | std::optional<CPubKey> pub = prov->GetPubKey(pos, arg, out, read_cache, write_cache); |
| 689 | if (!pub) return std::nullopt; |
| 690 | pubkeys.emplace_back(*pub); |
| 691 | } |
| 692 | std::sort(pubkeys.begin(), pubkeys.end()); |
| 693 | |
| 694 | CPubKey pubout; |
| 695 | if (m_aggregate_provider) { |
| 696 | // When we have a cached aggregate key, we are either returning it or deriving from it |
| 697 | // Either way, we can passthrough to its GetPubKey |
| 698 | // Use a dummy signing provider as private keys do not exist for the aggregate pubkey |
| 699 | std::optional<CPubKey> pub = m_aggregate_provider->GetPubKey(pos, dummy, out, read_cache, write_cache); |
| 700 | if (!pub) return std::nullopt; |
| 701 | pubout = *pub; |
| 702 | out.aggregate_pubkeys.emplace(m_aggregate_pubkey.value(), pubkeys); |
| 703 | } else { |
| 704 | if (!Assume(m_ranged_participants) || !Assume(m_path.empty())) return std::nullopt; |
| 705 | // Compute aggregate key from derived participants |
| 706 | std::optional<CPubKey> aggregate_pubkey = MuSig2AggregatePubkeys(pubkeys); |
| 707 | if (!aggregate_pubkey) return std::nullopt; |
| 708 | pubout = *aggregate_pubkey; |
| 709 | |
| 710 | std::unique_ptr<ConstPubkeyProvider> this_agg_provider = std::make_unique<ConstPubkeyProvider>(m_expr_index, aggregate_pubkey.value(), /*xonly=*/false); |
| 711 | this_agg_provider->GetPubKey(0, dummy, out, read_cache, write_cache); |
| 712 | out.aggregate_pubkeys.emplace(pubout, pubkeys); |
nothing calls this directly
no test coverage detected