Pages:
Author

Topic: Python Bitcoin ECC library, supports signing, transactions, determinstic wallets - page 2. (Read 11455 times)

legendary
Activity: 1708
Merit: 1020
Quote
Thanks for the commit!
My pleasure. PBT is great.
legendary
Activity: 1512
Merit: 1036
You can grab line 573-590 out of here if you want to add a "print paper wallet" def print_wallet(priv) to your code:

http://we.lovebitco.in/dice2key.py

Or grab the whole thing to line 483 if you want a pretty version of main.py, but there's still some warnings for python 2.7:

Expected type 'Number', got 'str | unicode' instead (at line 429) (edit: this appears to be an invalid warning I can't make go away)
Unexpected argument (at line 92) (incorrect call argument) (edit: VB fixed this)
472-475 "Q and Qr" are uppercase
redundant parenthesis. 94, 98, 103, 107, 112, 162, 167, 169

along with more PEP8 if: statements on same line, spacings etc.
newbie
Activity: 32
Merit: 0
Huge thanks for sharing.

This is the most intelligible/simple implementation I've found yet, and not just for ECC.
sr. member
Activity: 469
Merit: 253
In signing multisig transactions with pybitcointools.apply_multisignatures, I found that you have to apply the signatures in the correct order.
...

E.g. pubkeys PA, PB,PC. We apply signatures SA SB. First sig SA matches first pubkey PA, second matches second, so it returns 1. But what if we apply SA SC? It seems from my experiments that it works, but that if we apply SC SA, it doesn't. Is that what's supposed to happen?

Yes, that's how it's supposed to work. It's a Bitcoin protocol thing; it's done this way for efficiency reasons as I understand, so signature verification can be linear (try the pubkeys in order) instead of quadratic (try every sig with every pubkey to see if any combination works).

Thanks. That makes sense. Only a tiny bit of extra code to write Smiley
sr. member
Activity: 330
Merit: 397
In signing multisig transactions with pybitcointools.apply_multisignatures, I found that you have to apply the signatures in the correct order.
...

E.g. pubkeys PA, PB,PC. We apply signatures SA SB. First sig SA matches first pubkey PA, second matches second, so it returns 1. But what if we apply SA SC? It seems from my experiments that it works, but that if we apply SC SA, it doesn't. Is that what's supposed to happen?

Yes, that's how it's supposed to work. It's a Bitcoin protocol thing; it's done this way for efficiency reasons as I understand, so signature verification can be linear (try the pubkeys in order) instead of quadratic (try every sig with every pubkey to see if any combination works).
legendary
Activity: 1512
Merit: 1036
This library seems to have no problem putting invalid private keys through math without validation:
Code:
>>> pybitcointools.privtopub('0000000000000000000000000000000000000000000000000000000000000000')
'0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'
>>> pybitcointools.privtopub('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee')
'04d3c3c891a4e05e520b01928b19cf7b56b7debc725dd915a42763a6c94bcdce54e171bf8daa5328e7ef955a8d60a9e72cc6fe5ac918eac04134d692a34654c6c4'
>>> pybitcointools.get_privkey_format('ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffee')
'hex'
sr. member
Activity: 469
Merit: 253
In signing multisig transactions with pybitcointools.apply_multisignatures, I found that you have to apply the signatures in the correct order.

I can't find a clear explanation anywhere of how the signatures are applied, but here it says:
Quote
For each signature and public key pair, OP_CHECKSIG is executed. If more public keys than signatures are listed, some key/sig pairs can fail. All signatures need to match a public key. If all signatures are valid, 1 is returned, 0 otherwise
That's a bit ambiguous ("All sigs need to match a public key"), but it looks like it means that each sig-pubkey is checked as a pair. I don't get how this works.

E.g. pubkeys PA, PB,PC. We apply signatures SA SB. First sig SA matches first pubkey PA, second matches second, so it returns 1. But what if we apply SA SC? It seems from my experiments that it works, but that if we apply SC SA, it doesn't. Is that what's supposed to happen?

sr. member
Activity: 330
Merit: 397
I quite like your library.
It took me a while to realise that it actually does handle wallet import format. It works if you put WIF into privtopub() although it took me some searching and thinking to realise you can use bin_to_b58check() to make WIF from a binary private key. Maybe a priv_to_wif() function should be made?

Done, although not quite in that form. It's:

> key = sha256('123')
> key
'a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3'
> encode_privkey(key,'wif')
'5K5ZyFA5NqiBzCbiaTh5KYJmSh7dXdk65DvGkcx9G6ydsj83TM1'


Or just
Code:
cat key | pybtctool -s encode_privkey wif

What kind of license is this under?

Public domain; if that's not accepted in your jurisdiction then MIT. Just added the license file today.

Quote
Also there seems to be no pure python impl of scrypt. I know this goes against your intent (which I agree with) of having no dependency chasing.

Relying on an external C++ library for scrypt is fine; doing it pure python forces you to set lower parameters for practicality, which weakens security. My general rule is, if it's in a default Python installation, it's probably fine.
sr. member
Activity: 469
Merit: 253
Also, one suggestion request: should I made deserialize call deserialize_script automatically? That way deserialization would decompose the transaction all the way, including breaking down the script. If not, then I'll probably make a separate showtx method which would do a full decomposition and also try to calculate the input addresses for standard pubkey and p2sh transactions.

I'm not knowledgeable enough in the field to be very familiar with what people want, but having tried it out, I can definitely see a use for it (script deserialization). Whether there are use cases involving not doing it, such as to tie up the format with what bitcoind produces, I don't know, but I guess so. The obvious answer is to make it optional with a default of not doing it, i.e. deserialize(tx, deserialize_script=False)

Edit: a small thought, you might want to translate 174 to OP_CHECKMULTISIG or something like that. Being a noob in Bitcoin development I was confused by that kind of thing at first Smiley
sr. member
Activity: 469
Merit: 253
Can I ask which version of electrum you're using? I have 0.9 installed on my vps (because they're in the process of implementing multisig in the new version) but I can't get it to work right now with that, at least not yet.

Edit: ignore that; I was calling sendtx wrongly within Electrum. I finally managed to send my first multisig payment on the network Smiley

I find Electrum really flaky though; it took me three tries of running my script before the tx got accepted by a server. Sometimes it just hangs (messages like SSL Handshake timeout and others), and weirdly the second time I sent the transaction I got an error code -22 ( (False, u"error: {u'message': u'TX rejected', u'code': -22}")), but the third time it got sent  ((True, u'3e1dbe4c661b83b3d5ff22abf0e545924350c666c65ca875ac6aed741fb902b7')).
Any hints on how to make it robust, bearing in mind I'm trying to do everything within Python?

About your deserialize question: I'll have to take another look at the code, not sure if I can comment, but I'll try.
sr. member
Activity: 330
Merit: 397
Thanks muchly.
About sorting the pubkeys, I agree; I was a bit bewildered at first why you did it, then I saw the point, but finally I agree it's less confusing to just not do it.
About blockchain.info, the reason I didn't suspect it being the problem is that at least one person (and maybe others I read online) told me that they definitely do accept multisig txs. Is there any contact/support person there I could ask for confirmation, I wonder?

And one last question about this post: Why are you applying all 3 signatures? Isn't this 2 of 3?

Yep, sorry, meant to apply only 2 of 3. I made a mistake at first and copied over the wrong lines from my command line history. Retroactively fixed in my above comment.

As for bugs, I submitted it to the thread: https://bitcointalksearch.org/topic/m.3408171

Also, one suggestion request: should I made deserialize call deserialize_script automatically? That way deserialization would decompose the transaction all the way, including breaking down the script. If not, then I'll probably make a separate showtx method which would do a full decomposition and also try to calculate the input addresses for standard pubkey and p2sh transactions.
sr. member
Activity: 469
Merit: 253
sr. member
Activity: 330
Merit: 397
Okay, made some fixes.

1. scriptaddr takes hex or bin input
2. mk_multisig_script no longer sorts public keys (at first I did this so that people could deterministically make a multisig out of some keys without having to remember the order; this incident now convinced me that such a decision was inappropriate for a low-level library like pybitcointools). This should fix some problems as signature validation issues can arise if multisig signatures are in the wrong order.

However, the "Invalid Signature" problems are not entirely the fault of (2); rather, it seems like blockchain.info is screwing up. I spent some time debugging this; then however I tried pushing the same transaction using `electrum sendrawtransaction [tx]` and everything worked fine. I've run this again; same result.

Also, here are the instructions for how to make a multisig with pybtctool (the included command line wrapper for pybitcointools), copied straight from the command line:

Code:
vub@vub-U200: pybtctool random_key > k1
vub@vub-U200: pybtctool random_key > k2
vub@vub-U200: pybtctool random_key > k3

vub@vub-U200: cat k1 | pybtctool -s privtopub > p1
vub@vub-U200: cat k2 | pybtctool -s privtopub > p2
vub@vub-U200: cat k3 | pybtctool -s privtopub > p3

vub@vub-U200: cat p1 p2 p3 | pybtctool -s mk_multisig_script 2 3
524104b469d4fafd936e8630a5377223c5b7acfa9d2948b96845cc332607ec8528e6018abe46af616567ca44fca2d703a400dfdae73d0e21265c4dbeaf09e6294aa41941048ac7607d833aedb50c7be390955513f40327ff83891b53db2b241af64526ac17b37e7599f5ab2d4c7152779470dbc95c91526217de7bc002197ded7410526bfe4104cad74f0cf89dca7e13f37257e81308772fe3c7280f656ac88367867c54256ed606aa4dd2dc8ce4e73abb3159974f11657d2a365cee6fe86eeec4a8ce529cecd153ae
vub@vub-U200: cat p1 p2 p3 | pybtctool -s mk_multisig_script 2 3 > script

vub@vub-U200: pybtctool multisign `cat tx` 0 `cat script` `cat k1` > s1
vub@vub-U200: pybtctool multisign `cat tx` 0 `cat script` `cat k2` > s2
vub@vub-U200: pybtctool multisign `cat tx` 0 `cat script` `cat k3` > s3

vub@vub-U200: pybtctool apply_multisignatures `cat tx` 0 `cat script` `cat s1` `cat s3` > stx
vub@vub-U200: pybtctool apply_multisignatures `cat tx` 0 `cat script` `cat s1` `cat s3`
010000000125b98a02b8eb1ef3efb471cc87d6f028b53eadf29fe1cfb73fd0151188b6fe9300000000fd5f0100493046022100bcb0e128a7f4f39575f538979ecce4d49142ef6b613b4a98609bc14a7ae5ee0c02210094aca62aeae8301711560171087d8f069b79016d037f4e806df6c2efe12354e3014830450220257a3130f1d47ddf06b6a33882a1f1295cd8506f1ba1383b8b4cb5a40813c7ff022100ccea8cf93c54540f770e805a61585fb0ae82d6b6f68929b65afb0d6a9c0aa4ab014cc9524104b469d4fafd936e8630a5377223c5b7acfa9d2948b96845cc332607ec8528e6018abe46af616567ca44fca2d703a400dfdae73d0e21265c4dbeaf09e6294aa41941048ac7607d833aedb50c7be390955513f40327ff83891b53db2b241af64526ac17b37e7599f5ab2d4c7152779470dbc95c91526217de7bc002197ded7410526bfe4104cad74f0cf89dca7e13f37257e81308772fe3c7280f656ac88367867c54256ed606aa4dd2dc8ce4e73abb3159974f11657d2a365cee6fe86eeec4a8ce529cecd153aeffffffff0110270000000000001976a91405778c85c60c69598ea5bc896f872415fa7100b288ac00000000
vub@vub-U200: pybtctool pushtx `cat stx`
Traceback (most recent call last):
  File "/usr/local/bin/pybtctool", line 14, in
    o = vars()[cmd](*args)
  File "/usr/local/lib/python2.7/dist-packages/pybitcointools/bci.py", line 57, in pushtx
    return make_request('http://blockchain.info/pushtx','tx='+tx)
  File "/usr/local/lib/python2.7/dist-packages/pybitcointools/bci.py", line 13, in make_request
    raise Exception(p)
Exception: Invalid Signature
vub@vub-U200: electrum sendrawtransaction `cat stx`
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/electrum/interface.py", line 329, in init_tcp
    s.connect(( self.host.encode('ascii'), int(self.port)))
  File "/usr/lib/python2.7/ssl.py", line 331, in connect
    self._real_connect(addr, False)
  File "/usr/lib/python2.7/ssl.py", line 324, in _real_connect
    raise e
timeout: timed out
Using random server...
electrum.stepkrav.pw:50002:s
Connected to electrum.stepkrav.pw:50002
"914be4d2d48426959844520264e75f4c751b93cef8b5c13b2365bebcd9aa7181"

The instructions with plain pybitcointools are pretty much exactly the same.
sr. member
Activity: 469
Merit: 253
Your problem is that mk_multisig_script returns a hex encoded string and scriptaddr expects binary.  Fix:

Code:
msigaddr = scriptaddr(mscript.decode('hex'))

Many thanks. That solved that one. Do you happen to know the answer to my previous question too? (i.e. I'm still getting "Invalid Signature" after signing with the two private keys).
newbie
Activity: 16
Merit: 0
Your problem is that mk_multisig_script returns a hex encoded string and scriptaddr expects binary.  Fix:

Code:
msigaddr = scriptaddr(mscript.decode('hex'))
sr. member
Activity: 469
Merit: 253
A further question; possibly related, possibly not.

Creating a multisig address with bitcoind:

Code:
>_ ~/.bitcoin# bitcoind createmultisig 2 '["0453170015ba9dd27388e51e824a8d5516b7627c025e3727232d9803ffd9c2b99d3ac338b28656aa6461e751758ce22399128f4a290a0ba705ae137baadd548f24","048c3acf5cad1a4c18467ea64382b1e50d2a5f4cc9060219d360c5f50a8ef7c01875295a3b0801c06240e888afce9c17d2bbd295bea9aafb0b6d7d1c69b0e154c5","04a8b14eb8ae0a6decb12e3b8b3c907e2084fd74d30bd00b93e687b0bf7a450055706aed7f2aaf5ae1bff08b49a0310af3f1cc5b949607f522810ed9a139f6a69e"]'
{
    "address" : "3Ej7teuzS7AGQGFdGPfRpyCwzRUq7fUHoQ",
    "redeemScript" : "52410453170015ba9dd27388e51e824a8d5516b7627c025e3727232d9803ffd9c2b99d3ac338b28656aa6461e751758ce22399128f4a290a0ba705ae137baadd548f2441048c3acf5cad1a4c18467ea64382b1e50d2a5f4cc9060219d360c5f50a8ef7c01875295a3b0801c06240e888afce9c17d2bbd295bea9aafb0b6d7d1c69b0e154c54104a8b14eb8ae0a6decb12e3b8b3c907e2084fd74d30bd00b93e687b0bf7a450055706aed7f2aaf5ae1bff08b49a0310af3f1cc5b949607f522810ed9a139f6a69e53ae"
}

Trying to create the same multisig address with pybitcointools:
Code:
pubs = [same 3 pub keys as above]
mscript = mk_multisig_script(pubs,2,3)
msigaddr = scriptaddr(mscript)
print msigaddr
print mscript

gives this output:
Code:
38izn5J4EECw5NNFBE27fwLyxkaBAsavSF
 52410453170015ba9dd27388e51e824a8d5516b7627c025e3727232d9803ffd9c2b99d3ac338b28656aa6461e751758ce22399128f4a290a0ba705ae137baadd548f2441048c3acf5cad1a4c18467ea64382b1e50d2a5f4cc9060219d360c5f50a8ef7c01875295a3b0801c06240e888afce9c17d2bbd295bea9aafb0b6d7d1c69b0e154c54104a8b14eb8ae0a6decb12e3b8b3c907e2084fd74d30bd00b93e687b0bf7a450055706aed7f2aaf5ae1bff08b49a0310af3f1cc5b949607f522810ed9a139f6a69e53ae

The address generated is different, but the redeem script is the same. Something must be wrong..?
sr. member
Activity: 469
Merit: 253
This seems to be very inline with what I'm trying to do, so I greatly appreciate it.
Would it be possible to get a quick walkthrough of how to implement multisig transactions, along the lines of Gavin Andreesen's walkthrough for 2of3: https://gist.github.com/gavinandresen/3966071 ?

Edit: maybe it would be better for me to ask for help with a specific problem, so here goes:

I attempted to construct a spend FROM  a multisig address:

the 2 of 3 multisig was created with:
Code:
mscript = mk_multisig_script(pubs,2,3)
msigaddr = scriptaddr(mscript)

and pubs is a list of 3 public addresses, with corresponding list privs and list addresses.

I tried to spend thusly:

Code:
outs = [{'value': 20000, 'address': '38izn5J4EECw5NNFBE27fwLyxkaBAsavSF'},{'value':60000,'address':addresses[2]}]
tx3 = mktx(history(msigaddr),outs)
sig1 = multisign(tx3,0,mscript,privs[0])
print "Verifying sig1:",verify_tx_input(tx3,0,mscript,sig1,pubs[0])
sig2 = multisign(tx3,0,mscript,privs[2])
print "Verifying sig2:",verify_tx_input(tx3,0,mscript,sig2,pubs[2])
tx4 = apply_multisignatures(tx3,0,mscript,[sig1,sig2])
print deserialize(tx4)
pushtx(tx4)

#for ref, history(msigaddr) gives: [{'output': u'aba22dd8cab30ffcfb0c57eb20d3dc9412de4e28fda6a10375b5292a03892467:0', 'value': 100000, 'address': u'38izn5J4EECw5NNFBE27fwLyxkaBAsavSF'}]

I get an "Invalid Signature" exception. What did I do wrong?
staff
Activity: 4284
Merit: 8808
I'm thinking of maybe implementing BIP38, mostly for making encrypted paper wallets.
There is no BIP38.
newbie
Activity: 40
Merit: 0
I quite like your library.
It took me a while to realise that it actually does handle wallet import format. It works if you put WIF into privtopub() although it took me some searching and thinking to realise you can use bin_to_b58check() to make WIF from a binary private key. Maybe a priv_to_wif() function should be made?

So to generate keys for a paper wallet. (Maybe on a livecd with no browser where you cant load bitaddress.org)


>>> priv = random_key()
>>> bin_to_b58check(priv.decode("hex"), 0x80)
'5JjCeDuxt9jWdb7nw43w7zQSB53MYpVi1aXe7XoxrhebWB3ft5k'
>>> privtoaddr(priv)
'1Jx1tHXNLRHyDQUxhNAaWdMRRk5vUmSEeC'
>>>



I'm thinking of maybe implementing BIP38, mostly for making encrypted paper wallets.
What kind of license is this under? Since some pure python AES256 implementations I'm looking at are under Apache license. I never really paid much attention to licenses but I should ask how it goes here before I just copypaste parts of it into this library.
Also there seems to be no pure python impl of scrypt. I know this goes against your intent (which I agree with) of having no dependency chasing. I imagine I'll try to code BIP38 and if it goes well try to code a pure python scrypt.
sr. member
Activity: 330
Merit: 397
See my latest commits:

http://github.com/vbuterin/pybitcointools

New features:

* history: returns the history of an address in the form of outputs, including whether or not each output has been spent (uses blockchain.info)
* pushtx: pushes a transaction with blockchain.info/pushtx
* mktx, sign (build transactions)
* deterministic (RFC6979) ECDSA signing, so those evil random number generators will never hurt you again.
* pybtctool: a command-line tool for calling any of the functions in the library
* A setup.py script to make the library installable
* An actual README.md file (more coming soon)

The basic transaction tools have been confirmed to work; feel free to start building apps on top of it!
Pages:
Jump to: