Advertisement
Guest User

Untitled

a guest
Sep 20th, 2014
400
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. # This is a proposal to eliminate the need for OP_RETURN to relay
  2.  
  3. # First lets take an utxo that we own and try to send it to a stealth address.
  4.  
  5. # Info of utxo:
  6.  
  7. prev_hash = 'f3ebd0b3534518c23f439aac836ff207d6414b6530aecf1e0fff1d413774f994'
  8. vout = '06' # The 7th output.
  9. amount = 0.03170609 # in BTC
  10.  
  11. # The address I am using to send from in this example is 1FHxvwCfFz3B1VZSAQa71qWGyDbxdfamh4
  12.  
  13.  
  14. # Normally, this is where we would generate an ephemeral pubkey.
  15. # But instead, the sender, having entered the password for signature, reveals the private key
  16. # to the above address.
  17.  
  18. privkey = Decrypt(encrypted_privkey) # lets assume privkey is in bigint format.
  19.  
  20. shared_secret = ECmultiply(privkey, scan_pubkey) # scan_pubkey of recipient
  21. shared_secret_priv = sha256(shared_secret)
  22. shared_secret_pub = ECmultiply(shared_secret_priv, SECP256k1_generator_point)
  23.  
  24. # We have in effect, used the senders key as the ephemeral key. Since the pubkey must be
  25. # included in the ScriptSig, the recipient can know the shared secret without
  26. # the tx looking obviously like a stealth transaction.
  27.  
  28. # Here is where I thought: Oh, but if I send more bitcoins from the same address to the
  29. # same stealth address... the resulting send_to address will be the same! address reuse! OMG
  30.  
  31. # Now comes the solution. We take the hash of concatenated scan_pubkey, prev_hash, vout, and index
  32. # index is only used in the case where the same input is used with the same stealth address in the
  33. # same transaction. So if my input is fefe...fefe:3 and I have two outputs sending to Stealth Address Xyz...
  34. # Then the first one uses '00' and the second uses '01' etc.
  35. index = '00'
  36.  
  37.  
  38. # This becomes the privkey for a 3rd point.
  39.  
  40.  
  41. vout_priv = sha256((scan_pubkey + prev_hash + vout + index).decode('hex'))
  42. vout_pub = ECmultiply(vout_priv, SECP256k1_generator_point)
  43.  
  44.  
  45. # Now we have 3 points: spend_pubkey, shared_secret_pub, and vout_pub.
  46. # Add all three together.
  47.  
  48. address_point = ECaddition(ECaddition(spend_pubkey, shared_secret_pub), vout_pub)
  49. # As ECadd is communicative, order of addition doesnt matter
  50.  
  51. send_to_address = Base58CheckEncode(ripemd160(sha256(address_point)))
  52.  
  53. # create the output sending to the above address. Sending is finished.
  54.  
  55.  
  56. # For the recipient:
  57. # First, lets assume he knows what tx is to him from some outside source.
  58. # (I will mention the search method later)
  59.  
  60. # He searches the ScriptSig of each input for any pubkeys, and tries them in order.
  61. # (normal p2kh will have 1 pubkey per input)
  62.  
  63. # He notices the pubkey of the first input (which is prev_hash)
  64.  
  65. pubkey = '0309430d1bea1b90a59523f2892cd26084808394ce5cc7ea4b6ecbec0a63480c8c'
  66.  
  67. shared_secret = ECmultiply(scan_privkey, pubkey) # pubkey from ScriptSig x scan_privkey
  68. shared_secret_priv = sha256(shared_secret)
  69.  
  70.  
  71. # Then he looks at the vout index and prevhash used in the input.
  72.  
  73. vout_priv = sha256((scan_pubkey + prev_hash + vout + index).decode('hex'))
  74.  
  75.  
  76. # Adds together the three privkeys to (hopefully) generate the address.
  77.  
  78. send_to_address_priv = (spend_privkey + shared_secret_priv + vout_priv) % N # Mod order of the curve.
  79.  
  80. # Generate the address and check all outputs in the transaction to see if it is there.
  81. send_to_address_pub = ECmultiply(send_to_address_priv, SECP256k1_generator_point)
  82. send_to_address_test = Base58CheckEncode(ripemd160(sha256(send_to_address_pub)))
  83.  
  84. assert send_to_address_test == send_to_address
  85.  
  86. # If the addresses are equal, then you now have the private key,
  87. # and the only information necessary was the txid.
  88.  
  89.  
  90.  
  91. """
  92. Lets talk about performance:
  93.  
  94. If we look at the procedures for send and receive with the old OP_RETURN
  95. method (I left out simple things like adding bigints and modding the order of the curve etc.)
  96.  
  97. Old send   : ECmult > sha256 > ECmult > ECadd > sha256 > ripemd160
  98. ECmult x 2
  99. ECadd x 1
  100. sha256 x 2
  101. ripemd160 x 1
  102.  
  103. Old receive: ECmult > sha256 > ECmult > sha256 > ripemd160
  104. ECmult x 2
  105. sha256 x 2
  106. ripemd160 x 1
  107.  
  108.  
  109. Looking at the New method I explained above and comparing:
  110.  
  111. New send   : ECmult > sha256 > ECmult > sha256 > ECmult > ECadd > ECadd > sha256 > ripemd160
  112. ECmult x 3
  113. ECadd x 2
  114. sha256 x 3
  115. ripemd160 x 1
  116. Compare: Increase of 1 of each (ECmult, ECadd, sha256)
  117.  
  118. New receive: ECmult > sha256 > sha256 > ECmult > sha256 > ripemd160
  119. ECmult x 2
  120. sha256 x 3
  121. ripemd160 x 1
  122. Compare: Increase of 1 sha256
  123.  
  124. The heavy lifting is on the receiving end (as you must now iterate through every single ScriptSig
  125. and compare against all output addresses.) but luckily the receiving calculations only increased by one sha256.
  126.  
  127. To narrow down the txes you need to search... I was wondering if the input that was used to generate the address
  128. could change the sequence (the one that is normally 0xffffffff at the end of each input) to hash to the prefix...
  129. or even match the sequence msb bits to the prefix bits etc.
  130.  
  131. Caveats:
  132. 1. Can't send to stealth from Trezor using this method. (as you need to multiply your private key with the scan_pubkey)
  133.   Unless Trezor allowed for performing ECmultiplication on the device, and Trezor returns the shared secret.
  134.  
  135. 2. When thinking about coinjoin and other aspects where multiple people spending to multiple stealth addresses, if we consider coinjoin, we must check every input of every transaction against our info... which is costly. Doing things to mark inputs as stealth info (maybe changing the sequence value) could be considered... but for 100% stealth and 100% no way to discern stealth from normal... there seems to be no other way than to check every input.
  136.  
  137. However: that being said... it eliminates the requirement for the OP_RETURN table on Obelisk servers... and it's not much more strenuous than running a full node. (having to scan every input of every transaction etc. when blocks come in) but it will be more strenuous for SPV servers, as upon every block they will have to send every transaction to each user... it will also be hard to do on mobile devices (drain battery)... obviously the wallet file would store the most recently checked block so that it doesn't check from the beginning every time...
  138.  
  139. Perhaps a mode where the wallet doesn't actively search, but users need to input the txid or something that they receive from the sender might be good for mobile...
  140.  
  141. I would like to hear any comments / questions.
  142.  
  143. - dabura667
  144.  
  145. """
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement