Blokchain. *Coin. Hot topis for today. The 22nd mission is about blokchain and about coins. SpyCoins. The mission can be found on Stream #49. The SpyCoin center is here: http://gynvael.coldwind.pl/mission022_spycoin/
First failed attempt
I've tried to main SpyCoin. That would be an obvious solution to the challenge. Add a next block with a chunk that would transfer all the coind to the "Secret" account and find bytes that would give the md5-squred a valid "Spy" beginning. That failed miserably. Since it was a block above 138 I meeded to match the begining of the block with "SpyCoinXoXo". Tried to do some scripts like this one:
But after some hours for fruitless searching gave up this approch. I needed a new one..
A brand new chain
What if we could construct a new chain? The script only validaes that the root is the same. And our chain has to be only longer in terms of bytes, it doesn't have to be longer in terms of actual blocks in it. Maybe we can trick it into the beliveing that have have one?
What would would need to do is this:
- Copy the root block into the new one, this is to trick the script that our is a continuation of the current one
- Create a block that will transfer enough (500k) SpyCoins
- Create filler blocks. Blocks that are meaningless for us and ther soil purpose is to create a file big enough so the the script will accept it as a new chain
1 Copy the root block
This part is easy just copy over first
current = open('current_blockchain','rb').read() current = bytearray(current) newone = current[0:0x64+1]
2 Transfer the funds
A bit trickier part. Let's create a helper function that will return a transfer block to the "Secret20" account:
def add_funds(src, amount): secret = struct.pack("8s","Secret20") #add transffers transfer = bytearray() transfer.append(0x03) #type transfer += src.decode('hex') #from transfer += secret #to transfer += struct.pack("I", amount) #amount return transfer
What we do here is creating a bytes that will encode a transfer chunk (type =
0x03) then we specify a source wallet, destination wallet and of course the amount. Having that we can just type:
tr = bytearray() tr += add_funds("626973686f700000", 98830) tr += add_funds("6b61790000000000", 91400) tr += add_funds("627269736f747700", 142487) tr += add_funds("6167656e74393900", 90210) tr += add_funds("646f6e706564726f", 45032) tr += add_funds("6e61746173686100", 500000-98830-91400-142487-90210-45032)
And we have 6 operations that will, if everything is right, transfer 500k SpyCoins to "Secret20" wallet.
What we're missing is a signature of a block. How they are constructed? We're taking a
0x02 chunk with a previous block hash we concatenate it with this block and the md5-squared of that needs to start with "Sp", "Spy" or "SpyCoinXoXo" depending on the block number. So let's do that.
First a useful function:
def find_bytes(block, block_num): found = None for k in range(1,10): if found is not None: break for i in itertools.product(range(255), repeat=k): b = block + (''.join(map(chr,i))) h = block_hash(b) if verify_block(h, block_num): found = (''.join(map(chr,i)),h) break return found
verify_block is taken from the original script. This function is testing all the combinations of bytes (by using
itertools.product) until it find such combination that md5-squared will start with the apprioriate prefix.
With that we just write:
block_num = 1 confirm = current[0x65:0x65+0x12] found = find_bytes(confirm[1:]+tr, block_num) block_num += 1
Append it to the chain we're builing
tr += found confirm = 0x11+len(tr) hash = found newone += confirm newone += tr
Ok, so at this point we have the same root and we have transfer all the necessary funds to the "Secret20" account. What's left? Well now we need to prove our chain is later than the current one but having the size bigger than the size of existing SpyCoin chain.
3 Creating filler blocks
To have the bigger size, we will use the chunk type
while len(newone) < len(current): print 'Newone size: ',len(newone), 'Current: ', len(current) filler = bytearray() filler += '\xff' #size filler += '\x02'+hash filler += '\x00' filler += '\xff'*230 found = find_bytes(filler[1:], block_num) filler += found filler = len(filler)-1 block_num += 1 hash = found newone += filler
No magic here. We add blocks until we know we are bigger. And in each loop we create a block with a given size (starting with
0xff) then we provide a chunk type
0x02 (previous hash) with a hash. After that a chunk type
0x00 with some "random data" and of course some needed bytes so that the hash is correct. After bytes being added, we need to correct the size (
filler = len(filler)-1) and we're done. Rinse & repeat.
Save all the bytes to the new file:
The full script can be found here:
Have fun. I hope this will not have impact on SpyCoin price ;)