def transaction(e, d):
    """
    """
    k = ecc.ecdsa()
    src, dst, dat, lat, mnt, ref = e[:8], e[8:16], e[16:20], e[20:28], e[28:32], e[32:40]
    msg, sig, now = e[:-96], e[-96:], ecc.datint()
    if src not in d.keys() or dst not in d.keys() or src == dst:         return b'Error database'
    dls, dld = d[src][4:], d[dst][4:]
    zx, zd = ecc.b2h(src), ecc.b2h(dst)
    if zx not in d.keys():                                               return b'Error public key'
    k.pt = k.uncompress(ecc.h2b(zx + d[zx]))
    if not k.verify(sig, msg):                                           return b'Error signature'    
    val, bals, bald = ecc.b2i(mnt), balance(src, d), balance(dst, d)
    if val <= 0 or bals - val < -MAXBAL or bald + val > MAXBAL:          return b'Error value'
    os, od = ecc.b2i(d[src][:4]), ecc.b2i(d[dst][:4])
    ns, nd = os + 1, od + 1
    nhs = ecc.z10 if os == 0 else d[src + ecc.i2b(os, 4)][-10:]
    nhd = ecc.z10 if od == 0 else d[dst + ecc.i2b(od, 4)][-10:]
    lst_tot, lst_wlt = ecc.b2i(d[ecc.v1][:8]), ecc.b2i(d[ecc.v1][8:])
    if ecc.b2i(dls) <= now or ecc.b2i(dld) <= now or ecc.b2i(dat) > now: return b'Error deadline'    
    if os > 0:
        dx = src + ecc.i2b(os, 4)
        if len(d[dx]) == NS: dx = d[dx][:12]
        if ecc.b2i(d[dx][8:12]) >= ecc.b2i(dat):                         return b'Wait a minute !'
    nws, nwd = ecc.s2b(bals - val, 4), ecc.s2b(bald + val, 4)
    sm, dm = dst + ecc.i2b(nd, 4) + nws, src + dat + lat + mnt + ref + sig + nwd
    # BEGIN WRITE SECTION
    d[src] = ecc.i2b(ns, 4)  + dls
    d[src  + ecc.i2b(ns, 4)] = sm + hashlib.sha1(src + sm + nhs).digest()[:10]
    d[dst] = ecc.i2b(nd, 4)  + dld
    d[dst  + ecc.i2b(nd, 4)] = dm + hashlib.sha1(dst + dm + nhd).digest()[:10]
    d[ecc.v1] = ecc.i2b(lst_tot + 1, 8) + ecc.i2b(lst_wlt + val, 8)
    # END WRITE SECTION
    return b'TRANSACTION from ' + zx + b' to ' + zd    
Exemple #2
0
 def log(self):
     " Just for debugging "
     print('USER', self.name, 'Raw-balance:', self.bal, 'Said:',
           len(self.ids), 'ids')
     for i, j in enumerate(self.ids):
         print('%02d' % (i + 1), ecc.b2h(j[0][1:]), j[1:])
     print('USER', self.name, 'Heard:', len(self.cts), 'ids')
     for x in self.cts:
         print('  ', ecc.b2h(x[1:]), self.cts[x])
def register(e, d):
    ""
    zid, dl = ecc.b2h(e[:8]), ecc.add1year(ecc.datencode()) if len(d.keys()) == 2 else ecc.z4
    for i in range(1, 16):
        if sum([1 for x in d.keys() if len(x) == 16]) < (16**i)//2: break
    for x in d.keys():
        if len(x) == 16 and x[:i] == zid[:i]:
            return ('COLISION %s [%d] -> re-run generation !' % (zid, i)).encode('UTF-8')
    if zid in d: return b'COLISION!'
    # START WRITING
    d[e[:8]] = ecc.z4 + dl
    d[zid] = ecc.b2h(e[8:])
    # STOP WRITING
    return zid + b' registered'
def candidate(data, d):
    ky, mel , o = data[:48], data[48:], b''
    with dbm.open('mel', 'c') as m:
        if mel not in m:
            o = register(ky, d)
            if o[:8] != b'COLISION': m[mel] = ecc.b2h(ky[:8])
    return o
def phone(db, ip, unik=False):
    """ 
    IO CLIENT:
    Simulate smart-phone with strong authentication 
    Commands:
    l       -> list index of all registered bodies
    r email -> register a new body with a new email
    <num>   -> select <num> as current body
    v       -> verify all the database
    s       -> return server public id
    o       -> return proof of balance at current time, to give to offline objects
    c <num> -> request certificate to <num> or generate certificate for <num>
    p <num> <val> -> pay <num> body <val> amount of leaf
    h       -> display history for current body
    m       -> list all client ids (usually one if flag unik is True)
    b       -> begin counting resource by object
    e       -> end counting resource by object
    """
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    print ('IO Client (Phone)\nType ? for help')
    my = b''
    while True:
        if my == b'': my = get_my('1')
        cmd, req, bmy = input('%s >' % my.decode('UTF-8')), b'', ecc.h2b(my)
        if leaf.reg(re.match('(r|reg|register)\s*(\w{2,20}@\w{2,20}\.\w{2,3})\s*$', cmd)): # 48
            with dbm.open(db, 'c') as d:
                req = genkey(leaf.reg.v.group(2).encode('UTF-8'), unik, d)
        elif re.match('(v|verif|verification)\s*$', cmd): req = b'v'
        elif re.match('(l|ls|list)\s*$',            cmd): req = b'l'
        elif re.match('(s|server)\s*$',             cmd): req = b's'
        elif re.match('(h|hist|history)\s*$',       cmd): req = my
        elif re.match('(o|proof)\s*$',              cmd): req = bmy
        elif re.match('(\?|help)\s*$',              cmd): req = b''; print (__doc__, phone.__doc__)
        elif re.match('(b|begin|start)\s*$',        cmd): req = b''; start_access()
        elif re.match('(e|end|stop)\s*$',           cmd): req = b''; stop_access()
        elif leaf.reg(re.match('(my|)\s*(\d{1,2})\s*$', cmd)): my = get_my(leaf.reg.v.group(2))
        elif leaf.reg(re.match('(p|pay)\s*(\d{1,2})\s+(\d{1,3})\s*$', cmd)): # 136
            with dbm.open(db) as d:
                pld = ecc.i2b(int(leaf.reg.v.group(3)), 4)
                req = gene(bmy, ecc.h2b(get_my(leaf.reg.v.group(2))), pld, d)
        elif leaf.reg(re.match('(c|crt|cert)\s*(\d{1,2})\s*$', cmd)): # len:142
            with dbm.open(db) as d:
                req = gene(bmy, ecc.h2b(get_my(leaf.reg.v.group(2))), ecc.z10, d)
        elif re.match('(m|my)\s*$',                 cmd):
            with dbm.open(db) as d:
                for x in d.keys(): print (ecc.b2h(x).decode('UTF-8'))
            req = b''
        elif re.match('(q|quit)\s*$',               cmd):
            s.close()
            break
        if req:
            s.sendto(req, (ip, PORT1))
            data, addr = s.recvfrom(2048)
            if data:
                print (data.decode('UTF-8'))
                if   req == b'l':
                    with open('lpub',  'w') as f: f.write(data.decode('UTF-8'))
                elif req == bmy:
                    with open('proof', 'w') as f: f.write(data.decode('UTF-8'))
def proof(x, d):
    ""
    if b'SERVER' in d.keys():
        k = ecc.ecdsa()
        pk, sk = d[b'SERVER'][:48], d[b'SERVER'][48:]
        k.pt, k.privkey = k.uncompress(pk), ecc.b2i(sk)
        dat = ecc.datdecode(ecc.datencode()).encode('UTF-8')
        msg = b'%s %d %s' % (ecc.b2h(x), balance(x, d), dat)
        return ecc.z85encode(k.sign(msg)) + msg if not verif(d) else b'error'
    return b''
def certificate(e, d):
    """
    A(green) if first
    B->A if A(green)B(red)    then B(orange)
    A->B if A(green)B(orange) then B(green)
    """
    k = ecc.ecdsa()
    src, dst, dat, lat, pld, ref = e[:8], e[8:16], e[16:20], e[20:28], e[28:38], e[38:46]
    msg, sig, now = e[:-96], e[-96:], ecc.datint()
    if ecc.b2i(dat) > now:                                             return b'future date'
    if src not in d.keys() or dst not in d.keys() or src == dst:       return b'Error database'
    zx = ecc.b2h(src)
    if zx not in d.keys():                                             return b'Error public key'
    k.pt = k.uncompress(ecc.h2b(zx + d[zx]))
    if not k.verify(sig, msg):                                         return b'Error signature'
    green, orang, red = ecc.add1year(ecc.datencode()), ecc.datencode(), ecc.z4
    os, od = ecc.b2i(d[src][:4]), ecc.b2i(d[dst][:4])
    ns, nd = os + 1, od + 1
    nhs = ecc.z10 if os == 0 else d[src + ecc.i2b(os, 4)][-10:]
    if os > 0:
        dx = src + ecc.i2b(os, 4)
        if len(d[dx]) == NS: dx = d[dx][:12]
        if ecc.b2i(d[dx][8:12]) >= ecc.b2i(dat):                       return b'Wait a minute !'
    nws = ecc.s2b(balance(src, d), 4)
    sm = dst + dat + lat + pld + ref + sig + nws
    # START WRITING
    if ecc.b2i(d[dst][4:]) > ecc.datint() and d[src][4:] == red:
        d[src] = ecc.i2b(ns, 4) + orang
        d[src  + ecc.i2b(ns, 4)] = sm + hashlib.sha1(src + sm + nhs).digest()[:10]
        d[ecc.v1] = ecc.i2b(ecc.b2i(d[ecc.v1][:8]) + 1, 8) + d[ecc.v1][8:]
        return b'REQUEST by ' + zx
    if ecc.b2i(d[src][4:]) > ecc.datint() and d[dst][4:] != red:
        d[dst] = d[dst][:4] + green
        d[src] = ecc.i2b(ns, 4) + d[src][4:]       
        d[src  + ecc.i2b(ns, 4)] = sm + hashlib.sha1(src + sm + nhs).digest()[:10]
        d[ecc.v1] = ecc.i2b(ecc.b2i(d[ecc.v1][:8]) + 1, 8) + d[ecc.v1][8:16]
        return b'CERTIFICATION by ' + zx
    # STOP WRITING
    else:                                                               return b'Error request'
def history(e, d):
    ""
    x = ecc.h2b(e)
    n = ecc.b2i(d[x][:4])
    o = [e + b' nb: %04d balance: %6d' % (n, balance(x, d))]
    for i in range(n):
        dx = x + ecc.i2b(i+1, 4)
        h, zx, y = ecc.b2i(d[dx][-10:]), ecc.b2h(d[dx][:8]), d[dx]
        bal = ecc.b2s(y[-14:-10], 4)
        if len(y) == NS: dx = d[dx][:12]
        if len(y) == NC: val, sg, dat = 0, b' ', ecc.datdecode(d[dx][8:12])
        elif len(y) == ND:
            val = ecc.b2i(d[dx][20:24])
            dat = ecc.datdecode(d[dx][8:12])
            sg = b'+'
        elif len(y) == NS:
            val = ecc.b2i(d[dx][20:24])
            dat = ecc.datdecode(d[dx][8:12])
            sg = b'-'
        o.append(b'%03d %s%3d %8d H:%020X %s %s' % (i+1, sg, val, bal, h, zx, dat.encode('UTF-8')))
    o.append(b'Balance: %6d' % balance(x, d) )
    return b'\n'.join(o)
def verif(d):
    """
    check certification !
    """
    print ('run check!')
    k = ecc.ecdsa()
    if len(d.keys()) > 0 and ecc.v1 not in d:           return 0x01 # head does not exists 
    wc, wr, tc, tr, al = 0, 0, 0, 0, 0

    lo = []
    for i in [x for x in d.keys() if len(x) == 16]:
        x = ecc.h2b(i)
        if ecc.b2i(d[x][4:]) > ecc.datint(): lo.append(x)
    #print (lo)
    #find the root
    
    for x in d.keys():
        # Length
        lk, lv = len(x), len(d[x])
        if lk == 1: wr, tr = ecc.b2i(d[x][8:16]), ecc.b2i(d[x][:8])
        if lk == 1  and lv != 16:                       return 0x02 # bad length head
        if lk == 5  and lv != 96:                       return 0x03 # bad length server id
        if lk == 8  and lv !=  8:                       return 0x04 # bad length id head 
        if lk == 12 and lv not in (NS, ND, NC):         return 0x05 # bad length operation
        if lk == 16 and lv != 80:                       return 0x06 # bad length pub key
        # Public keys
        if lk == 12:
            if ecc.b2h(x[:8])    not in d:              return 0x07 # src id unknown
            if ecc.b2h(d[x][:8]) not in d:              return 0x08 # dst id unknown 
        if lk == 8:
            # Money supply
            al += balance(x, d)
            # Dates
            dat = ecc.z8
            for i in range(ecc.b2i(d[x][:4])):
                dx = x + ecc.i2b(i+1, 4)
                if len(d[dx]) in (ND, NC):
                    if    d[dx][8:12] <= dat:           return 0x09 # bad date increase
                    dat = d[dx][8:12]
                if len(d[dx]) == ND:
                    if dat > d[x][4:]:                  return 0x0A # invalid date/dead line
            # Signatures
            for i in range(ecc.b2i(d[x][:4])):
                dx = x + ecc.i2b(i+1, 4)
                if len(d[dx]) == NC: src, dst = x,         d[dx][:8]
                if len(d[dx]) == ND: src, dst = d[dx][:8], dx[:8]
                if len(d[dx]) in (NC, ND):
                    zx = ecc.b2h(src)
                    if zx not in d.keys():              return 0x0B # Error public key                    
                    msg, sig = src + dst + d[dx][8:-110], d[dx][-110:-14]
                    k = ecc.ecdsa()
                    k.pt = k.uncompress(ecc.h2b(zx + d[zx]))
                    if not k.verify(sig, msg):          return 0x0C # bad signature
            # Hash
            h = ecc.z10
            for i in range(ecc.b2i(d[x][:4])):
                dx = x + ecc.i2b(i+1, 4)
                h = hashlib.sha1(x + d[dx][:-10] + h).digest()[:10]
                if h != d[dx][-10:]:                    return 0x0D # bad hash
            # Wealth
            for i in range(ecc.b2i(d[x][:4])):
                dx = x + ecc.i2b(i+1, 4)
                if len(d[dx]) == ND: wc += ecc.b2i(d[dx][20:24])       
            # Operations counter
            for i in range(ecc.b2i(d[x][:4])):
                dx = x + ecc.i2b(i+1, 4)
                if len(d[dx]) in (ND, NC): tc += 1
            # Balances
            b = 0
            for i in range(ecc.b2i(d[x][:4])):
                dx = x + ecc.i2b(i+1, 4)
                if dx not in d:                         return 0x0E # missing transaction
                if len(d[dx])   == ND: b += ecc.b2i(d[x + ecc.i2b(i+1, 4)][20:24])
                elif len(d[dx]) == NS: b -= ecc.b2i(d[d[dx][:12]][20:24])
                if b != ecc.b2s(d[dx][-14:-10], 4):     return 0x0F # bad balance
                if b < -MAXBAL or b > MAXBAL:           return 0x10 # Out of bounds
    if wc != wr:                                        return 0x11 # bad wealth
    if tc != tr:                                        return 0x12 # bad counter
    if al != 0:                                         return 0x13 # bad money supply
    return 0 # Everythink ok !