5

This question by kenshi84 shows how the pseudoOuts and outPk fields can be validated by anyone (without knowing any of the private keys involved), by checking that sumIn === sumOut:

> var H = ge_scalarmult(cn_fast_hash(ge_scalarmult_base("0100000000000000000000000000000000000000000000000000000000000000")), "0800000000000000000000000000000000000000000000000000000000000000");
undefined
> H
"8b655970153799af2aeadc9ff1add0ea6c7251d54154cfa92c173a0dd39c1f94"
> var fee = swapEndian(d2h256("30000000000"));
undefined
> fee
"00AC23FC06000000000000000000000000000000000000000000000000000000"
> var feeH = ge_scalarmult(H, fee);
undefined
> feeH
"527e4c0b6e34f948fb59ab014ec8eedf9eccfda4930a0b30d12790a0ec0d91f2"
> var pseudoOuts = ["276f03ba8c7852cb545830f7fedcdcd08789675d2a6c265bea236d0de90f6b11", "c611cc551db3b05ad6e5dba4ce89a8eeeb18317d8b565031941e98b6b9b8db4f", "8a088f1ccd11dd1633a663538faa9cb18c157b4fd37c421697a6356b4d7a98f6", "9e1238add1c1a4712904e5d5d8913482dcd6d31af166bc73918fd8148a42f22b"];
undefined
> var outPk = [ "f9cabc6b0fd32822feb3e13c70b54b2cdc2a3ce7c88ac661c29ab20732e2974f", "cfb010382648e11d7d5744fe8051c8606f31c901f9ede5b7e392f73790f9e7f8"]
undefined
> var sumIn = ge_add(ge_add(ge_add(pseudoOuts[0], pseudoOuts[1]), pseudoOuts[2]), pseudoOuts[3]);
undefined
> var sumOut = ge_add(ge_add(outPk[0], outPk[1]), feeH);
undefined
> sumIn
"a340fb56b64d831d4f06079f1fc4d507a7a2d1b0107ea7814c626c7394190da6"
> sumOut
"a340fb56b64d831d4f06079f1fc4d507a7a2d1b0107ea7814c626c7394190da6"

It's nice to have working javascript code (you can try by opening a browser console here), and I wonder if my question can be answered in a similar way.

I've noticed that the ecdhInfo field wasn't used in the above javascript code. Is there a way to validate ecdhInfo too, without knowing any private keys? Or is this not necessary?

For reference, here's rct_signatures from kenshi84's question again:

{
    "type": 2, 
    "txnFee": 30000000000, 
    "pseudoOuts":["276f03ba8c7852cb545830f7fedcdcd08789675d2a6c265bea236d0de90f6b11", "c611cc551db3b05ad6e5dba4ce89a8eeeb18317d8b565031941e98b6b9b8db4f", "8a088f1ccd11dd1633a663538faa9cb18c157b4fd37c421697a6356b4d7a98f6", "9e1238add1c1a4712904e5d5d8913482dcd6d31af166bc73918fd8148a42f22b"], 
    "ecdhInfo": [ {
        "mask": "c626b75f726e88a26fc74c1bb508fa9358c0896a7635d0f1256c7f43f0217706", 
        "amount": "63c1d97047ff515ccd5ca271f4e5013b9c1092c25307207a0ff037b13f492c00"
      }, {
        "mask": "73b4367f9b143c0a453598f85761698c4548e890fa52a05b4e28183126525008", 
        "amount": "81b48b46e79b458a234ad36d3d0890f89e30d50cc18a687dd94fd0ef3417da0f"
      }], 
    "outPk": [ "f9cabc6b0fd32822feb3e13c70b54b2cdc2a3ce7c88ac661c29ab20732e2974f", "cfb010382648e11d7d5744fe8051c8606f31c901f9ede5b7e392f73790f9e7f8"]
 }
  • Assuming these fields are symmetrically encrypted, it would seem plausible that only the recipient can validate them. How would the recipient then check that mask and amount are correct? – Lustiger Astronaut Mar 3 '18 at 20:13
  • This code seems relevant. – Lustiger Astronaut Mar 3 '18 at 22:28
3

Both the ecdhInfo mask and amount are encrypted by the sender of the transaction.

Both are encrypted (each in a slightly different way) using the transaction's shared secret (aR).

Therefore both encrypted values will be randomly distributed, and thus cannot be validated by a third party.

If the sender of the transaction had somehow written faulty values into the transaction, the only consequence would be that the outputs created by the transaction would be unspendable.

The code that encrypts and decrypts the ecdhInfo values is here: https://github.com/monero-project/monero/blob/2b00899bb28e09f0c44813689acc0add73832215/src/ringct/rctOps.cpp#L447

  • Just to be sure... so ecdhInfo and outPk must have the same length, and for all i, 0 <= i < outPk.length, the receiver would check that ge_add(ge_scalarmult_base(ecdhDecode(ecdhInfo[i].mask, aR)), ge_scalarmult(ecdhDecode(ecdhInfo[i].amount, aR), H)) equals outPk[i]? – Lustiger Astronaut Mar 4 '18 at 5:21
  • Yes, to both. Technically your code wouldn't compile, but you've clearly understood the principle that the ecdhInfo is there to communicate the components of the output Pedersen commitments to the recipient, so that the recipient is then able to properly construct a RingCT proof that references those outputs as inputs in a subsequent transaction. – knaccc Mar 4 '18 at 5:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.