2

I am currently implementing the heuristic 1 algorithm from this paper https://eprint.iacr.org/2017/338.pdf for a university project. (pretty interesting btw worth reading :) ).

My problem currently is, I don't fully understand the vin field, which I need for the algorithm.

So what I know:

The vin field contains all input transactions for the whole transaction.

Example would be a vin field containing 3 inputs, this 3 inputs represent the denominations of the full transaction amount.

Each of this 3 inputs has also a key_image field. It is there for double spending reasons. Each key_image exists only once on the blockchain. For simplicity we say key_image = HASH(key_offset), where key_offset is the public key of the real spender in this vin input.

The values in key_offsets are: The public key of the spender + the mixins used. So key_offsets_size = spender_key + N * mixin_key.

I also know that key_offsets are stored differentially, meaning key_offsets = [1,1,1] => real index of inkeys: [1,2,3].

So I am pretty confused how it can be that the same index in key_offsets can be more than once on the blockchain.

For example I querried block X and I had key_offsets = [ 1 ], then I querried block Y (Y > X) and got the same key_offsets.

What am I missing here? Where are "the real" input keys stored and how can I acquire them? Would be awesome if someone could point me on the correct API call.

UPDATE:

For example I queried block 345 and 1247. Got tx 9ecdadf8b95aa0a7b754559f5fd7a9bb0f5014c4107b3dc6b3331430b5ea984d in 345 and ed4717dd86e5b033c36df3b41a3a5296f392e3524651c79792e9b39674c7f1ef in 1247.

When I get all the denominations from 345:

{
  "key": 
  {
    "amount": 458444,
    "k_image": "2c03aa742e881a41588827ea8680f68ea3e6988917c832767e951f3ff7457b17",
    "key_offsets": [
      0
    ]
  }
},

and for 1247:

{
  "key": 
  {
    "amount": 307304,
    "k_image": "fca0574448356fedf7493310fba22a717c0c7bd7f4acca03fb17bb8d582eb5ef",
    "key_offsets": [
      0
    ]
  }
},

So for each output you spend, you provide a set of key offsets, one of which will be yours...

This should mean that both txs use the tx with the index 0 as mixin. But there is only 1 offset present in the transactions meaning that the index 0 is the transaction itself.

1

So I am pretty confused how it can be that the same index in key_offsets can be more than once on the blockchain.

Let's take a step back.

Every output created (i.e. once mined, added to the blockchain), has a global index (its key offset).

Every transaction spends previously created outputs - it uses outputs as inputs to fund the transaction.

Now, when you create a transaction, for each output you own and are spending (so using as an input), you mix with other decoy outputs (other outputs on the blockchain, not owned by yourself). Collectively this is a set of key offsets (the global index of each output on the blockchain that is a member of this collection).

So for each output you spend, you provide a set of key offsets, one of which will be yours, the rest other peoples. This of course means other people creating transactions can also include your owned output indices in their set of key offsets.

As an observer, you can look at any given set of key offsets in a transaction, but have no idea which is the one actually being spent. Therefore, the fact you may see a particular output index in several different transactions, you have no way of knowing which, if any, of the transactions, are actually spending it.

Where are "the real" input keys stored and how can I acquire them?

If this is not clear from above, the input keys are stored on the blockchain. Each actual key is a previously created output and can be referenced (looked up), using its global index (key offset). You can use the daemon RPC command get_outs to obtain the actual key for an index. E.g. (on testnet here):

$ curl -X POST http://127.0.0.1:28081/get_outs -H 'Content-Type: application/json' \
       -d '{"outputs":[{"index":127232}]}'
{
  "outs": [{
    "height": 877775,
    "key": "3ab3f615dc7ee403d753f3c3604afe57af3bff62f2d95ae74c3ca5603295811c",
    "mask": "843ade9a400589ea368e639aec54a7627d06180eed9fbc5d3149f44bf452f3d9",
    "txid": "0000000000000000000000000000000000000000000000000000000000000000",
    "unlocked": true
  }],
  "status": "OK",
  "untrusted": false
}

UPDATE

Everything above relates to the current transaction version, v2 (i.e. RingCT), which covers the vast majority of Monero transactions. The question however has since been been updated to include references to pre-RingCT transactions as it now mentions heights 345 and 1247, so it's worth noting the following from the v1 transaction spec, section 3.2.2:

  - key_offsets: The list of offsets in the global array of outputs
  of type txout_to_key having the same amount as the input. The
  first value is the ordinal number of the first referenced output
  among those having the same amount. Each of the following values
  is the offset of the next referenced output relative to the
  previous one. One of the outputs referenced is the actual output
  being spent, but only the sender known which one it is. The array
  of the corresponding public keys is a part of one-time ring
  signature verification algorithm input [CNS002].

To lookup a v1 key from its offset, you must also provide the amount field, because as the spec states:

  The first value is the ordinal number of the first referenced output
  among those having the same amount.

And therefore the RPC command to lookup, includes the amount:

$ curl -X POST http://127.0.0.1:18081/get_outs -H 'Content-Type: application/json' \
       -d '{"outputs":[{"index":0,"amount":307304}]}'
{
  "outs": [{
    "height": 1123,
    "key": "45519224a687ec4fbb2675de996d4e3d8e8de8f32b7d6a57d6372f2f96908794",
    "mask": "8de5816e54e57d4c722e905aa5f9931da525ee351c29bb346aa1131f14937a9b",
    "txid": "0000000000000000000000000000000000000000000000000000000000000000",
    "unlocked": true
  }],
  "status": "OK",
  "untrusted": false
}

Therefore:

This should mean that both txs use the tx with the index 0 as mixin.

As you referenced txs in blocks 345 and 1247, these are v1 transactions. The output at index 0 for amount 307304, is not the same as the output at index 0 for amount 458444. They are different outputs.

  • Thank you for your answer. So what I am thinking is right. The key_offsets are indeed the inputs for my tx. BUT as I mentioned in my example I read multiple transactions where the whole key_offsets vector was the same. Meaning I had a vector1 = [1] and a vector2 = [1] from 2 different transactions, meaning the included inputs are the same. And since no mixins were used here (size=1) I definently know that this key is spend. This is the basis of the deannonymisation attack I am implementing. But you still answered the most needed part of my question. – Dimfred Aug 17 at 21:08
  • I've updated the answer based on your updated question which now references v1 transactions. – jtgrassie Aug 18 at 0:34
  • Now this all makes sense. Thank you very much. Yes indeed I am only interested in tx before block 1.400.000 (before RingCT enforce). Your answer was very good and well explained, I wish I could upvote it more times. – Dimfred Aug 18 at 12:36
  • Glad I could help. – jtgrassie Aug 18 at 13:56

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.