Author

Topic: How to compute stealth address prefix compatible with Dark Wallet (Read 1636 times)

hero member
Activity: 793
Merit: 1026
That's a great use case example!  Thank you again for your clear explanations.  It has been very helpful.
sr. member
Activity: 475
Merit: 252
Thank you again for another informative post!  So if I am understanding correctly, the 10 most significant bits of the hash of the OP_RETURN script (including the 6a identifier and the length) need to match the most significant bits of the prefix bytes.  So I just churn through nonces until the complete script hashes with the proper prefix bits.

As for the "i" problem -- I actually didn't know that i was available after the loop ended-- I thought it was destroyed.  That's why I was confused about that.

Also, what is the point of a multisig stealth address?  What is an example use case?  For the life of me, I don't understand the purpose of it.

You, me, and my brother exchange pubkeys and decide on a prefix and scan keypair, we can now create a static multisig address that anyone can pay to but it will generate a new multisig address for each transaction. So like the Darkwallet donation address is p2sh multisig, a team of bloggers could post a stealth multisig that's 2 of 3 etc. but looking up that address will not get you anything on the blockchain.

Use case could be a company that needs 2 of 3 signatures from 3 execs high up, but they don't want to reveal the entire funds of the company, plus they don't want to continue to give out new addresses every single time. Just one static address that is not lookup-able on the blockchain, and will give them new addresses for each transaction.
hero member
Activity: 793
Merit: 1026
Thank you again for another informative post!  So if I am understanding correctly, the 10 most significant bits of the hash of the OP_RETURN script (including the 6a identifier and the length) need to match the most significant bits of the prefix bytes.  So I just churn through nonces until the complete script hashes with the proper prefix bits.

As for the "i" problem -- I actually didn't know that i was available after the loop ended-- I thought it was destroyed.  That's why I was confused about that.

Also, what is the point of a multisig stealth address?  What is an example use case?  For the life of me, I don't understand the purpose of it.
sr. member
Activity: 475
Merit: 252
Also, I don't know how to make a pull request, but I'm pretty sure in lines 184-186 that the variable i should be changed to multi_n

Nope, this function parses it perfectly fine. I could replace i with (multi_n - 1) but since i ends the for loop with (multi_n - 1) anyways I left it there for simplicity's sake.

Edit:

Here's a stealth address I put together, it's a 2-of-3 p2sh multisig stealth with a 10 bit prefix at the end of it.

You can run it through my commit and it generates the outputs properly.

Code:
XnLzPVrAtK85YYpfthuy6o8urGjQCbr3kcbgzvKyCvuGY2VGSG1wmnkT5mYj1LTrY1fLi8eUjoLDDhA9VJYF2QWYdmW35V3dWPaCK4CJXWriLkXSXxXSLrgVNJxBpbZfcXf784Xzwa3YYPc3xycNQc8jZzo7828fCneoWS6zVfFeHFugBmx82Y64ZbA5rsYSkAo

Decoded into hex to make it easier to read with spaces:

Code:
2a = mainnet
00 = option
02e7b4c89573e9b26d6943919802fae4e364bc6520a2f7e7225e94121b38fcd394 = scan pubkey
03 = 3 total spend pubkeys
026cf6e82a420de750a5bb287a61274f4c593b2092c310eabd7837369d8fd40490 = spend_pubkey 1
03c4677b8497f7c785c9ac374db157c4e7b746040d425e13293d412784a85fa770 = spend_pubkey 2
02ae347b9e2d7d9ddf46b565438acee41df2b191762833ab362473f625a50c7267 = spend_pubkey 3
02 = 2 required signatures
0a = 10 prefix bits
ffff = 2 bytes because RoundUp(10 / 8) is 2, so 2 bytes. the first 10 bits (1111111111) must be matched.
7a00549c = the b58check checksum
hero member
Activity: 793
Merit: 1026
Thank you, that explanation and seeing the Electrum code in action really helped.

Also, I don't know how to make a pull request, but I'm pretty sure in lines 184-186 that the variable i should be changed to multi_n
sr. member
Activity: 475
Merit: 252
https://github.com/dabura667/electrum/blob/sendstealth/lib/bitcoin.py#L191

You are basically comparing the prefix to the trailing bytes at the end of the stealth address.

If the stealth address ends with a 0x00 that means a 0 bit length prefix.

if it is 0x0B then there will be two bytes tagged on to the end (because you need at least 2 bytes to represent 11 bits and 0x0B is 11)

so the sender takes the OP_RETURN script and hashes it with the nonce until the first 11 bits match the 1st 11 bits of the prefix bytes (the two bytes at the end of the stealth address)

This makes it easier for the receiver to find their payments, as the obelisk server stores all the stealth OP_RETURNS in a table along with the hash value given by double sha256ing the script + nonce.

So instead of checking every single one (like they do now) You can narrow it down to specific transactions.

The higher the prefix bit count, the harder it is to send to you but most people will probably only pick like a 3-4 bit prefix just to make synchronizing a tad faster. Higher the bitcount the less anonymity the stealth address has. (in fact, I think a 32 bit prefix that just tells the sender to place the 4 byte prefix AS THE NONCE and use that as an optional fully transparent re-usable address is one use case imo, as you can paste it statically on a website but you won't be reusing addresses when people send to you.

Anywho, any other questions?
hero member
Activity: 793
Merit: 1026
I'm trying to understand this explanation and for the life of me, I cannot understand it.  I understand that we're churning through nonces and double-sha256 of the entire output script including the nonce that's being tested.... but I don't understand what to compare it against or what to do with the double-hash once I have it.  Even in this seemingly simple function, I don't get what the bitsize is, or how that output is compared with the nonce.  Can somebody help me and explain in plain English, or Python code, how to calculate the prefix for stealth OP_RETURN data?  I truly feel like I dunce here, but it's just not making sense.
Jump to: