| 106 | } |
| 107 | |
| 108 | bool UnblindConfidentialPair(const CKey& blinding_key, const CConfidentialValue& conf_value, const CConfidentialAsset& conf_asset, const CConfidentialNonce& nonce_commitment, const CScript& committedScript, const std::vector<unsigned char>& vchRangeproof, CAmount& amount_out, uint256& blinding_factor_out, CAsset& asset_out, uint256& asset_blinding_factor_out) |
| 109 | { |
| 110 | if (!blinding_key.IsValid() || vchRangeproof.size() == 0) { |
| 111 | return false; |
| 112 | } |
| 113 | CPubKey ephemeral_key(nonce_commitment.vchCommitment); |
| 114 | if (nonce_commitment.vchCommitment.size() > 0 && !ephemeral_key.IsFullyValid()) { |
| 115 | return false; |
| 116 | } |
| 117 | |
| 118 | // ECDH or not depending on if nonce commitment is non-empty |
| 119 | uint256 nonce; |
| 120 | bool blank_nonce = false; |
| 121 | if (nonce_commitment.vchCommitment.size() > 0) { |
| 122 | nonce = blinding_key.ECDH(ephemeral_key); |
| 123 | CSHA256().Write(nonce.begin(), 32).Finalize(nonce.begin()); |
| 124 | } else { |
| 125 | // Use blinding key directly, and don't commit to a scriptpubkey |
| 126 | // This is used for issuance inputs. |
| 127 | blank_nonce = true; |
| 128 | nonce = uint256(std::vector<unsigned char>(blinding_key.begin(), blinding_key.end())); |
| 129 | } |
| 130 | |
| 131 | unsigned char msg[SIDECHANNEL_MSG_SIZE] = {0}; |
| 132 | size_t msg_size = SIDECHANNEL_MSG_SIZE; |
| 133 | |
| 134 | // If value is unblinded, we don't support unblinding just the asset |
| 135 | if (!conf_value.IsCommitment()) { |
| 136 | return false; |
| 137 | } |
| 138 | |
| 139 | // Valid asset commitment? |
| 140 | secp256k1_generator observed_gen; |
| 141 | if (conf_asset.IsCommitment()) { |
| 142 | if (secp256k1_generator_parse(secp256k1_blind_context, &observed_gen, &conf_asset.vchCommitment[0]) != 1) |
| 143 | return false; |
| 144 | } else if (conf_asset.IsExplicit()) { |
| 145 | if (secp256k1_generator_generate(secp256k1_blind_context, &observed_gen, conf_asset.GetAsset().begin()) != 1) |
| 146 | return false; |
| 147 | } |
| 148 | |
| 149 | // Valid value commitment? |
| 150 | secp256k1_pedersen_commitment value_commit; |
| 151 | if (secp256k1_pedersen_commitment_parse(secp256k1_blind_context, &value_commit, conf_value.vchCommitment.data()) != 1) { |
| 152 | return false; |
| 153 | } |
| 154 | |
| 155 | // Rewind rangeproof |
| 156 | uint64_t min_value, max_value, amount; |
| 157 | if (!secp256k1_rangeproof_rewind(secp256k1_blind_context, blinding_factor_out.begin(), &amount, msg, &msg_size, nonce.begin(), &min_value, &max_value, &value_commit, &vchRangeproof[0], vchRangeproof.size(), (committedScript.size() && !blank_nonce)? &committedScript.front(): NULL, blank_nonce ? 0 : committedScript.size(), &observed_gen)) { |
| 158 | return false; |
| 159 | } |
| 160 | |
| 161 | // Convenience pointers to starting point of each recovered 32 byte message |
| 162 | unsigned char *asset_type = msg; |
| 163 | unsigned char *asset_blinder = msg+32; |
| 164 | |
| 165 | // Asset sidechannel of asset type + asset blinder |