Search code examples
pythoncryptographypython-2.xpbkdf2scrypt

Algorithm with Scrypt and PBKDF2 - Python


I have tried to reproduce this algorithm on Python

(Double pipes mean to add 0x1 or 0x2 to the passphrase)

s1 = scrypt(key=(passphrase||0x1), salt=(salt||0x1), N=2^18, r=8, p=1, dkLen=32)

s2 = pbkdf2(key=(passphrase||0x2), salt=(salt||0x2), c=2^16, dkLen=32, prf=HMAC_SHA256)

keypair = generate_bitcoin_keypair(s1 ⊕ s2)

And I made this:

s1 = pyscrypt.hash(password=phrase+'\x01', salt=saltPhrase+'\x01', N=16, r=8, p=1, dkLen=32)

s2 = pbkdf2(phrase+'\x02', saltPhrase+'\x02', 1, keylen=32, prf='hmac-sha256')

newWallet = BitcoinKeypair.from_passphrase(''.join(chr(ord(a) ^ ord(b)) for a,b in zip(s1,s2)))

The problem is that it doesn't work properly because it generates this

bitcoin address: 1HvAip4QGWqPJoh8nxLmRAXtbuVj9AKGHq

Wif: 5Kd3D34oALv33x7RMAPrrsNtidZjQekdWHXWGXW6cs2SnRkKUR2

but the correct output is this:

bitcoin address: 1MGKWPZEqJh9JzCPYYsKFEo9w8E2GXmzA7

Wif: 5KXwsERJKvUZde3qHboJFz1gF6B15Xt7TB22bRWoGzgN3FHxqyR

Can someone help me? Thanks.

Here there's the entire code: http://pastebin.com/QL0tQ83v


To use this script you need to install these libraries:

pip install pyscrypt passlib coinkit

Solution

  • This appears to be an implementation of WarpWallet, which is where I guess you are getting your “correct” values. You have two issues.

    Firstly BitcoinKeypair.from_passphrase generates a key from a passphrase, but you have already generated the key yourself, so you don’t need this—you can just use the key you have (you’ll need to import binascii to use hexlify):

    # xor the two subkeys as before.
    key = ''.join(chr(ord(a) ^ ord(b)) for a,b in zip(s1,s2))
    # Convert to a hex string first (coinkit / pybitcoin expects hex
    # rather than raw bytes).
    key_hex = hexlify(key)
    # Create the keypair.
    newWallet = BitcoinKeypair(key_hex)
    

    (Also BitcoinKeypair appears to be deprecated now, perhaps you should look into moving to pybitcoin and BitcoinPrivateKey and BitcoinPublicKey).

    Secondly your work factors in both kdfs are way off. For scrypt it should be 2^18 (you have 16) and for pbkdf2 it should be 2^16 (you have 1).

    Here’s a version that gives the same result as the WarpWallet page (note I am using scrypt here rather than pyscrypt, as pyscrypt wanted to eat my laptop’s entire memory when I fixed the iteration count):

    s1 = scrypt.hash(password=phrase+'\x01', salt=saltPhrase+'\x01', N=1<<18, r=8, p=1, buflen=32)
    s2 = pbkdf2(phrase+'\x02', saltPhrase+'\x02', 1<<16, keylen=32, prf='hmac-sha256')
    
    key = ''.join(chr(ord(a) ^ ord(b)) for a,b in zip(s1,s2))
    key_hex = hexlify(key)
    newWallet = BitcoinKeypair(key_hex)