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

Blinding of asset issuance transaction #254

Open
Sosthene00 opened this issue Dec 9, 2020 · 4 comments
Open

Blinding of asset issuance transaction #254

Sosthene00 opened this issue Dec 9, 2020 · 4 comments

Comments

@Sosthene00
Copy link

There's something I don't understand about the workflow to blind an asset issuance. tx_elements_input_init takes issuance_amount and issuance_amount_rangeproof as arguments, but how do we compute those data?

If I understand correctly, issuance_amount should be the value commitment to the amount of issued assets, and issuance_amount_rangeproof is the corresponding rangeproof.

At first I just took the value commitment and rangeproof for the newly issued asset output and put it also in the input, it didn't work and now I think I understand why, but now how should I create the right value commitment and rangeproof for the input ?

To compute a value commitment, I need the amount issued (so far so good), a value blinding factor (vbf) and a generator (I need an asset blinding factor for this one).

In a normal input, I'll take the vbf and abf from the previous transaction, but since an issuance doesn't spend a previous output, does it mean I can just take random 32 bytes for those ?

Then to compute the rangeproof, I'll need a blinding pubkey that again I'm supposed to take from the prevout, so can I just compute an ephemeral key pair and take the pubkey ?

Here's the relevant part of my code so far (I edited some parts since it's a bit long, maybe there are some inconsistencies because of that), I can produce a transaction that I can sign but I'll get a 16: bad-txns-in-ne-out error in elements with testmempoolaccept, and I guess that's because my value commitments is broken but I can't see how to correct it.

@apoelstra
Copy link
Member

You should never be copying blinding factors like you're describing. They should be generated uniformly randomly, except that one has to be chosen to cancel all the others out -- which looks like what your code is doing, except for the final cancellation step.

@Sosthene00
Copy link
Author

Sosthene00 commented Dec 10, 2020

Hi, thanks for answering me so fast, and sorry if my code is a bit confused it's just a draft.

If I didn't get you wrong, you're talking about this part (l.90-93):

# abfs and vbfs are lists of asset/value bf that I've got from previous transaction outputs I'm spending
for abf in abfs:
        abfs_in += bytes(abf)
for vbf in vbfs:
        vbfs_in += bytes(vbf)

Then I generate random abf and vbf for the outputs of the transaction I'm creating:

abfs_out = urandom(32 * num_outputs)
vbfs_out = urandom(32 * (num_outputs - 1))

And at last the final vbf:

vbfs_out += wally.asset_final_vbf(
        clear_values + output_values, # which is just inputs and outputs clear values
        num_inputs, # should I count the input issuance as an input ?
        abfs_in + abfs_out,
        vbfs_in + vbfs_out)

This part I tried to copy and adapt the workflow described here, l. 54-113. My understanding is that we first get the abfs and vbfs from the previous outputs we're spending and then generate randomly new ones for the outputs we'll create, which is what we pass as arguments to asset_final_vbf to compute the final vbf that cancels out all the others.

There are a lot of questions about how to handle asset issuance, since they're not "real" inputs and don't point to existing UTXOs. That's what confusing me a bit now I think.

@apoelstra
Copy link
Member

Oh! I misunderstood what you meant by copying blinding factors. Indeed, the blinding factors on the inputs have to match the commitments, which are defined by the outputs that they reference, so you have to look this up and copy the value into place.

For the purposes of balancing commitments, you can think of issued assets as "real" inputs, in that they appear on the negative side of the verification equation. But unlike real inputs, you should generate the blinding factors for issuance inputs randomly, just like you do with outputs.

@Sosthene00
Copy link
Author

Sosthene00 commented Feb 15, 2021

Hi, I've resumed work on this topic and I think I understand better what's going on, but I might still be misunderstanding something about asset issuance.

I managed to create blinded (but not signed yet) transaction with libwally, but it seems they are incorrect though, as Elements' testmempoolaccept returns "16: bad-txns-in-ne-out", where I'd rather expect whatever error there's for an unsigned transaction. I guess it means there's something wrong with my commitments, but I can't see exactly what.

I think I might be uncorrectly generating the issuance rangeproof, as this part is still a bit obscure to me, and I'm trying to lay here what I understood so far so that I can be corrected if I misunderstood something.

Iiuc, when blinding a "normal" output, the sender:

  • generates an ephemeral keypair
  • ECDH the ephemeral private key and the public key provided by the recipient in the confidential address to generate a nonce
  • uses the nonce to generate the rangeproof
  • puts the ephemeral public key in the output so that the recipient can retrieve it, perform ECDH with his own private blinding key, find the nonce and unblind the output

It seems this can't work the same in the case of an initial issuance. I've read Elements' code to try to figure out what to do (for example here and there) and here's what I'm doing in Libwally wrt the issuance of a new asset:

  • Compute a new asset ID
  • Generate random blinding factors
  • use the asset ID and asset blinding factor to compute the generator (rougly like this wally_asset_generator_from_bytes(new_asset_id, asset_blinding_factor, generator_out))
  • use the generator I just got with the clear value and value blinding factor to create a value commitment wally_asset_value_commitment(clear_value, value_blinding_factor, generator, commitment_out)

I've seen in Elements that we generate a private blinding key for issuance with an OP_RETURN script with prevout of the input the issuance is hooked to and our master blinding key, and then we use this key as a nonce for the rangeproof. The nonce of a first issuance is empty, since we'll use the private blinding key directly as a nonce for unblinding.

Here's the step in Libwally:

  • create a message with the concatenation of the previous txid and the vout
  • use wally_scriptpubkey_op_return_from_bytes to create a script with this message
  • wally_asset_blinding_key_to_ec_private_key to get the blinding private key from script
  • wally_asset_rangeproof_with_nonce, the nonce being the key I obtained at the previous step, to generate the issuance rangeproof
  • wally_tx_add_elements_raw_input with NULL as a nonce

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

No branches or pull requests

2 participants