electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit 5d6496f1f920aa70b129f1e54321ddd59c766b51
parent 8a8aeb456780c016e876526128be1adf7676db9a
Author: thomasv <thomasv@gitorious>
Date:   Fri, 22 Feb 2013 16:17:46 +0100

move crypto from wallet class to bitcoin.py

Diffstat:
Melectrum | 4+++-
Mlib/__init__.py | 2+-
Mlib/bitcoin.py | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib/wallet.py | 69+++++----------------------------------------------------------------
4 files changed, 75 insertions(+), 66 deletions(-)

diff --git a/electrum b/electrum @@ -662,6 +662,7 @@ if __name__ == '__main__': message = ' '.join(args[2:]) if len(args) > 3: print_msg("Warning: Message was reconstructed from several arguments:", repr(message)) + print_msg(wallet.sign_message(address, message, password)) elif cmd == 'verifymessage': @@ -675,8 +676,9 @@ if __name__ == '__main__': sys.exit(1) if len(args) > 4: print_msg("Warning: Message was reconstructed from several arguments:", repr(message)) + EC_KEY.verify_message(address, signature, message) try: - wallet.verify_message(address, signature, message) + EC_KEY.verify_message(address, signature, message) print_msg(True) except BaseException as e: print_error("Verification error: {0}".format(e)) diff --git a/lib/__init__.py b/lib/__init__.py @@ -7,6 +7,6 @@ from verifier import WalletVerifier from interface import Interface, pick_random_server, DEFAULT_SERVERS from simple_config import SimpleConfig import bitcoin -from bitcoin import Transaction +from bitcoin import Transaction, EC_KEY from mnemonic import mn_encode as mnemonic_encode from mnemonic import mn_decode as mnemonic_decode diff --git a/lib/bitcoin.py b/lib/bitcoin.py @@ -273,12 +273,78 @@ 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 ) +from ecdsa.util import string_to_number, number_to_string + +def msg_magic(message): + return "\x18Bitcoin Signed Message:\n" + chr( len(message) ) + message + + class EC_KEY(object): def __init__( self, secret ): self.pubkey = ecdsa.ecdsa.Public_key( generator_secp256k1, generator_secp256k1 * secret ) self.privkey = ecdsa.ecdsa.Private_key( self.pubkey, secret ) self.secret = secret + def sign_message(self, message, compressed, address): + private_key = ecdsa.SigningKey.from_secret_exponent( self.secret, curve = SECP256k1 ) + public_key = private_key.get_verifying_key() + signature = private_key.sign_digest( Hash( msg_magic(message) ), sigencode = ecdsa.util.sigencode_string ) + assert public_key.verify_digest( signature, Hash( msg_magic(message) ), sigdecode = ecdsa.util.sigdecode_string) + for i in range(4): + sig = base64.b64encode( chr(27 + i + (4 if compressed else 0)) + signature ) + try: + self.verify_message( address, sig, message) + return sig + except: + continue + else: + raise BaseException("error: cannot sign message") + + @classmethod + def verify_message(self, address, signature, message): + """ See http://www.secg.org/download/aid-780/sec1-v2.pdf for the math """ + from ecdsa import numbertheory, ellipticcurve, util + import msqr + curve = curve_secp256k1 + G = generator_secp256k1 + order = G.order() + # extract r,s from signature + sig = base64.b64decode(signature) + if len(sig) != 65: raise BaseException("Wrong encoding") + r,s = util.sigdecode_string(sig[1:], order) + nV = ord(sig[0]) + if nV < 27 or nV >= 35: + raise BaseException("Bad encoding") + if nV >= 31: + compressed = True + nV -= 4 + else: + compressed = False + + recid = nV - 27 + # 1.1 + x = r + (recid/2) * order + # 1.3 + alpha = ( x * x * x + curve.a() * x + curve.b() ) % curve.p() + beta = msqr.modular_sqrt(alpha, curve.p()) + y = beta if (beta - recid) % 2 == 0 else curve.p() - beta + # 1.4 the constructor checks that nR is at infinity + R = ellipticcurve.Point(curve, x, y, order) + # 1.5 compute e from message: + h = Hash( msg_magic(message) ) + e = string_to_number(h) + minus_e = -e % order + # 1.6 compute Q = r^-1 (sR - eG) + inv_r = numbertheory.inverse_mod(r,order) + Q = inv_r * ( s * R + minus_e * G ) + public_key = ecdsa.VerifyingKey.from_public_point( Q, curve = SECP256k1 ) + # check that Q is the public key + public_key.verify_digest( sig[1:], h, sigdecode = ecdsa.util.sigdecode_string) + # check that we get the original signing address + addr = public_key_to_bc_address( encode_point(public_key, compressed) ) + if address != addr: + raise BaseException("Bad signature") + ###################################### BIP32 ############################## diff --git a/lib/wallet.py b/lib/wallet.py @@ -216,71 +216,12 @@ class Wallet: return secexp, compressed - def msg_magic(self, message): - return "\x18Bitcoin Signed Message:\n" + chr( len(message) ) + message - def sign_message(self, address, message, password): - secexp, compressed = self.get_private_key(address, password) - private_key = ecdsa.SigningKey.from_secret_exponent( secexp, curve = SECP256k1 ) - public_key = private_key.get_verifying_key() - signature = private_key.sign_digest( Hash( self.msg_magic( message ) ), sigencode = ecdsa.util.sigencode_string ) - assert public_key.verify_digest( signature, Hash( self.msg_magic( message ) ), sigdecode = ecdsa.util.sigdecode_string) - for i in range(4): - sig = base64.b64encode( chr(27 + i + (4 if compressed else 0)) + signature ) - try: - self.verify_message( address, sig, message) - return sig - except: - continue - else: - raise BaseException("error: cannot sign message") - - - def verify_message(self, address, signature, message): - """ See http://www.secg.org/download/aid-780/sec1-v2.pdf for the math """ - from ecdsa import numbertheory, ellipticcurve, util - import msqr - curve = curve_secp256k1 - G = generator_secp256k1 - order = G.order() - # extract r,s from signature - sig = base64.b64decode(signature) - if len(sig) != 65: raise BaseException("Wrong encoding") - r,s = util.sigdecode_string(sig[1:], order) - nV = ord(sig[0]) - if nV < 27 or nV >= 35: - raise BaseException("Bad encoding") - if nV >= 31: - compressed = True - nV -= 4 - else: - compressed = False - - recid = nV - 27 - # 1.1 - x = r + (recid/2) * order - # 1.3 - alpha = ( x * x * x + curve.a() * x + curve.b() ) % curve.p() - beta = msqr.modular_sqrt(alpha, curve.p()) - y = beta if (beta - recid) % 2 == 0 else curve.p() - beta - # 1.4 the constructor checks that nR is at infinity - R = ellipticcurve.Point(curve, x, y, order) - # 1.5 compute e from message: - h = Hash( self.msg_magic( message ) ) - e = string_to_number(h) - minus_e = -e % order - # 1.6 compute Q = r^-1 (sR - eG) - inv_r = numbertheory.inverse_mod(r,order) - Q = inv_r * ( s * R + minus_e * G ) - public_key = ecdsa.VerifyingKey.from_public_point( Q, curve = SECP256k1 ) - # check that Q is the public key - public_key.verify_digest( sig[1:], h, sigdecode = ecdsa.util.sigdecode_string) - # check that we get the original signing address - addr = public_key_to_bc_address( encode_point(public_key, compressed) ) - if address != addr: - raise BaseException("Bad signature") - - + sec = self.get_private_key_base58(address, password) + key = regenerate_key(sec) + compressed = is_compressed(sec) + return key.sign_message(message, compressed, address) + def create_new_address(self, for_change): n = len(self.change_addresses) if for_change else len(self.addresses) address = self.get_new_address(n, for_change)