I think it may be a bug in python
There is no bug in python, the bug is in your usage of AES. You are using one of the modes that does
not encrypt each block individually so when you encrypt the first block (first 16 bytes) you get the correct result but when you encrypt the second block (second 16 bytes) you get the wrong result. Then you concatenate the two parts and encode it with base58 so your string ends up looking like that.
Use the mode I told you above (ECB) and it should fix your issue.
Learn about AES modes here:
https://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_(ECB)
You can see the data in your base58, the last part is the second block you encrypt which is different:
0142-c0-e957a24a-d357fafb81c71f8375a9a4d0ac02bad5-f6c87c4b459fabe34c0c314b33708ec3
0142-c0-e957a24a-d357fafb81c71f8375a9a4d0ac02bad5-30d5c2d250fed0ce62b993841bb5ccac
Good call! It was just a typo.
I did:
Do AES256Encrypt(block = bitcoinprivkey[16...31] xor derivedhalf1[0...15], key = derivedhalf2), call the 16-byte result encryptedhalf2
when it was supposed to be:
Do AES256Encrypt(block = bitcoinprivkey[16...31] xor derivedhalf1[16...31], key = derivedhalf2), call the 16-byte result encryptedhalf2
Passphrase: TestingOneTwoThree
Encrypted key: 6PRVWUbkzzsbcVac2qwfssoUJAN1Xhrg6bNk8J7Nzm5H7kxEbn2Nh2ZoGg
WIF key: 5KN7MzqK5wt2TP1fQCYyHBtDrXdJuXbUzm4A9rKAteGu3Qi5CVR
HEX key: CBF4B9F70470856BB4F40F80B87EDB90865997FFEE6DF315AB166D713AF433A5
Computed BTC address: 1Jq6MksXQVWzrznvZzxkV6oY57oWXD9TXB
Encryption steps:
1. Compute the Bitcoin address (ASCII), and take the first four bytes of SHA256(SHA256()) of it. Let's call this addresshash.
addresshash is b'\xe9W\xa2J'
Function name: normalize_string using unicodedata.normalize package
-------------------------
2. Derive a key from the passphrase using scrypt
Parameters: passphrase is the passphrase itself encoded in UTF-8 and normalized using Unicode Normalization Form C (NFC). salt is addresshash from the earlier step, n=16384, r=8, p=8, length=64 (n, r, p are provisional and subject to consensus)
scrypt = b'\xf8vH\xa6\xb4/\xdd\x86\xefh7\xa2I\xcd\xe1S\x18\xf2d\xd4:\x85\x9ba\x0ex\xeac\xd5\x1c\xb2\xd3\xe6\x0b\xf4K\xfb)\xd5C\xbb\xa2J\xfc\xcc\xfa\xdb\xfcn\xf91/\xcc\xcfX\x9f\xa5\xea\x13f\xec!\xe4\xc0'
scrypt_hash_hex = f87648a6b42fdd86ef6837a249cde15318f264d43a859b610e78ea63d51cb2d3e60bf44bfb29d54 3bba24afcccfadbfc6ef9312fcccf589fa5ea1366ec21e4c0
Let's split the resulting 64 bytes in half, and call them derivedhalf1 and derivedhalf2.
derivedhalf1 = b'\xf8vH\xa6\xb4/\xdd\x86\xefh7\xa2I\xcd\xe1S\x18\xf2d\xd4:\x85\x9ba\x0ex\xeac\xd5\x1c\xb2\xd3'
derivedhalf2 = b'\xe6\x0b\xf4K\xfb)\xd5C\xbb\xa2J\xfc\xcc\xfa\xdb\xfcn\xf91/\xcc\xcfX\x9f\xa5\xea\x13f\xec!\xe4\xc0'
3. Do AES256Encrypt(block = bitcoinprivkey[0...15] xor derivedhalf1[0...15], key = derivedhalf2), call the 16-byte result encryptedhalf1
key = b'\xe6\x0b\xf4K\xfb)\xd5C\xbb\xa2J\xfc\xcc\xfa\xdb\xfcn\xf91/\xcc\xcfX\x9f\xa5\xea\x13f\xec!\xe4\xc0'
data= 68470520909420510445936813703370586819
encryptedhalf1= b'\xd3W\xfa\xfb\x81\xc7\x1f\x83u\xa9\xa4\xd0\xac\x02\xba\xd5'
4. Do AES256Encrypt(block = bitcoinprivkey[16...31] xor derivedhalf1[16...31], key = derivedhalf2), call the 16-byte result encryptedhalf2
data2= 210910838195062625062692659411739509110
enryptedhalf2= b'\xf6\xc8|KE\x9f\xab\xe3L\x0c1K3p\x8e\xc3'
5. The encrypted private key is the Base58Check-encoded concatenation of the following, which totals 39 bytes without Base58 checksum: 0x01 0x42 + flagbyte + salt + encryptedhalf1 + encryptedhalf2
Using uncompressed address
object_id_prefix= b'\x01B'
flagbyte_byte= b'\xc0'
salt=addresshash= b'\xe9W\xa2J'
private_key_encrypted_bytes= b'\x01B\xc0\xe9W\xa2J\xd3W\xfa\xfb\x81\xc7\x1f\x83u\xa9\xa4\xd0\xac\x02\xba\xd5\xf6\xc8|KE\x9f\xab\xe3L\x0c1K3p\x8e\xc3'
Base 58 encoded encrypted private key
6PRVWUbkzzsbcVac2qwfssoUJAN1Xhrg6bNk8J7Nzm5H7kxEbn2Nh2ZoGg
58
Known encrypted key
6PRVWUbkzzsbcVac2qwfssoUJAN1Xhrg6bNk8J7Nzm5H7kxEbn2Nh2ZoGg
58
SUCCESS keys match
Passphrase: TestingOneTwoThree
Encrypted key: 6PYNKZ1EAgYgmQfmNVamxyXVWHzK5s6DGhwP4J5o44cvXdoY7sRzhtpUeo
WIF key: L44B5gGEpqEDRS9vVPz7QT35jcBG2r3CZwSwQ4fCewXAhAhqGVpP
HEX key: CBF4B9F70470856BB4F40F80B87EDB90865997FFEE6DF315AB166D713AF433A5
Computed BTC address: 164MQi977u9GUteHr4EPH27VkkdxmfCvGW
Encryption steps:
1. Compute the Bitcoin address (ASCII), and take the first four bytes of SHA256(SHA256()) of it. Let's call this addresshash.
addresshash is b'C\xbeAy'
Function name: normalize_string using unicodedata.normalize package
-------------------------
2. Derive a key from the passphrase using scrypt
Parameters: passphrase is the passphrase itself encoded in UTF-8 and normalized using Unicode Normalization Form C (NFC). salt is addresshash from the earlier step, n=16384, r=8, p=8, length=64 (n, r, p are provisional and subject to consensus)
scrypt = b's\x1e\xf3\xc77\xb5]\xf4\x99\x8bD\xfa\x8aTz?8\xdfBM\xa2@\xde8\x9b\x11\xd1\x87[\xa4wg//\xe8\x1b\x052\xb5\x95\x0e>\xa6\xff\xf9,e\xd4g\xaa}\x05Ii\x82\x1d\xe24Oz\x86\xd4%i'
scrypt_hash_hex = 731ef3c737b55df4998b44fa8a547a3f38df424da240de389b11d1875ba477672f2fe81b0532b59 50e3ea6fff92c65d467aa7d054969821de2344f7a86d42569
Let's split the resulting 64 bytes in half, and call them derivedhalf1 and derivedhalf2.
derivedhalf1 = b's\x1e\xf3\xc77\xb5]\xf4\x99\x8bD\xfa\x8aTz?8\xdfBM\xa2@\xde8\x9b\x11\xd1\x87[\xa4wg'
derivedhalf2 = b'//\xe8\x1b\x052\xb5\x95\x0e>\xa6\xff\xf9,e\xd4g\xaa}\x05Ii\x82\x1d\xe24Oz\x86\xd4%i'
3. Do AES256Encrypt(block = bitcoinprivkey[0...15] xor derivedhalf1[0...15], key = derivedhalf2), call the 16-byte result encryptedhalf1
key = b'//\xe8\x1b\x052\xb5\x95\x0e>\xa6\xff\xf9,e\xd4g\xaa}\x05Ii\x82\x1d\xe24Oz\x86\xd4%i'
data= 245794453406607058042499921876840260015
encryptedhalf1= b'p\xe4\xa0\x80_\x15\xa7~\xfcs\x8fy@h\xd8\x83'
4. Do AES256Encrypt(block = bitcoinprivkey[16...31] xor derivedhalf1[16...31], key = derivedhalf2), call the 16-byte result encryptedhalf2
data2= 253253421257611663847159858968675763394
enryptedhalf2= b'|)\x85\xa6\x94_\x7f\xe0\xdb?u\xdc0^\xaf|'
5. The encrypted private key is the Base58Check-encoded concatenation of the following, which totals 39 bytes without Base58 checksum: 0x01 0x42 + flagbyte + salt + encryptedhalf1 + encryptedhalf2
Using compressed address
object_id_prefix= b'\x01B'
flagbyte_byte= b'\xe0'
salt=addresshash= b'C\xbeAy'
private_key_encrypted_bytes= b'\x01B\xe0C\xbeAyp\xe4\xa0\x80_\x15\xa7~\xfcs\x8fy@h\xd8\x83|)\x85\xa6\x94_\x7f\xe0\xdb?u\xdc0^\xaf|'
Base 58 encoded encrypted private key
6PYNKZ1EAgYgmQfmNVamxyXVWHzK5s6DGhwP4J5o44cvXdoY7sRzhtpUeo
58
Known encrypted key
6PYNKZ1EAgYgmQfmNVamxyXVWHzK5s6DGhwP4J5o44cvXdoY7sRzhtpUeo
58
SUCCESS keys match
The good news is i got it working with "No compression, no EC multiply" test vectors 1 and 2 as well as their related "Compression, no EC multiply" counterparts.
The bad news is it doesn't work with "No compression, no EC multiply" Test vector 3. That one uses a strange passphrase.
Passphrase ϓ␀hankey (\u03D2\u0301\u0000\U00010400\U0001F4A9; GREEK UPSILON WITH HOOK, COMBINING ACUTE ACCENT, NULL, DESERET CAPITAL LETTER LONG I, PILE OF POO)
along with the following note:
Note: The non-standard UTF-8 characters in this passphrase should be NFC normalized to result in a passphrase of 0xcf9300f0909080f09f92a9 before further processing
None of that really makes any sense to me. 0xcf9300f0909080f09f92a9 is a hexadecimal number, not a string.
Once again the lack of explanation,documentation, thouroughness in things rears its ugly head. [moderator's note: consecutive posts merged]