def decrypt(encrypted_privkey, passphrase): # 1. Collect encrypted private key and passphrase from user. # passed as parameters data = enc.b58decode(encrypted_privkey) flagbyte = data[2:3] check = data[-4:] if check != hashlib.sha256(hashlib.sha256(data[:-4]).digest()).digest()[:4]: return False, 'checksum' addresshash = data[3:7] encryptedhalf1 = data[7:23] encryptedhalf2 = data[23:39] #3. Derive decryption key for seedb using scrypt with passpoint, addresshash, and ownersalt key = scrypt.hash(passphrase, addresshash, 16384, 8, 8) derivedhalf1 = key[0:32] derivedhalf2 = key[32:64] #4. Decrypt encryptedpart2 using AES256Decrypt to yield the last 8 bytes of seedb and the last 8 bytes of encryptedpart1. Aes = aes.Aes(derivedhalf2) decryptedhalf2 = Aes.dec(encryptedhalf2) #5. Decrypt encryptedpart1 to yield the remainder of seedb. decryptedhalf1 = Aes.dec(encryptedhalf1) priv = decryptedhalf1 + decryptedhalf2 priv = binascii.unhexlify('%064x' % (long(binascii.hexlify(priv), 16) ^ long(binascii.hexlify(derivedhalf1), 16))) return priv, addresshash
def decrypt(encrypted_privkey, passphrase, p): #1. Collect encrypted private key and passphrase from user. # passed as parameters #2. Derive passfactor using scrypt with ownersalt and the user's passphrase and use it to recompute passpoint d = enc.b58decode(encrypted_privkey) d = d[2:] flagbyte = d[0:1] d = d[1:] addresshash = d[0:4] d = d[4:-4] #3. Derive decryption key for seedb using scrypt with passpoint, addresshash, and ownersalt key = scrypt.hash(passphrase, addresshash, 16384, 8, p) derivedhalf1 = key[0:32] derivedhalf2 = key[32:64] encryptedhalf1 = d[0:16] encryptedhalf2 = d[16:32] #4. Decrypt encryptedpart2 using AES256Decrypt to yield the last 8 bytes of seedb and the last 8 bytes of encryptedpart1. Aes = aes.Aes(derivedhalf2) decryptedhalf2 = Aes.dec(encryptedhalf2) #5. Decrypt encryptedpart1 to yield the remainder of seedb. decryptedhalf1 = Aes.dec(encryptedhalf1) priv = decryptedhalf1 + decryptedhalf2 priv = binascii.unhexlify('%064x' % (long(binascii.hexlify(priv), 16) ^ long(binascii.hexlify(derivedhalf1), 16))) return priv, addresshash
def encrypt(pub_address, passphrase): """ Encrypt the public address """ #1 base 58 decode the public address address = enc.b58decode(pub_address) #2. Take a hash of the decoded address to act as a scrypt salt salt = hashlib.sha256(hashlib.sha256(address).digest()).digest()[:4] #2. Derive a key from the passphrase using scrypt key = scrypt.hash(passphrase, salt, 16384, 8, 8) #3. Split the key into half 1 and half 2 derivedhalf1 = key[0:32] derivedhalf2 = key[32:64] #4 AES encrypt address halves as per bip38 halflength = int(math.floor(len(address) / 2)) Aes = aes.Aes(derivedhalf2) #for Aes encryption, string needs to have length = 16 xorhalf1 = enc.sxor(address[:halflength], derivedhalf1[:16]).ljust(16, '0') xorhalf2 = enc.sxor(address[halflength:], derivedhalf1[16:32]).ljust(16, '0') encryptedhalf1 = Aes.enc(xorhalf1) encryptedhalf2 = Aes.enc(xorhalf2) #5. The encrypted private key is the Base58Check-encoded concatenation of the following # \x78\x8e\xa3\x69\xb6 + address_length + salt + encryptedhalf1 + encryptedhalf2 encAddress = '\x78\x8e\xa3\x69\xb6' + chr(len(address)) + salt + encryptedhalf1 + encryptedhalf2 check = hashlib.sha256(hashlib.sha256(encAddress).digest()).digest()[:4] return enc.b58encode(encAddress + check)
def decrypt(encrypted_privkey, passphrase, p): """ decrypt a bip0038 encrypted private key return the key and address hash for adress verification """ print('Decrypting private key...') #1. Collect encrypted private key and passphrase from user. # passed as parameters #2. Derive passfactor using scrypt with ownersalt and the user's passphrase and use it to recompute passpoint d = enc.b58decode(encrypted_privkey) d = d[2:] flagbyte = d[0:1] d = d[1:] addresshash = d[0:4] d = d[4:-4] #3. Derive decryption key for seedb using scrypt with passpoint, addresshash, and ownersalt key = scrypt.hash(passphrase,addresshash, 16384, 8, p) derivedhalf1 = key[0:32] derivedhalf2 = key[32:64] encryptedhalf1 = d[0:16] encryptedhalf2 = d[16:32] Aes = aes.Aes(derivedhalf2) #4. Decrypt encryptedpart2 using AES256Decrypt to yield the last 8 bytes of seedb and the last 8 bytes of encryptedpart1. decryptedhalf2 = Aes.dec(encryptedhalf2) #5. Decrypt encryptedpart1 to yield the remainder of seedb. decryptedhalf1 = Aes.dec(encryptedhalf1) priv = decryptedhalf1 + decryptedhalf2 priv = binascii.unhexlify('%064x' % (long(binascii.hexlify(priv), 16) ^ long(binascii.hexlify(derivedhalf1), 16))) return priv, addresshash
def encrypt(pub_address, passphrase): """ Encrypt the public address """ #1 base 58 decode the public address address = enc.b58decode(pub_address) #2. Take a hash of the decoded address to act as a scrypt salt salt = hashlib.sha256(hashlib.sha256(address).digest()).digest()[:4] #2. Derive a key from the passphrase using scrypt key = scrypt.hash(passphrase, salt, 16384, 8, 8) #3. Split the key into half 1 and half 2 derivedhalf1 = key[0:32] derivedhalf2 = key[32:64] #4 AES encrypt address halves as per bip38 halflength = int(math.floor(len(address) / 2)) Aes = aes.Aes(derivedhalf2) #for Aes encryption, string needs to have length = 16 xorhalf1 = enc.sxor(address[:halflength], derivedhalf1[:16]).ljust(16, '0') xorhalf2 = enc.sxor(address[halflength:], derivedhalf1[16:32]).ljust(16, '0') encryptedhalf1 = Aes.enc(xorhalf1) encryptedhalf2 = Aes.enc(xorhalf2) #5. The encrypted private key is the Base58Check-encoded concatenation of the following # \x78\x8e\xa3\x69\xb6 + address_length + salt + encryptedhalf1 + encryptedhalf2 encAddress = '\x78\x8e\xa3\x69\xb6' + chr( len(address)) + salt + encryptedhalf1 + encryptedhalf2 check = hashlib.sha256(hashlib.sha256(encAddress).digest()).digest()[:4] return enc.b58encode(encAddress + check)
def confirmcode(confirmationcode, passphrase): """ A confirmation tool, given a passphrase and a confirmation code, can recalculate the address, verify the address hash, and then assert the following: "It is confirmed that Bitcoin address address depends on this passphrase". To recalculate the address: """ #decode the confirmationcode to give addresshash, ownerentropy and encryptedpointb data = enc.b58decode(confirmationcode) checksum = data[-4:] hash = hashlib.sha256(hashlib.sha256(data[:-4]).digest()).digest()[:4] assert hash == checksum addresshash = data[6:10] ownerentropy = data[10:18] encryptedpointb = data[18:51] pointbx1 = encryptedpointb[1:17] pointbx2 = encryptedpointb[17:33] #1. Derive passfactor using scrypt with ownerentropy and the user's passphrase and use it to recompute passpoint passfactor = scrypt.hash(passphrase, ownerentropy, 16384, 8, 8, 32) pub = elip.base10_multiply(elip.G, enc.decode(passfactor, 256)) passpoint = ('0' + str(2 + (pub[1] % 2)) + enc.encode(pub[0], 16, 64)).decode('hex') #2. Derive decryption key for pointb using scrypt with passpoint, addresshash, and ownerentropy key = scrypt.hash(passpoint, addresshash + ownerentropy, 1024, 1, 1, 64) derivedhalf1 = key[0:32] derivedhalf2 = key[32:64] #3. Decrypt encryptedpointb to yield pointb Aes = aes.Aes(derivedhalf2) decryptedhalf1 = Aes.dec(pointbx1) decryptedhalf2 = Aes.dec(pointbx2) pointb = '0' + decryptedhalf1 + decryptedhalf2 pointb = binascii.unhexlify('%064x' % (long(binascii.hexlify(pointb), 16) ^ long(binascii.hexlify(derivedhalf1), 16))) #4. ECMultiply pointb by passfactor. Use the resulting EC point as a public key and hash it into address using either compressed or uncompressed public key # methodology as specified in flagbyte. pub = elip.base10_multiply(pointb, enc.decode(passfactor, 256)) print('pub[0] = ' + str(pub[0])) print('pub[1] = ' + str(pub[1])) publicKey = ('0' + str(2 + (pub[1] % 2)) + enc.encode(pub[0], 16, 64)) print('pubKey = ' + publicKey) generatedaddress = address.publicKey2Address(publicKey) print('generatedaddress = ' + generatedaddress) #print(hashlib.sha256(hashlib.sha256(generatedaddress).digest()).digest()[:4]) #print(addresshash) #assert hashlib.sha256(hashlib.sha256(generatedaddress).digest()).digest()[:4] == addresshash return
def checkChecksum(key): """ requires a base58_Check encoded string. calculates the hash of the key and compare to the checksum """ # decode to base256 checkKey = enc.b58decode(key) checksum = checkKey[-4:] hash = hashlib.sha256(hashlib.sha256(checkKey[:-4]).digest()).digest()[:4] if hash == checksum: return True else: return False
def confirmcode(confirmationcode, passphrase): """ A confirmation tool, given a passphrase and a confirmation code, can recalculate the address, verify the address hash, and then assert the following: "It is confirmed that Bitcoin address address depends on this passphrase". To recalculate the address: """ #decode the confirmationcode to give addresshash, ownerentropy and encryptedpointb data = enc.b58decode(confirmationcode) checksum = data[-4:] hash = hashlib.sha256(hashlib.sha256(data[:-4]).digest()).digest()[:4] assert hash == checksum addresshash = data[6:10] ownerentropy = data[10:18] encryptedpointb = data[18:51] pointbx1 = encryptedpointb[1:17] pointbx2 = encryptedpointb[17:33] #1. Derive passfactor using scrypt with ownerentropy and the user's passphrase and use it to recompute passpoint passfactor = scrypt.hash(passphrase, ownerentropy, 16384, 8, 8, 32) pub = elip.base10_multiply(elip.G, enc.decode(passfactor, 256)) passpoint = ('0' + str(2 + (pub[1] % 2)) + enc.encode(pub[0], 16, 64)).decode('hex') #2. Derive decryption key for pointb using scrypt with passpoint, addresshash, and ownerentropy key = scrypt.hash(passpoint, addresshash + ownerentropy, 1024, 1, 1, 64) derivedhalf1 = key[0:32] derivedhalf2 = key[32:64] #3. Decrypt encryptedpointb to yield pointb Aes = aes.Aes(derivedhalf2) decryptedhalf1 = Aes.dec(pointbx1) decryptedhalf2 = Aes.dec(pointbx2) pointb = '0' + decryptedhalf1 + decryptedhalf2 pointb = binascii.unhexlify('%064x' % (long(binascii.hexlify(pointb), 16) ^ long(binascii.hexlify(derivedhalf1), 16))) #4. ECMultiply pointb by passfactor. Use the resulting EC point as a public key and hash it into address using either compressed or uncompressed public key # methodology as specified in flagbyte. pub = elip.base10_multiply(pointb, enc.decode(passfactor, 256)) print('pub[0] = ' + str(pub[0])) print('pub[1] = ' + str(pub[1])) publicKey = ('0' + str(2 + (pub[1] % 2)) + enc.encode(pub[0], 16, 64)) print('pubKey = ' + publicKey) generatedaddress = address.publicKey2Address(publicKey) print('generatedaddress = ' + generatedaddress) #print(hashlib.sha256(hashlib.sha256(generatedaddress).digest()).digest()[:4]) #print(addresshash) #assert hashlib.sha256(hashlib.sha256(generatedaddress).digest()).digest()[:4] == addresshash return
def decrypt(encSeed, passphrase): """ Decrypt an Electrum seed encrypted with the above method """ #1. Base 58 decrypt the encrypted key # get the two encrypted halves, the check and the salt decSeed = enc.b58decode(encSeed) check = decSeed[-4:] #check that it's not been tampered with if check != hashlib.sha256(hashlib.sha256( decSeed[:-4]).digest()).digest()[:4]: return False, 'checksum' salt = decSeed[4:8] encryptedhalfs = decSeed[8:len(decSeed) - 4] encryptedhalf1 = encryptedhalfs[0:int(math.floor(len(encryptedhalfs) / 2))] encryptedhalf2 = encryptedhalfs[int(math.floor(len(encryptedhalfs) / 2)):] #2. Derive the decryption key using scrypt key = scrypt.hash(passphrase, salt, 16384, 8, 8) derivedhalf1 = key[0:32] derivedhalf2 = key[32:64] #3. Decrypt the encrypted halves Aes = aes.Aes(derivedhalf2) decryptedhalf1 = Aes.dec(encryptedhalf1) decryptedhalf2 = Aes.dec(encryptedhalf2) #4 . xor them with the two halves of derivedhalf1 to get the original values half1 = enc.sxor(decryptedhalf1, derivedhalf1[:16]) half2 = enc.sxor(decryptedhalf2, derivedhalf1[16:32]) #5. build the seed and check it against the check hash seed = half1 + half2 if salt != hashlib.sha256(hashlib.sha256(seed).digest()).digest()[:4]: return False, 'salt' #6. encode the seed as an Electrum Mnemonic list mn = mn_encode(str(seed)) #6 . return the mnemonic as a single string seed = '' for word in mn: seed += word + ' ' return True, seed
def decrypt(encSeed, passphrase): """ Decrypt an Electrum seed encrypted with the above method """ #1. Base 58 decrypt the encrypted key # get the two encrypted halves, the check and the salt decSeed = enc.b58decode(encSeed) check = decSeed[-4:] #check that it's not been tampered with if check != hashlib.sha256(hashlib.sha256(decSeed[:-4]).digest()).digest()[:4]: return False, 'checksum' salt = decSeed[4:8] encryptedhalfs = decSeed[8:len(decSeed)-4] encryptedhalf1 = encryptedhalfs[0:int(math.floor(len(encryptedhalfs) / 2))] encryptedhalf2 = encryptedhalfs[int(math.floor(len(encryptedhalfs) / 2)):] #2. Derive the decryption key using scrypt key = scrypt.hash(passphrase, salt, 16384, 8, 8) derivedhalf1 = key[0:32] derivedhalf2 = key[32:64] #3. Decrypt the encrypted halves Aes = aes.Aes(derivedhalf2) decryptedhalf1 = Aes.dec(encryptedhalf1) decryptedhalf2 = Aes.dec(encryptedhalf2) #4 . xor them with the two halves of derivedhalf1 to get the original values half1 = enc.sxor(decryptedhalf1, derivedhalf1[:16]) half2 = enc.sxor(decryptedhalf2, derivedhalf1[16:32]) #5. build the seed and check it against the check hash seed = half1 + half2 if salt != hashlib.sha256(hashlib.sha256(seed).digest()).digest()[:4]: return False, 'salt' #6. encode the seed as an Electrum Mnemonic list mn = mn_encode(str(seed)) #6 . return the mnemonic as a single string seed = '' for word in mn: seed += word + ' ' return True, seed
def decrypt(enc_address, passphrase): """ Decrypt an Public Address encrypted with the above method """ #1. Base 58 decrypt the encrypted key # get the two encrypted halves, the check and the salt dec_address = enc.b58decode(enc_address) check = dec_address[-4:] #check that it's not been tampered with if check != hashlib.sha256(hashlib.sha256( dec_address[:-4]).digest()).digest()[:4]: return False, 'checksum' length = ord(dec_address[5:6]) halflength = int(math.floor(length / 2)) salt = dec_address[6:10] encryptedhalfs = dec_address[10:len(dec_address) - 4] encryptedhalf1 = encryptedhalfs[:16] encryptedhalf2 = encryptedhalfs[16:] #2. Derive the decryption key using scrypt key = scrypt.hash(passphrase, salt, 16384, 8, 8) derivedhalf1 = key[0:32] derivedhalf2 = key[32:64] #3. Aes decrypt the encrypted halves Aes = aes.Aes(derivedhalf2) xorhalf1 = Aes.dec(encryptedhalf1) xorhalf2 = Aes.dec(encryptedhalf2) #4 . xor them with the two halves of derivedhalf1 to get the original values half1 = enc.sxor(xorhalf1[:halflength], derivedhalf1[:16]) half2 = enc.sxor(xorhalf2[:(length - halflength)], derivedhalf1[16:32]) #5. build the address and check it against the check hash pub_address = half1 + half2 if salt != hashlib.sha256( hashlib.sha256(pub_address).digest()).digest()[:4]: return False, 'salt' #6. return the address as a single string return True, enc.b58encode(pub_address)
def decrypt(enc_address, passphrase): """ Decrypt an Public Address encrypted with the above method """ #1. Base 58 decrypt the encrypted key # get the two encrypted halves, the check and the salt dec_address = enc.b58decode(enc_address) check = dec_address[-4:] #check that it's not been tampered with if check != hashlib.sha256(hashlib.sha256(dec_address[:-4]).digest()).digest()[:4]: return False, 'checksum' length = ord(dec_address[5:6]) halflength = int(math.floor(length / 2)) salt = dec_address[6:10] encryptedhalfs = dec_address[10:len(dec_address) - 4] encryptedhalf1 = encryptedhalfs[:16] encryptedhalf2 = encryptedhalfs[16:] #2. Derive the decryption key using scrypt key = scrypt.hash(passphrase, salt, 16384, 8, 8) derivedhalf1 = key[0:32] derivedhalf2 = key[32:64] #3. Aes decrypt the encrypted halves Aes = aes.Aes(derivedhalf2) xorhalf1 = Aes.dec(encryptedhalf1) xorhalf2 = Aes.dec(encryptedhalf2) #4 . xor them with the two halves of derivedhalf1 to get the original values half1 = enc.sxor(xorhalf1[:halflength], derivedhalf1[:16]) half2 = enc.sxor(xorhalf2[:(length - halflength)], derivedhalf1[16:32]) #5. build the address and check it against the check hash pub_address = half1 + half2 if salt != hashlib.sha256(hashlib.sha256(pub_address).digest()).digest()[:4]: return False, 'salt' #6. return the address as a single string return True, enc.b58encode(pub_address)
def intermediate2privK(intermediate_passphrase_string): """ Steps to create new encrypted private keys given intermediate_passphrase_string from owner (so we have ownerentropy, and passpoint, but we do not have passfactor or the passphrase): """ #get ownerentropy and passpoint from the intermediate key #check the checksum en route decstring = enc.b58decode(intermediate_passphrase_string) checksum = decstring[-4:] if checksum != hashlib.sha256(hashlib.sha256(decstring[:-4]).digest()).digest()[:4]: return False, 'checksum' decodedstring = decstring[:-4] ownerentropy = decodedstring[8:16] passpoint = decodedstring[-33:] print(passpoint) #1. Set flagbyte. #Turn on bit 0x20 if the Bitcoin address will be formed by hashing the compressed public key (optional, saves space, but many Bitcoin implementations aren't compatible with it) #Turn on bit 0x04 if ownerentropy contains a value for lotsequence. #(While it has no effect on the keypair generation process, the decryption process needs this flag to know how to process ownerentropy) flagbyte = chr(0b00100000) # 00 EC 1 compressed 00 future 0 has no lotsequence 00 future #2. Generate 24 random bytes, call this seedb. Take SHA256(SHA256(seedb)) to yield 32 bytes, call this factorb. seedb = os.urandom(24) seedb = b'ABCDEFGHIJKLMNOPQRSTUVWX' #seedb = bytearray(b'ABCDEFGHIJKLMNOPQRSTUVWX') #for c in seedb: print(c) factorb = hashlib.sha256(hashlib.sha256(seedb).digest()).digest() #3. ECMultiply passpoint by factorb. pub = elip.base10_multiply(enc.decode(passpoint, 256), enc.decode(factorb, 256)) #4. Use the resulting EC point as a public key and hash it into a Bitcoin address using either compressed or uncompressed public key methodology # (specify which methodology is used inside flagbyte). # This is the generated Bitcoin address, call it generatedaddress. publicKey = ('0' + str(2 + (pub[1] % 2)) + enc.encode(pub[0], 16, 64)) generatedaddress = address.publicKey2Address(publicKey) ## TODO Remember to add in the currency details here #5. Take the first four bytes of SHA256(SHA256(generatedaddress)) and call it addresshash. addresshash = hashlib.sha256(hashlib.sha256(generatedaddress).digest()).digest()[:4] #6. Now we will encrypt seedb. Derive a second key from passpoint using scrypt #Parameters: passphrase is passpoint provided from the first party (expressed in binary as 33 bytes). # salt is addresshash + ownerentropy, n=1024, r=1, p=1, length=64. The "+" operator is concatenation. encseedb = scrypt.hash(passpoint, addresshash + ownerentropy, 1024, 1, 1, 64) #7. Split the result into two 32-byte halves and call them derivedhalf1 and derivedhalf2. derivedhalf1 = encseedb[0:32] derivedhalf2 = encseedb[32:64] #8. Do AES256Encrypt(seedb[0...15] xor derivedhalf1[0...15], derivedhalf2), call the 16-byte result encryptedpart1 Aes = aes.Aes(derivedhalf2) encryptedpart1 = Aes.enc(enc.sxor(seedb[:16], derivedhalf1[:16])) #9. Do AES256Encrypt((encryptedpart1[8...15] + seedb[16...23]) xor derivedhalf1[16...31], derivedhalf2), call the 16-byte result encryptedpart2. # The "+" operator is concatenation. encryptedpart2 = Aes.enc(enc.sxor(encryptedpart1[8:16] + seedb[16:24], derivedhalf1[16:32])) #10. The encrypted private key is the Base58Check-encoded concatenation of the following, which totals 39 bytes without Base58 checksum: #0x01 0x43 + flagbyte + addresshash + ownerentropy + encryptedpart1[0...7] + encryptedpart2 input = '\x01\x43' + flagbyte + addresshash + ownerentropy + encryptedpart1[0:8] + encryptedpart2 checksum = hashlib.sha256(hashlib.sha256(input).digest()).digest()[:4] BIPKey = enc.b58encode(input + checksum) cnfrmcode = confirmationcode(flagbyte, addresshash, ownerentropy, factorb, derivedhalf1, derivedhalf2) return BIPKey, generatedaddress, cnfrmcode
def intermediate2privK(intermediate_passphrase_string): """ Steps to create new encrypted private keys given intermediate_passphrase_string from owner (so we have ownerentropy, and passpoint, but we do not have passfactor or the passphrase): """ #get ownerentropy and passpoint from the intermediate key #check the checksum en route decstring = enc.b58decode(intermediate_passphrase_string) checksum = decstring[-4:] if checksum != hashlib.sha256(hashlib.sha256( decstring[:-4]).digest()).digest()[:4]: return False, 'checksum' decodedstring = decstring[:-4] ownerentropy = decodedstring[8:16] passpoint = decodedstring[-33:] print(passpoint) #1. Set flagbyte. #Turn on bit 0x20 if the Bitcoin address will be formed by hashing the compressed public key (optional, saves space, but many Bitcoin implementations aren't compatible with it) #Turn on bit 0x04 if ownerentropy contains a value for lotsequence. #(While it has no effect on the keypair generation process, the decryption process needs this flag to know how to process ownerentropy) flagbyte = chr( 0b00100000 ) # 00 EC 1 compressed 00 future 0 has no lotsequence 00 future #2. Generate 24 random bytes, call this seedb. Take SHA256(SHA256(seedb)) to yield 32 bytes, call this factorb. seedb = os.urandom(24) seedb = b'ABCDEFGHIJKLMNOPQRSTUVWX' #seedb = bytearray(b'ABCDEFGHIJKLMNOPQRSTUVWX') #for c in seedb: print(c) factorb = hashlib.sha256(hashlib.sha256(seedb).digest()).digest() #3. ECMultiply passpoint by factorb. pub = elip.base10_multiply(enc.decode(passpoint, 256), enc.decode(factorb, 256)) #4. Use the resulting EC point as a public key and hash it into a Bitcoin address using either compressed or uncompressed public key methodology # (specify which methodology is used inside flagbyte). # This is the generated Bitcoin address, call it generatedaddress. publicKey = ('0' + str(2 + (pub[1] % 2)) + enc.encode(pub[0], 16, 64)) generatedaddress = address.publicKey2Address( publicKey) ## TODO Remember to add in the currency details here #5. Take the first four bytes of SHA256(SHA256(generatedaddress)) and call it addresshash. addresshash = hashlib.sha256( hashlib.sha256(generatedaddress).digest()).digest()[:4] #6. Now we will encrypt seedb. Derive a second key from passpoint using scrypt #Parameters: passphrase is passpoint provided from the first party (expressed in binary as 33 bytes). # salt is addresshash + ownerentropy, n=1024, r=1, p=1, length=64. The "+" operator is concatenation. encseedb = scrypt.hash(passpoint, addresshash + ownerentropy, 1024, 1, 1, 64) #7. Split the result into two 32-byte halves and call them derivedhalf1 and derivedhalf2. derivedhalf1 = encseedb[0:32] derivedhalf2 = encseedb[32:64] #8. Do AES256Encrypt(seedb[0...15] xor derivedhalf1[0...15], derivedhalf2), call the 16-byte result encryptedpart1 Aes = aes.Aes(derivedhalf2) encryptedpart1 = Aes.enc(enc.sxor(seedb[:16], derivedhalf1[:16])) #9. Do AES256Encrypt((encryptedpart1[8...15] + seedb[16...23]) xor derivedhalf1[16...31], derivedhalf2), call the 16-byte result encryptedpart2. # The "+" operator is concatenation. encryptedpart2 = Aes.enc( enc.sxor(encryptedpart1[8:16] + seedb[16:24], derivedhalf1[16:32])) #10. The encrypted private key is the Base58Check-encoded concatenation of the following, which totals 39 bytes without Base58 checksum: #0x01 0x43 + flagbyte + addresshash + ownerentropy + encryptedpart1[0...7] + encryptedpart2 input = '\x01\x43' + flagbyte + addresshash + ownerentropy + encryptedpart1[ 0:8] + encryptedpart2 checksum = hashlib.sha256(hashlib.sha256(input).digest()).digest()[:4] BIPKey = enc.b58encode(input + checksum) cnfrmcode = confirmationcode(flagbyte, addresshash, ownerentropy, factorb, derivedhalf1, derivedhalf2) return BIPKey, generatedaddress, cnfrmcode