URI: 
       tseparate bitcoin related functions from wallet.py - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 5717b43661be2b0616528911b8919f1852139a57
   DIR parent 728ae0d1848ee975c466ca939f9cdd0d39153114
  HTML Author: thomasv <thomasv@gitorious>
       Date:   Fri, 19 Oct 2012 14:55:01 +0200
       
       separate bitcoin related functions from wallet.py
       
       Diffstat:
         M lib/__init__.py                     |       1 +
         A lib/bitcoin.py                      |     211 +++++++++++++++++++++++++++++++
         M lib/util.py                         |      27 +++++++++++++++++++++++++--
         M lib/wallet.py                       |     219 +------------------------------
         M scripts/validate_tx                 |      12 +-----------
         M setup.py                            |       1 +
       
       6 files changed, 242 insertions(+), 229 deletions(-)
       ---
   DIR diff --git a/lib/__init__.py b/lib/__init__.py
       t@@ -1,3 +1,4 @@
        from wallet import Wallet, format_satoshis
        from interface import WalletSynchronizer, Interface, pick_random_server, DEFAULT_SERVERS
        from simple_config import SimpleConfig
       +import bitcoin
   DIR diff --git a/lib/bitcoin.py b/lib/bitcoin.py
       t@@ -0,0 +1,211 @@
       +#!/usr/bin/env python
       +#
       +# Electrum - lightweight Bitcoin client
       +# Copyright (C) 2011 thomasv@gitorious
       +#
       +# This program is free software: you can redistribute it and/or modify
       +# it under the terms of the GNU General Public License as published by
       +# the Free Software Foundation, either version 3 of the License, or
       +# (at your option) any later version.
       +#
       +# This program is distributed in the hope that it will be useful,
       +# but WITHOUT ANY WARRANTY; without even the implied warranty of
       +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
       +# GNU General Public License for more details.
       +#
       +# You should have received a copy of the GNU General Public License
       +# along with this program. If not, see <http://www.gnu.org/licenses/>.
       +
       +
       +import hashlib, base64, ecdsa, re
       +
       +
       +def rev_hex(s):
       +    return s.decode('hex')[::-1].encode('hex')
       +
       +def int_to_hex(i, length=1):
       +    s = hex(i)[2:].rstrip('L')
       +    s = "0"*(2*length - len(s)) + s
       +    return rev_hex(s)
       +
       +
       +def Hash(data):
       +    return hashlib.sha256(hashlib.sha256(data).digest()).digest()
       +
       +
       +############ functions from pywallet ##################### 
       +
       +addrtype = 0
       +
       +def hash_160(public_key):
       +    try:
       +        md = hashlib.new('ripemd160')
       +        md.update(hashlib.sha256(public_key).digest())
       +        return md.digest()
       +    except:
       +        import ripemd
       +        md = ripemd.new(hashlib.sha256(public_key).digest())
       +        return md.digest()
       +
       +
       +def public_key_to_bc_address(public_key):
       +    h160 = hash_160(public_key)
       +    return hash_160_to_bc_address(h160)
       +
       +def hash_160_to_bc_address(h160):
       +    vh160 = chr(addrtype) + h160
       +    h = Hash(vh160)
       +    addr = vh160 + h[0:4]
       +    return b58encode(addr)
       +
       +def bc_address_to_hash_160(addr):
       +    bytes = b58decode(addr, 25)
       +    return bytes[1:21]
       +
       +def encode_point(pubkey, compressed=False):
       +    order = generator_secp256k1.order()
       +    p = pubkey.pubkey.point
       +    x_str = ecdsa.util.number_to_string(p.x(), order)
       +    y_str = ecdsa.util.number_to_string(p.y(), order)
       +    if compressed:
       +        return chr(2 + (p.y() & 1)) + x_str
       +    else:
       +        return chr(4) + pubkey.to_string() #x_str + y_str
       +
       +__b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
       +__b58base = len(__b58chars)
       +
       +def b58encode(v):
       +    """ encode v, which is a string of bytes, to base58."""
       +
       +    long_value = 0L
       +    for (i, c) in enumerate(v[::-1]):
       +        long_value += (256**i) * ord(c)
       +
       +    result = ''
       +    while long_value >= __b58base:
       +        div, mod = divmod(long_value, __b58base)
       +        result = __b58chars[mod] + result
       +        long_value = div
       +    result = __b58chars[long_value] + result
       +
       +    # Bitcoin does a little leading-zero-compression:
       +    # leading 0-bytes in the input become leading-1s
       +    nPad = 0
       +    for c in v:
       +        if c == '\0': nPad += 1
       +        else: break
       +
       +    return (__b58chars[0]*nPad) + result
       +
       +def b58decode(v, length):
       +    """ decode v into a string of len bytes."""
       +    long_value = 0L
       +    for (i, c) in enumerate(v[::-1]):
       +        long_value += __b58chars.find(c) * (__b58base**i)
       +
       +    result = ''
       +    while long_value >= 256:
       +        div, mod = divmod(long_value, 256)
       +        result = chr(mod) + result
       +        long_value = div
       +    result = chr(long_value) + result
       +
       +    nPad = 0
       +    for c in v:
       +        if c == __b58chars[0]: nPad += 1
       +        else: break
       +
       +    result = chr(0)*nPad + result
       +    if length is not None and len(result) != length:
       +        return None
       +
       +    return result
       +
       +
       +def EncodeBase58Check(vchIn):
       +    hash = Hash(vchIn)
       +    return b58encode(vchIn + hash[0:4])
       +
       +def DecodeBase58Check(psz):
       +    vchRet = b58decode(psz, None)
       +    key = vchRet[0:-4]
       +    csum = vchRet[-4:]
       +    hash = Hash(key)
       +    cs32 = hash[0:4]
       +    if cs32 != csum:
       +        return None
       +    else:
       +        return key
       +
       +def PrivKeyToSecret(privkey):
       +    return privkey[9:9+32]
       +
       +def SecretToASecret(secret):
       +    vchIn = chr(addrtype+128) + secret
       +    return EncodeBase58Check(vchIn)
       +
       +def ASecretToSecret(key):
       +    vch = DecodeBase58Check(key)
       +    if vch and vch[0] == chr(addrtype+128):
       +        return vch[1:]
       +    else:
       +        return False
       +
       +########### end pywallet functions #######################
       +
       +# secp256k1, http://www.oid-info.com/get/1.3.132.0.10
       +_p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2FL
       +_r = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141L
       +_b = 0x0000000000000000000000000000000000000000000000000000000000000007L
       +_a = 0x0000000000000000000000000000000000000000000000000000000000000000L
       +_Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798L
       +_Gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8L
       +curve_secp256k1 = ecdsa.ellipticcurve.CurveFp( _p, _a, _b )
       +generator_secp256k1 = ecdsa.ellipticcurve.Point( curve_secp256k1, _Gx, _Gy, _r )
       +oid_secp256k1 = (1,3,132,0,10)
       +SECP256k1 = ecdsa.curves.Curve("SECP256k1", curve_secp256k1, generator_secp256k1, oid_secp256k1 ) 
       +
       +
       +def filter(s): 
       +    out = re.sub('( [^\n]*|)\n','',s)
       +    out = out.replace(' ','')
       +    out = out.replace('\n','')
       +    return out
       +
       +def raw_tx( inputs, outputs, for_sig = None ):
       +    s  = int_to_hex(1,4)                                     +   '     version\n' 
       +    s += int_to_hex( len(inputs) )                           +   '     number of inputs\n'
       +    for i in range(len(inputs)):
       +        _, _, p_hash, p_index, p_script, pubkey, sig = inputs[i]
       +        s += p_hash.decode('hex')[::-1].encode('hex')        +  '     prev hash\n'
       +        s += int_to_hex(p_index,4)                           +  '     prev index\n'
       +        if for_sig is None:
       +            sig = sig + chr(1)                               # hashtype
       +            script  = int_to_hex( len(sig))                  +  '     push %d bytes\n'%len(sig)
       +            script += sig.encode('hex')                      +  '     sig\n'
       +            pubkey = chr(4) + pubkey
       +            script += int_to_hex( len(pubkey))               +  '     push %d bytes\n'%len(pubkey)
       +            script += pubkey.encode('hex')                   +  '     pubkey\n'
       +        elif for_sig==i:
       +            script = p_script                                +  '     scriptsig \n'
       +        else:
       +            script=''
       +        s += int_to_hex( len(filter(script))/2 )             +  '     script length \n'
       +        s += script
       +        s += "ffffffff"                                      +  '     sequence\n'
       +    s += int_to_hex( len(outputs) )                          +  '     number of outputs\n'
       +    for output in outputs:
       +        addr, amount = output
       +        s += int_to_hex( amount, 8)                          +  '     amount: %d\n'%amount 
       +        script = '76a9'                                      # op_dup, op_hash_160
       +        script += '14'                                       # push 0x14 bytes
       +        script += bc_address_to_hash_160(addr).encode('hex')
       +        script += '88ac'                                     # op_equalverify, op_checksig
       +        s += int_to_hex( len(filter(script))/2 )             +  '     script length \n'
       +        s += script                                          +  '     script \n'
       +    s += int_to_hex(0,4)                                     # lock time
       +    if for_sig is not None: s += int_to_hex(1, 4)            # hash type
       +    return s
       +
       +
   DIR diff --git a/lib/util.py b/lib/util.py
       t@@ -1,6 +1,5 @@
       -import os
       +import os, sys
        import platform
       -import sys
        
        def print_error(*args):
            # Stringify args
       t@@ -8,6 +7,7 @@ def print_error(*args):
            sys.stderr.write(" ".join(args) + "\n")
            sys.stderr.flush()
        
       +
        def user_dir():
            if "HOME" in os.environ:
              return os.path.join(os.environ["HOME"], ".electrum")
       t@@ -18,6 +18,7 @@ def user_dir():
            else:
              raise BaseException("No home directory found in environment variables.")
        
       +
        def appdata_dir():
            """Find the path to the application data directory; add an electrum folder and return path."""
            if platform.system() == "Windows":
       t@@ -30,9 +31,11 @@ def appdata_dir():
            else:
                raise Exception("Unknown system")
        
       +
        def get_resource_path(*args):
            return os.path.join(".", *args)
        
       +
        def local_data_dir():
            """Return path to the data folder."""
            assert sys.argv
       t@@ -40,3 +43,23 @@ def local_data_dir():
            local_data = os.path.join(prefix_path, "data")
            return local_data
        
       +
       +def format_satoshis(x, is_diff=False, num_zeros = 0):
       +    from decimal import Decimal
       +    s = Decimal(x)
       +    sign, digits, exp = s.as_tuple()
       +    digits = map(str, digits)
       +    while len(digits) < 9:
       +        digits.insert(0,'0')
       +    digits.insert(-8,'.')
       +    s = ''.join(digits).rstrip('0')
       +    if sign: 
       +        s = '-' + s
       +    elif is_diff:
       +        s = "+" + s
       +
       +    p = s.find('.')
       +    s += "0"*( 1 + num_zeros - ( len(s) - p ))
       +    s += " "*( 9 - ( len(s) - p ))
       +    s = " "*( 5 - ( p )) + s
       +    return s
   DIR diff --git a/lib/wallet.py b/lib/wallet.py
       t@@ -30,233 +30,21 @@ import aes
        import ecdsa
        
        from ecdsa.util import string_to_number, number_to_string
       -from util import print_error
       -from util import user_dir
       -
       -############ functions from pywallet ##################### 
       -
       -addrtype = 0
       -
       -def hash_160(public_key):
       -    try:
       -        md = hashlib.new('ripemd160')
       -        md.update(hashlib.sha256(public_key).digest())
       -        return md.digest()
       -    except:
       -        import ripemd
       -        md = ripemd.new(hashlib.sha256(public_key).digest())
       -        return md.digest()
       -
       -
       -def public_key_to_bc_address(public_key):
       -    h160 = hash_160(public_key)
       -    return hash_160_to_bc_address(h160)
       -
       -def hash_160_to_bc_address(h160):
       -    vh160 = chr(addrtype) + h160
       -    h = Hash(vh160)
       -    addr = vh160 + h[0:4]
       -    return b58encode(addr)
       -
       -def bc_address_to_hash_160(addr):
       -    bytes = b58decode(addr, 25)
       -    return bytes[1:21]
       -
       -def encode_point(pubkey, compressed=False):
       -    order = generator_secp256k1.order()
       -    p = pubkey.pubkey.point
       -    x_str = ecdsa.util.number_to_string(p.x(), order)
       -    y_str = ecdsa.util.number_to_string(p.y(), order)
       -    if compressed:
       -        return chr(2 + (p.y() & 1)) + x_str
       -    else:
       -        return chr(4) + pubkey.to_string() #x_str + y_str
       -
       -__b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
       -__b58base = len(__b58chars)
       -
       -def b58encode(v):
       -    """ encode v, which is a string of bytes, to base58."""
       -
       -    long_value = 0L
       -    for (i, c) in enumerate(v[::-1]):
       -        long_value += (256**i) * ord(c)
       -
       -    result = ''
       -    while long_value >= __b58base:
       -        div, mod = divmod(long_value, __b58base)
       -        result = __b58chars[mod] + result
       -        long_value = div
       -    result = __b58chars[long_value] + result
       -
       -    # Bitcoin does a little leading-zero-compression:
       -    # leading 0-bytes in the input become leading-1s
       -    nPad = 0
       -    for c in v:
       -        if c == '\0': nPad += 1
       -        else: break
       -
       -    return (__b58chars[0]*nPad) + result
       -
       -def b58decode(v, length):
       -    """ decode v into a string of len bytes."""
       -    long_value = 0L
       -    for (i, c) in enumerate(v[::-1]):
       -        long_value += __b58chars.find(c) * (__b58base**i)
       -
       -    result = ''
       -    while long_value >= 256:
       -        div, mod = divmod(long_value, 256)
       -        result = chr(mod) + result
       -        long_value = div
       -    result = chr(long_value) + result
       -
       -    nPad = 0
       -    for c in v:
       -        if c == __b58chars[0]: nPad += 1
       -        else: break
       -
       -    result = chr(0)*nPad + result
       -    if length is not None and len(result) != length:
       -        return None
       -
       -    return result
       -
       -
       -def Hash(data):
       -    return hashlib.sha256(hashlib.sha256(data).digest()).digest()
       -
       -def EncodeBase58Check(vchIn):
       -    hash = Hash(vchIn)
       -    return b58encode(vchIn + hash[0:4])
       -
       -def DecodeBase58Check(psz):
       -    vchRet = b58decode(psz, None)
       -    key = vchRet[0:-4]
       -    csum = vchRet[-4:]
       -    hash = Hash(key)
       -    cs32 = hash[0:4]
       -    if cs32 != csum:
       -        return None
       -    else:
       -        return key
       -
       -def PrivKeyToSecret(privkey):
       -    return privkey[9:9+32]
       -
       -def SecretToASecret(secret):
       -    vchIn = chr(addrtype+128) + secret
       -    return EncodeBase58Check(vchIn)
       -
       -def ASecretToSecret(key):
       -    vch = DecodeBase58Check(key)
       -    if vch and vch[0] == chr(addrtype+128):
       -        return vch[1:]
       -    else:
       -        return False
       -
       -########### end pywallet functions #######################
       -
       +from util import print_error, user_dir, format_satoshis
       +from bitcoin import *
        
        # URL decode
        _ud = re.compile('%([0-9a-hA-H]{2})', re.MULTILINE)
        urldecode = lambda x: _ud.sub(lambda m: chr(int(m.group(1), 16)), x)
        
       -
       -def int_to_hex(i, length=1):
       -    s = hex(i)[2:].rstrip('L')
       -    s = "0"*(2*length - len(s)) + s
       -    return s.decode('hex')[::-1].encode('hex')
       -
       -
       -# AES
       +# AES encryption
        EncodeAES = lambda secret, s: base64.b64encode(aes.encryptData(secret,s))
        DecodeAES = lambda secret, e: aes.decryptData(secret, base64.b64decode(e))
        
        
       -
       -# secp256k1, http://www.oid-info.com/get/1.3.132.0.10
       -_p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2FL
       -_r = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141L
       -_b = 0x0000000000000000000000000000000000000000000000000000000000000007L
       -_a = 0x0000000000000000000000000000000000000000000000000000000000000000L
       -_Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798L
       -_Gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8L
       -curve_secp256k1 = ecdsa.ellipticcurve.CurveFp( _p, _a, _b )
       -generator_secp256k1 = ecdsa.ellipticcurve.Point( curve_secp256k1, _Gx, _Gy, _r )
       -oid_secp256k1 = (1,3,132,0,10)
       -SECP256k1 = ecdsa.curves.Curve("SECP256k1", curve_secp256k1, generator_secp256k1, oid_secp256k1 ) 
       -
       -
       -def filter(s): 
       -    out = re.sub('( [^\n]*|)\n','',s)
       -    out = out.replace(' ','')
       -    out = out.replace('\n','')
       -    return out
       -
       -def raw_tx( inputs, outputs, for_sig = None ):
       -    s  = int_to_hex(1,4)                                     +   '     version\n' 
       -    s += int_to_hex( len(inputs) )                           +   '     number of inputs\n'
       -    for i in range(len(inputs)):
       -        _, _, p_hash, p_index, p_script, pubkey, sig = inputs[i]
       -        s += p_hash.decode('hex')[::-1].encode('hex')        +  '     prev hash\n'
       -        s += int_to_hex(p_index,4)                           +  '     prev index\n'
       -        if for_sig is None:
       -            sig = sig + chr(1)                               # hashtype
       -            script  = int_to_hex( len(sig))                  +  '     push %d bytes\n'%len(sig)
       -            script += sig.encode('hex')                      +  '     sig\n'
       -            pubkey = chr(4) + pubkey
       -            script += int_to_hex( len(pubkey))               +  '     push %d bytes\n'%len(pubkey)
       -            script += pubkey.encode('hex')                   +  '     pubkey\n'
       -        elif for_sig==i:
       -            script = p_script                                +  '     scriptsig \n'
       -        else:
       -            script=''
       -        s += int_to_hex( len(filter(script))/2 )             +  '     script length \n'
       -        s += script
       -        s += "ffffffff"                                      +  '     sequence\n'
       -    s += int_to_hex( len(outputs) )                          +  '     number of outputs\n'
       -    for output in outputs:
       -        addr, amount = output
       -        s += int_to_hex( amount, 8)                          +  '     amount: %d\n'%amount 
       -        script = '76a9'                                      # op_dup, op_hash_160
       -        script += '14'                                       # push 0x14 bytes
       -        script += bc_address_to_hash_160(addr).encode('hex')
       -        script += '88ac'                                     # op_equalverify, op_checksig
       -        s += int_to_hex( len(filter(script))/2 )             +  '     script length \n'
       -        s += script                                          +  '     script \n'
       -    s += int_to_hex(0,4)                                     # lock time
       -    if for_sig is not None: s += int_to_hex(1, 4)            # hash type
       -    return s
       -
       -
       -
       -
       -def format_satoshis(x, is_diff=False, num_zeros = 0):
       -    from decimal import Decimal
       -    s = Decimal(x)
       -    sign, digits, exp = s.as_tuple()
       -    digits = map(str, digits)
       -    while len(digits) < 9:
       -        digits.insert(0,'0')
       -    digits.insert(-8,'.')
       -    s = ''.join(digits).rstrip('0')
       -    if sign: 
       -        s = '-' + s
       -    elif is_diff:
       -        s = "+" + s
       -
       -    p = s.find('.')
       -    s += "0"*( 1 + num_zeros - ( len(s) - p ))
       -    s += " "*( 9 - ( len(s) - p ))
       -    s = " "*( 5 - ( p )) + s
       -    return s
       -
       -
        from version import ELECTRUM_VERSION, SEED_VERSION
        
        
       -
        class Wallet:
            def __init__(self, config={}):
        
       t@@ -285,7 +73,6 @@ class Wallet:
                self.addressbook           = config.get('contacts', [])           # outgoing addresses, for payments
                self.imported_keys         = config.get('imported_keys',{})
        
       -
                # not saved
                self.receipt = None          # next receipt
                self.tx_history = {}
   DIR diff --git a/scripts/validate_tx b/scripts/validate_tx
       t@@ -2,21 +2,11 @@
        
        import sys, hashlib
        from electrum import Interface
       +from electrum.bitcoin import Hash, rev_hex, int_to_hex
        
        """validate a transaction (SPV)"""
        
        
       -Hash = lambda x: hashlib.sha256(hashlib.sha256(x).digest()).digest()
       -
       -def rev_hex(s):
       -    return s.decode('hex')[::-1].encode('hex')
       -
       -def int_to_hex(i, length=1):
       -    s = hex(i)[2:].rstrip('L')
       -    s = "0"*(2*length - len(s)) + s
       -    return rev_hex(s)
       -
       -
        i = Interface({'server':'ecdsa.org:50002:s'})
        i.start()
        
   DIR diff --git a/setup.py b/setup.py
       t@@ -59,6 +59,7 @@ setup(name = "Electrum",
                          'electrum.bmp',
                          'electrum.msqr',
                          'electrum.util',
       +                  'electrum.bitcoin',
                          'electrum.i18n'],
            description = "Lightweight Bitcoin Wallet",
            author = "thomasv",