Skip to content

Instantly share code, notes, and snippets.

@lsparrish
Last active December 15, 2015 09:59
Show Gist options
  • Select an option

  • Save lsparrish/5242810 to your computer and use it in GitHub Desktop.

Select an option

Save lsparrish/5242810 to your computer and use it in GitHub Desktop.
simple, vaguely bitcoin-like program
#==========Bitbrick: a somewhat bitcoin-like program.==========#
# The goal is secure published transactions. Not yet completed.
# So far we have the ability to ensure that a given address has
# enough funds to send based on the sum of past transactions.
# Install Notes:
# Uses dbdict, a recipe from: http://code.activestate.com/recipes/576642-persistent-dict-with-multiple-standard-file-format/
# On Ubuntu the Crypto library can be installed with "sudo apt-get install python-crypto"
# Details:
# Addresses are first 16 chars of a hash of the public key.
# Transaction IDs are first 16 chars of the buyer's signature.
# Receipts are lists of debits and credits that have been applied to each address.
# Buyer is sender, seller is receiver. (May also be donor/recipient.)
# Todo:
# Needs to share transactions, with common starting points (like a genesis block) and so forth.
# Should be able to be infinitely divisible by using multipliers.
# Idea is to make many borrowable fungible currencies that float with
# relation next to each other, with bitbricks acting as the finite-supply
# stable intermediary. There needs to be clean ways to convert/recycle between them.
# Stored needs to be indexed to proof of work.
#===============================#
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto import Random
from time import ctime
from random import random
from dbdict import PersistentDict
from pprint import pprint
#===============================#
def r(): return Random.new().read
def k(): return RSA.generate(1024,r())
def newitem():
key=k(); pkey=key.publickey()
text=pkey.exportKey()
return SHA256.new(text).hexdigest()[:16], key, pkey
def privateaddress(address, key, pkey):
return {address:key.exportKey()}
def publicaddress(address, key, pkey):
return {address:pkey.exportKey()}
def newaddress(d,item):
d['private'].update(privateaddress(*item))
d['public'].update(publicaddress(*item))
d['receipt']['debit'].update({item[0]:[]})
d['receipt']['credit'].update({item[0]:[]})
d['stored'].update({item[0]:0})
def newreciept(transid):
buyer,seller,amount=transinfo(transid)[:3]
d['receipt']['credit'][seller].append(transid)
d['receipt']['debit'][buyer].append(transid)
#---lookup functions---#
def getpkey(address):
text=d['public'][address]
return RSA.importKey(text)
def getkey(address):
text=d['private'][address]
return RSA.importKey(text)
def transinfo(transid):
return d['transaction'][transid][1]
def transbuyer(transid):
return transinfo(transid)[0]
def transseller(transid):
return transinfo(transid)[1]
def transamount(transid):
return transinfo(transid)[2]
#---transaction functions---#
def createtransaction(buyer,seller,amount):
key=getkey(buyer)
transinfo=[buyer,seller,amount,ctime()]
transtext=str(transinfo)
transsig=key.sign(transtext,'')
transid=str(transsig[0])[:16]
return {transid:[transsig,transinfo]}
def addtransaction(buyer,seller,amount):
trans=createtransaction(buyer,seller,amount)
d['transaction'].update(trans)
transid=trans.keys()[0]
newreciept(transid)
return transid
def verifytranssig(transid):
trans=d['transaction'][transid]
transsig=trans[0]
transinfo=trans[1]
pkey=getpkey(transinfo[0])
return pkey.verify(str(transinfo),transsig)
def getstored(address):
amountstored=d['stored'][address]
print "Buyer Address: " + address + " Amount Stored: " + str(amountstored)
return amountstored
def getamounts(address,transtype):
translist=d['receipt'][transtype][address]
total=[]
for transid in translist:
total.append(transamount(transid))
print "Buyer Address: " + str(address) + " Transaction: " + str(transtype) + " Total: " + str(sum(total))
return sum(total)
def verifytransamount(transid):
available=getamounts(transbuyer(transid),'credit')-getamounts(transbuyer(transid),'debit')+getstored(transbuyer(transid))+transamount(transid)
print "Available for transfer: " + str(available)
return available >= transamount(transid)
def verifytransaction(transid):
return verifytranssig(transid) & verifytransamount(transid)
#---publish---#
def sendtrans(transid):
#submit d['transaction'][transid]
#print transinfo(transid) # placeholder
print "Network functionality not implemented yet. Transaction kept locally."
def publishtrans(transid):
# filter function, only sends it out if available is greater than trans amount
if verifytransaction(transid):
print "Enough funds are available. Submitting transaction " + transid + "."
sendtrans(transid)
else:
print "Error: not enough funds available for transaction " + transid + ". Deleting transaction."
deletetrans(transid)
def deletetrans(transid):
trans=d['transaction'].pop(transid)
buyer,seller=trans[1][:2]
d['receipt']['debit'][buyer].remove(transid)
d['receipt']['credit'][seller].remove(transid)
#---test---#
def init():
d=PersistentDict('bitbrick.json',flag='c',format='json');
d={}; # uncomment to start with blank dictionary
if d=={}:
d=PersistentDict('bitbrick.json',flag='c',format='json');
d['private'],d['public'],d['transaction'],d['receipt'],d['stored'] = \
{},{},{},{'credit':{},'debit':{}},{}
return d
d=init()
item=newitem()
newaddress(d,item)
buyer=item[0]
item=newitem()
newaddress(d,item)
seller=item[0]
amount=100
d['stored'][buyer]=100 # give the buyer some stored funds.
# eventually there will be code to make sure stored comes from a proven source
# such as a rare hash or converted currency.
trans=addtransaction(buyer, seller, amount)
publishtrans(trans)
buyer,seller=seller,buyer
trans=addtransaction(buyer, seller, amount)
#publishtrans(trans)
d.close()
def addtransid(d):
# Adding them together makes exact order irrelevant
# as long as everyone has the same set of transactions.
t=0
for value in d['transaction'].values():
t += int(value[0][0])
num = t % pow(16, 16)
print "Checksum of all transaction signatures is: " + str(hex(num)[2:18])
return num
def genhash(d,transsum,nonce):
text = str(transsum + nonce)
hash = SHA256.new(text).hexdigest()[:16]
return hash
def checknonce(d,hash,nonce):
transsum=addtransid(d)
text = str(transsum + nonce)
return hash == genhash(transsum,nonce)
def checktranssum(d,transsum):
addtransid(d) == transsum
def checkwork(hash,number):
return int(hash,16) <= number
def trynonce(d,difficulty):
nonce=int(random()*1000) # random number that gets added to transsum
transsum=addtransid(d)
hash = genhash(d,transsum,nonce)
number=pow(16, 16)/difficulty
print "This time around, " + \
"chance: 1/" + str(difficulty)
print "Result: " + str(checkwork(hash,number))
print "Hash was: " + hash
trynonce(d,4);trynonce(d,4);trynonce(d,4);trynonce(d,4)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment