Electrum's "script hash" form with NBitcoin?

1

I've come across how scripts are hashed in the electrum (stratum) protocol implementation by looking at the docs.

I'm using NBitcoin, and I've tried to generate this hash from a segwit address, first this way:

myPublicKey.WitHash.ScriptPubKey.Hash.ToString()

However, electrum servers throw an error saying that this hash is not valid. I'm guessing because this hash is of type HASH160 instead of SHA256 like the docs claim? (As I see that the hash generated by this technique is the same hash that appears below the address in a page like this.)

Also I'm wondering if I need to reverse the chain of characters myself or if NBitcoin's SHA256 methods would do it for me? All in all, how to get this hash with NBitcoin API so that Electrum servers are happy?

knocte

Posted 2019-01-13T17:31:39.143

Reputation: 1 581

Answers

1

In F#:

let address = BitcoinAddress.Create("1HLoD9E4SDFFPDiYfNYnkBLQ85Y51J3Zb1", 
                                    NBitcoin.Network.Main)
let sha = NBitcoin.Crypto.Hashes.SHA256(address.ScriptPubKey.ToBytes())
let reversedSha = sha.Reverse().ToArray() // add `open System.Linq` at the top
NBitcoin.DataEncoders.Encoders.Hex.EncodeData reversedSha

knocte

Posted 2019-01-13T17:31:39.143

Reputation: 1 581

-1

Electrum server expects scripts to be queried by their sha256 hash, regardless of script type. The name script hash is a bit confusing - it actually just means take the sha256 of the script. You should be using a bare sha256 method instead of the Hash one, which seems to hash the data for use with bitcoin transactions. I'm not sure which endianness is used by NBitcoin, but if you do end up needing to reverse it, you shouldn't reverse the individual characters, rather you should be reversing the raw bytes, or in case it's a string, then in groups of two characters.

arubi

Posted 2019-01-13T17:31:39.143

Reputation: 1 716

I've tried both WitScriptId(account.PublicKey.WitHash.ScriptPubKey).ToString() (because WitScriptId constructor seems to call sha256) and also reversed via NBitcoin.DataEncoders.Encoders.Hex.EncodeData(WitScriptId(account.PublicKey.WitHash.ScriptPubKey).ToBytes().Reverse().ToArray()), but electrum servers return a balance of zero for these two options (but I know it's not zero) – knocte – 2019-01-13T18:17:06.167

You shouldn't be using any bitcoin-specific hashes to hash the scriptpubkey. Try something like : https://github.com/MetacoSA/NBitcoin/blob/master/NBitcoin/Crypto/Hashes.cs#L621

– arubi – 2019-01-13T18:31:05.897

now I've tried NBitcoin.DataEncoders.Encoders.Hex.EncodeData(NBitcoin.Crypto.Hashes.SHA256(account.PublicKey.ScriptPubKey.ToBytes())), and reversing it; and NBitcoin.DataEncoders.Encoders.Hex.EncodeData(NBitcoin.Crypto.Hashes.SHA256(account.PublicKey.WitHash.ScriptPubKey.ToBytes())) and reversing it, still zero balance – knocte – 2019-01-13T18:52:11.043

Maybe post the contents of an example ccount.PublicKey.ScriptPubKey in your original question. Hard to know if you're hashing the correct blob. – arubi – 2019-01-13T19:00:28.407

updated the question to reflect what you just asked – knocte – 2019-01-14T04:02:35.663

Ok, so really the address 39PtejNZn8sTGSFrefYUWxp7WdEyMLobkQ is for the script A9145483DD3179B74D410D474669AD5ED63A55EAB5A387, which isn't listed. The "reversed" sha256 of this script is 8ECFA8BA033A3332C73BBC6368DFA99D0FA2BD7035A92A4D78BBF0197E1FE44B. The two scrips you did list are a p2pk and p2wpkh, but not the p2sh-p2wpkh which the address actually references. The last script which is the bare p2wpk script has address bc1qfd6pj3fttk7caqsqpauvr7khy9lwpmgsf4thv2 and rev. sha256 46731F1C49B8E024E92702C8CE87764C0C0F8BCF675C90B8E26BC38FF9043179 – arubi – 2019-01-15T18:47:40.470