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:
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)