Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redesign PSET #900

Merged
merged 91 commits into from
Jul 6, 2021
Merged

Redesign PSET #900

merged 91 commits into from
Jul 6, 2021

Conversation

achow101
Copy link
Contributor

The original PSET had some issues with leaking private information and there were issues with the design of the various roles. This PR replaces it with a new PSET design that should be able to provide all of the things that people expect PSETs to do while preserving privacy.

Additionally, an actual specification for this new design has been written up. It describes all of the new fields, their serialization, and how roles should handle the PSET data.

This is still a work in progress as not everything with the blinder role has been worked out yet.

** Key: A 32 Scalar Offset computed by a blinder.
*** <tt>{0x00}|{offset}</tt>
** Value: None. The value must have a length of zero.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Should be PSET_GLOBAL_SCALAR
  • 32 byte
  • The scalar value should be stored in the value (not the key) since that makes the key unique and prevents duplicates even in general PSBT utilities that pass this field through. It also then matches every other Elements type in the doc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There can be multiple scalars. Putting it in the value then requires a unique key per scalar.

The original suggestion was to attach a scalar to an output, however they aren't really related to a particular output, so I opted to go with a global field.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah. This wasn't clear from the docs. given multiple scalars in a psbt, how do i know in which context to use one versus another? It seems like more data than just the scalar value will be needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The scalars are only used by the last blinder and they are used all together at that time. They're just used in the last blinding step to make sure that everything balances.

@@ -21,6 +20,9 @@ signatures for an input while the input does not have a complete set of signatur
The signer can be offline as all necessary information will be provided in the
transaction.

This is a modification of BIP 174 for the Elements sidechain. It includes changes necessary
for Confidential Transactions, Confidential Assets, and Peg-in transactions.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please consider making this doc a diff/addendum to the BIP rather than repeating the PSBT fields etc. Its hard to read, easy to miss the Elements specific stuff and it will only get out of date w.r.t. BIP 174 as its updated.

If you cant do this at least highlight the Elements changes in the markup somehow.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit 0b3b9ed is just the PSET changes.

Copy link
Contributor

@dgpv dgpv Sep 7, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The people who will be implementing support for PSET in their code have to use the full document, they cannot use commit as the reference. I concur with @jgriffiths that the doc should be an addendum rather than edit. I think that the described problems (need to read diff PSET/PSBT instead of the document, need to sync with PSBT as it is updated) are significant. It is the additions to the standard that are proprietary, not the standard itself. Therefore only the additions should be described in the spec.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

*proprietary in a sense that they use the PSBT_PROPRIETARY type designed for proprietary extensions, not that the changes are somehow not open.

doc/pset.mediawiki Outdated Show resolved Hide resolved
The amount is added to the PSET input as <tt>PSET_IN_ISSUANCE_VALUE</tt>.

The Creator decides whether and which inputs are Peg-in inputs.
Peg-in inputs must have the Peg-in flag set in their outpoints.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issuance and pegin are mutually exclusive, no? if so this should be documented above with their input fields.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am under the impression that they are not mutually exclusive. I don't really see why they would be.

doc/pset.mediawiki Outdated Show resolved Hide resolved
The blinder will then subtract the sum of their inputs' blinding factors from the sum of their output's blinding factors.
The result must be added as a <tt>PSET_GLOBAL_SCALAR</tt> field.

For the Blinder who blinds the last output to be blinded, it will subtract all of the scalar offsets from the value blinding factor for the last output.

This comment was marked as outdated.


For the Blinder who blinds the last output to be blinded, it will subtract all of the scalar offsets from the value blinding factor for the last output.
The result will be the amount blinding factor for that last output. The creation of the asset commitment, proofs, and other fields proceeds as usual.
Once all outputs are blinded, all <tt>PSET_GLOBAL_SCALAR</tt> fields must be removed from the PSET.

This comment was marked as outdated.

doc/pset.mediawiki Outdated Show resolved Hide resolved
doc/pset.mediawiki Outdated Show resolved Hide resolved
doc/pset.mediawiki Outdated Show resolved Hide resolved
src/psbt.cpp Outdated
if (!input.IsSane()) return false;
// Check issuance is empty in CTxOut but set in input
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is confusing. The "Check issuance is empty in CTxOut" happens later, but it is referred to as it it happens just here. I think better wording would be along the lines of "Check that issuance is empty in the input, because later we check that issuance is empty in CTxOut"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reworded

src/psbt.cpp Outdated
if (!tx->vin[i].assetIssuance.nAmount.IsNull()) return false;
if (!input.issuance_value && input.issuance_value_commitment.IsNull()) return false;
}
// Check whether any input is blinded
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment is at the end of the loop. Usually the comment describes the code that is below (or left of) the comment. Does this comment refer to the code that is supposed to be here, but removed ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

src/psbt.cpp Outdated

bool PSBTOutput::IsBlinded() const
{
return blinding_pubkey.IsValid();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nor IsPartiallyBlinded neither IsFullyBlinded check blinding_pubkey.IsValid(). That means that there is a logical contradiction that an output can be 'FullyBlinded', but not 'Blinded'. This can create confusion that can result in mistakes. Maybe better wording can help, like 'Blindable' instead of 'Blinded' ? Or IsPartiallyBlinded/IsFullyBlinded should imply IsBlinded

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Enforced it.

src/psbt.cpp Outdated
@@ -329,6 +402,7 @@ bool FinalizeAndExtractPSBT(PartiallySignedTransaction& psbtx, CMutableTransacti
result.witness.vtxinwit[i].scriptWitness = psbtx.inputs[i].final_script_witness;
PSBTInput& input = psbtx.inputs[i];

/*
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commented-out (and not removed) code without any further comment with justification of not removing it can be confusing and distracting. Is this commented out just temporary ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is just temporary. The comment is to just make the code compile so that the action that this code does can be reimplemented later in this PR.

src/psbt.h Outdated
@@ -174,49 +159,83 @@ struct PSBTInput
SerializeToVector(s, final_script_witness.stack);
}

// Issuance value
// We shouldn't have both the value and value commitment, but maybe we do
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comments should make the code more clear, rather than introduce doubt.

"but maybe we do" is not connected to the action in the code, and should either be dropped, or expanded, "but maybe we do, and in this case we ignore the value"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarified

src/psbt.h Outdated
SerializeToVector(s, asset_commitment);
}
// Asset
// We shouldn't have both asset and asset commitment, but if we do, wrte only the asset commitment
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mistype: "wrte" instead of "write"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

* Type: Value Commitment <tt>PSET_OUT_VALUE_COMMITMENT = 0x01</tt>
** Key: None. The key must only contain the 1 byte type.
*** <tt>{0x01}</tt>
** Value: The 33 byte Value Commitment for this output. Adding this field requires the removal of <tt>PSET_OUT_VALUE</tt>.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding PSET_OUT_VALUE requires remove of commitment, too. I think better say that the fields are mutually exclusive, as said for issuance value/commitment fields. (the same can be said for asset and asset commitment)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

will still need to handle events where keys are duplicated when combining transactions with duplicated fields. In this event, with the exception of duplicate output commitments and proofs, the software may choose
whichever value it wishes.<ref>'''Why can the values be arbitrarily chosen?''' When there are duplicated keys, the values that can be chosen will either be
valid or invalid. If the values are invalid, a signer would simply produce an invalid signature and the final transaction itself would be invalid. If the
values are valid, then it does not matter which is chosen as either way the transaction is still valid.</ref>. For <tt>PSBT_OUT_VALUE_COMMITMENT</tt>, <tt>PSBT_OUT_ASSET_COMMITMENT</tt>, <tt>PSBT_OUT_VALUE_RANGEPROOF</tt>, <tt>PSBT_OUT_ASSET_SURJ_PROOF</tt>, and <tt>PSBT_OUT_ECDH_PUBKEY</tt>, the PSET should be considered invalid if these are duplicated.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think what is meant here is that 'the combined PSET should be considered invalid'. Wouldn't it be more clear to say that PSETs cannot be combined if these fields are present in both instances ?

Also I believe that if values of these fields are equal for the outputs of two PSETs, they can be combined. For example, two PSETs that was modified from one common ancestor could have these fields in outputs that are equal.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tried to clarify and generalize this.

For any output which is going to be blinded, the Creator must add the blinding pubkey in the <tt>PSET_OUT_BLINDING_PUBKEY</tt> field.

If any input is blinded, at least one of the outputs must also be blinded, i.e. it must have a <tt>PSET_OUT_BLINDING_PUBKEY</tt>.
Such an output can be a 0 value OP_RETURN output.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creator can be unaware that Updater will add a blinded input afterwards. Then the updater have to enforce this rule, too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would violate the constraint that the unsigned tx cannot change. Maybe we should assume (or stipulate) that creators know which/whether inputs are blinded?


The Creator decides whether and which inputs are issuance inputs.
For those inputs, the issuance data must be added to the input in the global unsigned transaction, except for the issuance amount.
Such inputs must also have the issuance flag set in the outpoint.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would add "in the outpoint of the prevout". Just "outpoint" can be mistakenly read as "output" and confuse the reader (I myself misread and was confused, like "how an output can be related here at all ?")

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

** Key: None. The key must only contain the 1 byte type.
*** <tt>{0x09}</tt>
** Value: The Peg-in witness for the Peg-in Transaction.
*** <tt>{script}</tt>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be PSET_IN_ASSET_COMMITMENT to supply asset commitment of the prevout, so Creator/Updater can provide blinding information for the inputs when they will not be the Blinder

Copy link
Contributor

@dgpv dgpv Sep 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(this info is supplied in auxiliary_generators argument to BlindTransaction())

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be in the UTXO already.

Once all outputs are blinded, all <tt>PSET_GLOBAL_SCALAR</tt> fields must be removed from the PSET.

A single entity is likely to be a Creator, Updater, and Blinder.
In that case, the PSET should never be output with <tt>PSET_IN_ISSUANCE_VALUE</tt>, <tt>PSET_OUT_VALUE</tt>, or <tt>PSET_OUT_ASSET</tt>.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creator must set output values to 0 and assets to NULL. So for unblinded outputs, PSET_OUT_VALUE and PSET_OUT_ASSET need to remain after blinding. Or there should be a rule that unblinded output values should have their value/asset specified in embedded transaction, and these PSET_* fields used only for blindable outputs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I clarified this to say that unblinded outputs should have these fields.

The resulting PSBT must contain all of the key-value pairs from each of the PSBTs.
The Combiner must remove any duplicate key-value pairs, in accordance with the specification. It can pick arbitrarily when conflicts occur.
For all PSET output fields, the combiner must fail to combine if these fields are not identical.
If the PSETs to be combined have incomplete blinded outputs but the combined result would only complete blinded outputs, then the Combiner must fail unless it is also a Blinder and can reblind its outputs.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wording is unclear. Does it says that if the two outputs that are combined are both incomplete-blinded, but the resulting output will have all the fields to consider it complete, there is a big chance that these fields are incompatible because different randomness was used to produce them ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

** Value: The rangeproof for the value of this output.
*** <tt>{rangeproof}</tt>

* Type: Asset Surjection Proof <tt>PSET_OUT_ASSET_SURJ_PROOF = 0x05</tt>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if RANGEPROOF is spelled without underscore, it would be more consistent to spell SURJPROOF or SURJECTIONPROOF also without underscore. Or use RANGE_PROOF instead.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally prefer PSET_OUT_VALUE_RANGE_PROOF and PSET_OUT_ASSET_SURJECTION_PROOF

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Although in the Elements code they are referred to as rangeproof and surjectionproof, without underscores.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also 'value' and 'asset' prefixes can be implicit in these names

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the various papers on CT and CA, rangeproof as one word is the typical usage while surjection proof is 2 words. So following that convention, it would be RANGEPROOF and SURJECTION_PROOF.

@achow101
Copy link
Contributor Author

I've updated pset.mediawiki to just be PSET and not contain PSBT.

@dgpv
Copy link
Contributor

dgpv commented Sep 16, 2020

I'd like to note that I find PSET prefix confusing if used in implementation (not so much in the specification) that will most likely be based on PSBT. Unless BIP174 is used in prefix for the names rather than PSBT, I would say that it is better to use PSBT_Elements, PSBT_ELTS and the like prefixes for the names, and say that 'PSBT' stands for 'partially-signed bitcoin-like transaction'.

@dgpv
Copy link
Contributor

dgpv commented Sep 16, 2020

Especially when used along with PSBT_-prefixed names, PSET_ will cause frequent pain due to mixups, especially because B and E are so close visually.

@dgpv
Copy link
Contributor

dgpv commented Sep 18, 2020

In the various papers on CT and CA, rangeproof as one word is the typical usage while surjection proof is 2 words. So following that convention, it would be RANGEPROOF and SURJECTION_PROOF.

Implementors are more likely to look into reference code than the papers, and more likely to get the conventions from there. Elements code mainly uses no-underscore convention.

elements$ git grep -i surjectionproof|wc -l
303
elements$ git grep -i surjection_proof|wc -l
38
elements$ git grep -i rangeproof|wc -l
414
elements$ git grep -i range_proof|wc -l
16

walletfillpsbtdata

These are all done by walletprocesspsbt
This test is for a condition that no longer matters. Prior to CA, there
was only the single value blinder for a transaction that sent unconf to
conf. This would necessitate setting that single blinding factor to 0,
which would make the single output not actually blinded. But with CA,
because each output has an additional blinding factor for the asset,
this issue no longer exists.
Helper function for getting a CTxOut for a PSBTOutput
It doesn't work, disable for now.
@apoelstra
Copy link
Member

utack e3a4081

I need an hour or two to build-test all the commits and run some tests on the tip, and we need to merge #1012 to fix CI, then we should be good to go!

@apoelstra
Copy link
Member

ack f8553c5

@apoelstra
Copy link
Member

CI failure due to #1012

@apoelstra apoelstra merged commit 9a15459 into ElementsProject:master Jul 6, 2021
apoelstra added a commit to apoelstra/elements that referenced this pull request Jul 9, 2021
…suances.py

Should describe the outputs as an array rather than as an object. (The old
behavior has long been deprecated but was eliminated entirely in ElementsProject#900.)
stevenroose added a commit that referenced this pull request Jul 12, 2021
…ash_pegins_issuances.py

1c883db test: update `createrawtransaction` call in feature_taphash_pegins_issuances.py (Andrew Poelstra)

Pull request description:

  Should describe the outputs as an array rather than as an object. (The old behavior has long been deprecated but was eliminated entirely in #900.)

  Fixes functional tests which were broken in master by simultaneous merge of #1002 and #900.

ACKs for top commit:
  stevenroose:
    utACK 1c883db

Tree-SHA512: f7963c34e7006a25ac5515e30966ef46777fa22d6125d219345731aef603e5f3179fc316134d59694af8e753f7cb48c825ad3434f2bceda0a10b8d5a52c32cd3
apoelstra added a commit to apoelstra/elements that referenced this pull request Aug 31, 2021
apoelstra added a commit that referenced this pull request Aug 31, 2021
…ew RPC changes

c0936ba test: fix surjectionproof overflow functional test for new RPC changes (Andrew Poelstra)

Pull request description:

  This fixes an undetected merge conflict between #1014 and #900.

ACKs for top commit:
  gwillen:
    utACK c0936ba
  psgreco:
    UTACK c0936ba

Tree-SHA512: a39d98db91d92f7e0e739e06d7a1bb13814d2bc7751cb6105a759af04ed0d61d206d1650f5e4e087feaeafcf1c482587b05b66d9cc497bc594a45df6bf23c07a
gwillen pushed a commit that referenced this pull request Jun 1, 2022
I hacked up rpc_fundrawtransaction.py a little bit because our `get_address`
method here depends on nobody having called `createwallet` on a particular
node ... the "correct" fix for this would be to redo the Elements changes
to this functional test for the 0.20+ createwallet changes, but because
there will be big future changes to this test (in Elements #900 (PSET))
I did the quick/hacky thing, and will defer cleanups to a separate
post-rebase PR.
gwillen pushed a commit that referenced this pull request Jun 1, 2022
Surprisingly easy to do. Almost all of the diff resolution was mechanically
  * replacing boost::variant with std::variant
  * replacing Optional with std::optional
     * then replacing `nullopt` with `std::nullopt`
  * updating the RPC functions for the new RPCArg::Default type
  * update the tests/ directory to make new (since 22) tests use arrays for
    createrawtransaction outputs
  * other ad-hoc changes to function parameters etc (not too many of these)

I had to "really" change the code in PrecomputePSBTData, which was introduced
in 22.0 and affected by PSET, but this function was like 8 lines long so it
was easy.

Reviewing the diff may be a bit difficult because of the mix of mechanical
changes and ad-hoc things. Probably the most straightforward thing to do
is to redo the merge, `sed -i` to fix the boost::variant and Optional stuff,
then diff the remaining conflicts against this commit.

TODO: grep for `blindpsbt` and you will see that this RPC is still referenced
in documentation and help text even though it was deleted. Need to fix this
in 0.21 in a separate PR.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants