I’ve been writing my own Python library for handling Bitcoin elliptic curve arithmetic for a while now, and just yesterday I made a serious push to have it include many more features. It now supports compressed keys, ECDSA message signatures (compatible with Electrum; see tests.py) and even Electrum wallets. I thought that the project would also interest this community particularly because the base58check conversions have an open “magic byte” parameter that you can set to various values to create addresses for different currencies. I’m pretty sure that this is the only functional implementation of a deterministic wallet generator for ppcoin and primecoin, if not all altcoins in general, out there (correct me if I’m wrong there).
Here’s the repo: https://github.com/vbuterin/pybitcointools
I deliberately designed the library to be simple and no-nonsense. No hundred-line monolithic functions, no classes, no wrapper objects, just hex/binary/numbers in and hex/binary/numbers out. Note that this is NOT a fully functional wallet; it does not support transaction generation or verification, networking or anything to do with blocks. You still need *coind or *coin-qt along with the importprivkey command to do that.
Here are some basic usage scenarios:
[font=courier]> from main import *
pk = sha256(“correct horse battery staple”)
pk
‘c4bbcb1fbec99d65bf59d85c8cb62ee2db963f0fe106f483d9afa73bd4e39a8a’
hex_to_b58check(pk,128)
‘5KJvsngHeMpm884wtkJNzQGaCErckhHJBGFsvd3VyK5qMZXj3hS’
pubkey_to_address(privtopub(pk))
‘1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T’[/font]
ECDSA (Electrum-compatible):
[font=courier]> sig = ecdsa_sign(“Hallo world”,sha256(“123”))
sig
‘G9vmnqdlS9hmP7qT6ReRJEqldYn7f6xc47ado3zg7g4LKpLgVmpmSttDNAAPSizww7zzKDamsyD7bhhfAqaAJ0s=’
ecdsa_verify(“Hallo world”,sig,privtopub(sha256(“123”)))
True
ecdsa_verify(“Hallo world!”,sig,privtopub(sha256(“123”)))
False
ecdsa_recover(“Hallo world”,sig)
‘04be686ed7f0539affbaf634f3bcc2b235e8e220e7be57e9397ab1c14c39137eb43705125aac75a865268ef33c53897c141bd092cf4d1a306b2a57e37e1386826d’
privtopub(sha256(“123”))
‘04be686ed7f0539affbaf634f3bcc2b235e8e220e7be57e9397ab1c14c39137eb43705125aac75a865268ef33c53897c141bd092cf4d1a306b2a57e37e1386826d’[/font]
Electrum:
[font=courier]> seed = sha256(“cow”)[:32]
mpk = electrum_mpk(seed)
for i in range(5): print electrum_privkey(seed,i,0), pubkey_to_address(privtopub(electrum_privkey(seed,i,0)))
daa19f768ea1a7bc8e33d83f9401ef237f5164ce39bf8000ec9630d088cec028 1GG9cGb7KW6qNBCxcU7Y3NH3mPRz9YSxgG
c45ad49da1ccb0ba30258902ed3de66af571de7421f9c73ffc0a8c2bde9ca596 19zxmnE4hmTwPFxhoDAxjtfnKQcRES4Sm2
c31100a56692314248a73f29b767ca252c3847eae15ce5d06e7e7f67a63ee5df 17mJpsyEVykxuf5H4YWsyhatXFyuJmkuoh
302362a97a2db566c5c65b875388db7cce246355faa72f15b486111c2f380bf3 16PGWQwcXM37iY7dPHqqVFit4GXsifRuAM
869424a50260cca7a7fa475c85e48ddf0e47abb0474df59ee45e72e6b95c8333 15QgAJmroGtExvVqVd8MGs1ZZvwYsk39i7
for i in range(5): print pubkey_to_address(electrum_pubkey(mpk,i,0))
1GG9cGb7KW6qNBCxcU7Y3NH3mPRz9YSxgG
19zxmnE4hmTwPFxhoDAxjtfnKQcRES4Sm2
17mJpsyEVykxuf5H4YWsyhatXFyuJmkuoh
16PGWQwcXM37iY7dPHqqVFit4GXsifRuAM
15QgAJmroGtExvVqVd8MGs1ZZvwYsk39i7[/font]
Much faster Electrum by precomputing the secret exponent:
[font=courier]> seed = sha256(“cow”)[:32]
secexp = electrum_stretch(seed)
for i in range(5): print electrum_privkey(secexp,i,0), pubkey_to_address(privtopub(electrum_privkey(secexp,i,0)))
daa19f768ea1a7bc8e33d83f9401ef237f5164ce39bf8000ec9630d088cec028 1GG9cGb7KW6qNBCxcU7Y3NH3mPRz9YSxgG
c45ad49da1ccb0ba30258902ed3de66af571de7421f9c73ffc0a8c2bde9ca596 19zxmnE4hmTwPFxhoDAxjtfnKQcRES4Sm2
c31100a56692314248a73f29b767ca252c3847eae15ce5d06e7e7f67a63ee5df 17mJpsyEVykxuf5H4YWsyhatXFyuJmkuoh
302362a97a2db566c5c65b875388db7cce246355faa72f15b486111c2f380bf3 16PGWQwcXM37iY7dPHqqVFit4GXsifRuAM
869424a50260cca7a7fa475c85e48ddf0e47abb0474df59ee45e72e6b95c8333 15QgAJmroGtExvVqVd8MGs1ZZvwYsk39i7[/font]
And the part that you’ll be interested in. Just add “23” as a parameter to pubkey_to_address and, presto, you have a Primecoin address!
[font=courier]> seed = sha256(“cow”)[:32]
secexp = electrum_stretch(seed)
for i in range(5): print electrum_privkey(secexp,i,0), pubkey_to_address(privtopub(electrum_privkey(secexp,i,0)),23)
daa19f768ea1a7bc8e33d83f9401ef237f5164ce39bf8000ec9630d088cec028 AX32FmSjeekzB9QxB7msCFY9EzMgW3n1QE
c45ad49da1ccb0ba30258902ed3de66af571de7421f9c73ffc0a8c2bde9ca596 AQmqRH5h2v86CEAhMrqHtmvso1Y7ZfKRpz
c31100a56692314248a73f29b767ca252c3847eae15ce5d06e7e7f67a63ee5df ANYBUNprq8R7idHGdCBD8aqyzrubaCesdF
302362a97a2db566c5c65b875388db7cce246355faa72f15b486111c2f380bf3 AMA99uoErVhGXWKcwwWAe8yyXsTa9CnoUw
869424a50260cca7a7fa475c85e48ddf0e47abb0474df59ee45e72e6b95c8333 ALBYoodV8RYPmthq4GngRkGf3XsFH9DEBc[/font]
Compressed public keys (generates different addresses):
[font=courier]> for i in range(5): print electrum_privkey(secexp,i,0), pubkey_to_address(privtopub(electrum_privkey(secexp,i,0)+‘01’),23)
daa19f768ea1a7bc8e33d83f9401ef237f5164ce39bf8000ec9630d088cec028 Ae1kkNubgx2sjS5AS2pyBy5Z5KTGcUJu1K
c45ad49da1ccb0ba30258902ed3de66af571de7421f9c73ffc0a8c2bde9ca596 ATfpeh24NPJavK9CGakHpkxyxiqmpULvZZ
c31100a56692314248a73f29b767ca252c3847eae15ce5d06e7e7f67a63ee5df AbAThra1Z4DTmgJpeSS9XtbftFRGp4qQVj
302362a97a2db566c5c65b875388db7cce246355faa72f15b486111c2f380bf3 AYRXkLbjGg7a6hyeK9khbPDYuMU8vgYTJK
869424a50260cca7a7fa475c85e48ddf0e47abb0474df59ee45e72e6b95c8333 APTAtL5TGKYdmGebZAQVFy93bPYu9DBQrW[/font]
Wallet import format of the above (note that the magic byte becomes 128+23 = 151). Compressed or uncompressed addresses generated by this are perfectly compatible with primecoind; I checked.
[font=courier]> for i in range(5): print hex_to_b58check(electrum_privkey(secexp,i,0)+‘01’,151)
PTtCoGVHD4sCjDm9YCu8Dw43PhLdjvCa7Q5U1mzNagoRdAupaNGe
PT8uF6DBZBPPf9d6cPXCphShTF7nUfWZ4NKfse8q3JUh32b322Wo
PT6Pz5QvxVVSsNZtUpEntDK3gBKhPiAaPGL38b2vBWKodTiGf76F
PNAnei9WhxN1SbJzUKXJ5nvMmoZXZFcjwHG1iN6Z8RdtievFrtze
PR4pL8K75o5fpbBsgDMpbiGVp4C44eYRGCqC7iN5Q33x1UCyxMpo[/font]
And with PPCoin, just replace 23 with 55 and 151 with 183.
This is still an early work in progress; ideally, with help from others, I’d like to this extended to handle transactions and networking, and serve as a universal altcoin light client. That’s a far-off goal though; better have the more basic features ironed out first. Feel free to provide any suggestions!