bitcoin-cigs 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,9 +1,94 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe BitcoinCigs do
4
- let(:address) { "13C5HZKutjMDeuc7f5mPj6XGpJCZu7xKh2"}
5
- let(:signature) { "H55JIuwEi4YXzINOzx2oU6VsfBcTOScpFtp10pP/M4EWV336ClH65SObwPXnRf/fMXDu8hs8nweB42CtpWgngeM=" }
6
- let(:message) { "aaa" }
4
+ let(:wallet_key) { "5JFZuDkLgbEXK4CUEiXyyz4fUqzAsQ5QUqufdJy8MoLA9S1RdNX" }
5
+ let(:address) { "11o51X3ciSjoLWFN3sbg3yzCM8RSuD2q9" }
6
+ let(:original_address) { "11o51X3ciSjoLWFN3sbg3yzCM8RSuD2q9" }
7
+ let(:private_key) { ["39678A14ECA8479B3C58DCD25A5C94BE768389E823435C4DDFCAEB13519AB10E"].pack('H*') }
8
+ let(:signature) { "HIBYi2g3yFimzD/YSD9j+PYwtsdCuHR2xwIQ6n0AN6RPUVDGttgOmlnsiwx90ZSjmaWrH1/HwrINJbaP7eMA6V4=" }
9
+
10
+ let(:message) { "this is a message" }
11
+
12
+ describe "sign_message!" do
13
+ subject { BitcoinCigs.sign_message!(wallet_key, message) }
14
+
15
+ context "with valid data" do
16
+ it "generates the correct signature" do
17
+ expect(BitcoinCigs.verify_message(address, subject, message)).to be_true
18
+ end
19
+ end
20
+
21
+ context "invalid wallet key" do
22
+ let(:wallet_key) { "invalid wallet key" }
23
+
24
+ it "raises an error" do
25
+ expect { subject }.to raise_error(::BitcoinCigs::Error, "Unknown Wallet Format")
26
+ end
27
+ end
28
+ end
29
+
30
+ describe "sign_message" do
31
+ subject { BitcoinCigs.sign_message(wallet_key, message) }
32
+
33
+ context "with valid data" do
34
+ it "generates the correct signature" do
35
+ expect(BitcoinCigs.verify_message(address, subject, message)).to be_true
36
+ end
37
+ end
38
+
39
+ context "invalid wallet key" do
40
+ let(:wallet_key) { "invalid wallet key" }
41
+
42
+ it "returns nil" do
43
+ expect(subject).to be_nil
44
+ end
45
+ end
46
+ end
47
+
48
+ describe "convert_wallet_format_to_bytes!" do
49
+ subject { BitcoinCigs.convert_wallet_format_to_bytes!(wallet_key) }
50
+
51
+ context "with wallet import format" do
52
+ let(:wallet_key) { "5JFZuDkLgbEXK4CUEiXyyz4fUqzAsQ5QUqufdJy8MoLA9S1RdNX" }
53
+
54
+ it "converts to correct bytes" do
55
+ expect(subject).to eq(private_key)
56
+ end
57
+ end
58
+
59
+ context "with compressed wallet import format" do
60
+ let(:wallet_key) { "Ky9JDVGHsk6gnh7dDYKkWWsAquDLZSrSdtsTVGJjUoVZN7sYjyyP" }
61
+
62
+ it "converts to correct bytes" do
63
+ expect(subject).to eq(private_key)
64
+ end
65
+ end
66
+
67
+ context "with mini format" do
68
+ let(:wallet_key) { "S6c56bnXQiBjk9mqSYE7ykVQ7NzrRy" }
69
+ let(:private_key) { ["4C7A9640C72DC2099F23715D0C8A0D8A35F8906E3CAB61DD3F78B67BF887C9AB"].pack('H*') }
70
+
71
+ it "converts to correct bytes" do
72
+ expect(subject).to eq(private_key)
73
+ end
74
+ end
75
+
76
+ context "with hex format" do
77
+ let(:wallet_key) { "39678A14ECA8479B3C58DCD25A5C94BE768389E823435C4DDFCAEB13519AB10E" }
78
+
79
+ it "converts to correct bytes" do
80
+ expect(subject).to eq(private_key)
81
+ end
82
+ end
83
+
84
+ context "with base 64 format" do
85
+ let(:wallet_key) { "OWeKFOyoR5s8WNzSWlyUvnaDiegjQ1xN38rrE1GasQ4=" }
86
+
87
+ it "converts to correct bytes" do
88
+ expect(subject).to eq(private_key)
89
+ end
90
+ end
91
+ end
7
92
 
8
93
  describe "verify_message!" do
9
94
  subject { BitcoinCigs.verify_message!(address, signature, message) }
@@ -18,7 +103,8 @@ describe BitcoinCigs do
18
103
  let(:address) { "invalid" }
19
104
 
20
105
  it "raises ::BitcoinCigs::Error" do
21
- expect { subject }.to raise_error(::BitcoinCigs::Error, "Bad address. Signing: 13C5HZKutjMDeuc7f5mPj6XGpJCZu7xKh2, Received: invalid")
106
+ # TODO: improve message
107
+ expect { subject }.to raise_error(::BitcoinCigs::Error, "Bad address. Signing: #{original_address}, Received: #{address}")
22
108
  end
23
109
  end
24
110
 
@@ -35,7 +121,7 @@ describe BitcoinCigs do
35
121
 
36
122
  it "raises ::BitcoinCigs::Error" do
37
123
  # TODO: wrong message, also occurs in python version
38
- expect { subject }.to raise_error(::BitcoinCigs::Error, "Bad address. Signing: 1887raouuBL3BJHMxgsGBZAWGqTjBEJP2p, Received: 13C5HZKutjMDeuc7f5mPj6XGpJCZu7xKh2")
124
+ expect { subject }.to raise_error(::BitcoinCigs::Error, "Bad address. Signing: 1Es3JV8zYTMtbg7rPMizYZYPc8rcvsJ21m, Received: #{address}")
39
125
  end
40
126
  end
41
127
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bitcoin-cigs
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-06-02 00:00:00.000000000 Z
12
+ date: 2013-06-06 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -56,17 +56,21 @@ files:
56
56
  - LICENSE.txt
57
57
  - README.md
58
58
  - Rakefile
59
- - bin/jasvet.py
60
59
  - bitcoin-cigs.gemspec
61
60
  - lib/bitcoin-cigs.rb
62
61
  - lib/bitcoin_cigs.rb
63
62
  - lib/bitcoin_cigs/base_58.rb
63
+ - lib/bitcoin_cigs/crypto_helper.rb
64
64
  - lib/bitcoin_cigs/curve_fp.rb
65
+ - lib/bitcoin_cigs/ec_key.rb
65
66
  - lib/bitcoin_cigs/error.rb
66
- - lib/bitcoin_cigs/math_helper.rb
67
67
  - lib/bitcoin_cigs/point.rb
68
+ - lib/bitcoin_cigs/private_key.rb
68
69
  - lib/bitcoin_cigs/public_key.rb
70
+ - lib/bitcoin_cigs/signature.rb
69
71
  - lib/bitcoin_cigs/version.rb
72
+ - misc/bitaddress.org.html
73
+ - misc/jasvet.py
70
74
  - spec/bitcoin_cigs/base_58_spec.rb
71
75
  - spec/bitcoin_cigs_spec.rb
72
76
  - spec/spec_helper.rb
data/bin/jasvet.py DELETED
@@ -1,615 +0,0 @@
1
- #!/usr/bin/env python
2
-
3
- # jackjack's signing/verifying tool
4
- # verifies base64 signatures from Bitcoin
5
- # signs message in three formats:
6
- # - Bitcoin base64 (compatible with Bitcoin)
7
- # - ASCII armored, Clearsign
8
- # - ASCII armored, Base64
9
- #
10
- # Licence: Public domain or CC0
11
-
12
- import time
13
- import hashlib
14
- import random
15
- import base64
16
-
17
- FTVerbose=False
18
-
19
-
20
-
21
- def randomk(): #better make it stronger
22
- rk=0
23
- for i in range(8):
24
- rk=long(random.random()*0xffffffff)<<(32*i)
25
- return rk
26
-
27
- # Common constants/functions for Bitcoin
28
-
29
- def hash_160_to_bc_address(h160, addrtype=0):
30
- vh160 = chr(addrtype) + h160
31
- h = Hash(vh160)
32
- addr = vh160 + h[0:4]
33
- print "b58:::", base64.b64encode(addr), b58encode(addr)
34
- return b58encode(addr)
35
-
36
- def bc_address_to_hash_160(addr):
37
- bytes = b58decode(addr, 25)
38
- return bytes[1:21]
39
-
40
- def Hash(data):
41
- print "HASH", hashlib.sha256(hashlib.sha256(data).digest()).digest()
42
- return hashlib.sha256(hashlib.sha256(data).digest()).digest()
43
-
44
- def sha256(data):
45
- return hashlib.sha256(data).digest()
46
-
47
- def sha1(data):
48
- return hashlib.sha1(data).digest()
49
-
50
- __b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
51
- __b58base = len(__b58chars)
52
-
53
- def b58encode(v):
54
- long_value = 0L
55
- for (i, c) in enumerate(v[::-1]):
56
- long_value += (256**i) * ord(c)
57
-
58
- result = ''
59
- while long_value >= __b58base:
60
- div, mod = divmod(long_value, __b58base)
61
- result = __b58chars[mod] + result
62
- long_value = div
63
- result = __b58chars[long_value] + result
64
-
65
- nPad = 0
66
- for c in v:
67
- if c == '\0': nPad += 1
68
- else: break
69
-
70
- return (__b58chars[0]*nPad) + result
71
-
72
- def b58decode(v, length):
73
- long_value = 0L
74
- for (i, c) in enumerate(v[::-1]):
75
- long_value += __b58chars.find(c) * (__b58base**i)
76
-
77
- result = ''
78
- while long_value >= 256:
79
- div, mod = divmod(long_value, 256)
80
- result = chr(mod) + result
81
- long_value = div
82
- result = chr(long_value) + result
83
-
84
- nPad = 0
85
- for c in v:
86
- if c == __b58chars[0]: nPad += 1
87
- else: break
88
-
89
- result = chr(0)*nPad + result
90
- if length is not None and len(result) != length:
91
- return None
92
-
93
- return result
94
-
95
-
96
- def regenerate_key(sec):
97
- b = ASecretToSecret(sec)
98
- if not b:
99
- return False
100
- b = b[0:32]
101
- secret = int('0x' + b.encode('hex'), 16)
102
- return EC_KEY(secret)
103
-
104
- def GetPubKey(pkey, compressed=False):
105
- return i2o_ECPublicKey(pkey, compressed)
106
-
107
- def GetPrivKey(pkey, compressed=False):
108
- return i2d_ECPrivateKey(pkey, compressed)
109
-
110
- def GetSecret(pkey):
111
- return ('%064x' % pkey.secret).decode('hex')
112
-
113
-
114
- def i2d_ECPrivateKey(pkey, compressed=False):#, crypted=True):
115
- part3='a081a53081a2020101302c06072a8648ce3d0101022100' # for uncompressed keys
116
- if compressed:
117
- if True:#not crypted: ## Bitcoin accepts both part3's for crypted wallets...
118
- part3='a08185308182020101302c06072a8648ce3d0101022100' # for compressed keys
119
- key = '3081d30201010420' + \
120
- '%064x' % pkey.secret + \
121
- part3 + \
122
- '%064x' % _p + \
123
- '3006040100040107042102' + \
124
- '%064x' % _Gx + \
125
- '022100' + \
126
- '%064x' % _r + \
127
- '020101a124032200'
128
- else:
129
- key = '308201130201010420' + \
130
- '%064x' % pkey.secret + \
131
- part3 + \
132
- '%064x' % _p + \
133
- '3006040100040107044104' + \
134
- '%064x' % _Gx + \
135
- '%064x' % _Gy + \
136
- '022100' + \
137
- '%064x' % _r + \
138
- '020101a144034200'
139
-
140
- return key.decode('hex') + i2o_ECPublicKey(pkey, compressed)
141
-
142
- def i2o_ECPublicKey(pkey, compressed=False):
143
- if compressed:
144
- if pkey.pubkey.point.y() & 1:
145
- key = '03' + '%064x' % pkey.pubkey.point.x()
146
- else:
147
- key = '02' + '%064x' % pkey.pubkey.point.x()
148
- else:
149
- key = '04' + \
150
- '%064x' % pkey.pubkey.point.x() + \
151
- '%064x' % pkey.pubkey.point.y()
152
-
153
- return key.decode('hex')
154
-
155
- def hash_160(public_key):
156
- md = hashlib.new('ripemd160')
157
- md.update(hashlib.sha256(public_key).digest())
158
- return md.digest()
159
-
160
- def public_key_to_bc_address(public_key, v=0):
161
- h160 = hash_160(public_key)
162
- return hash_160_to_bc_address(h160, v)
163
-
164
- def inverse_mod( a, m ):
165
- if a < 0 or m <= a: a = a % m
166
- c, d = a, m
167
- uc, vc, ud, vd = 1, 0, 0, 1
168
- while c != 0:
169
- q, c, d = divmod( d, c ) + ( c, )
170
- uc, vc, ud, vd = ud - q*uc, vd - q*vc, uc, vc
171
- assert d == 1
172
- if ud > 0: return ud
173
- else: return ud + m
174
-
175
- class CurveFp( object ):
176
- def __init__( self, p, a, b ):
177
- self.__p = p
178
- self.__a = a
179
- self.__b = b
180
-
181
- def p( self ):
182
- return self.__p
183
-
184
- def a( self ):
185
- return self.__a
186
-
187
- def b( self ):
188
- return self.__b
189
-
190
- def contains_point( self, x, y ):
191
- return ( y * y - ( x * x * x + self.__a * x + self.__b ) ) % self.__p == 0
192
-
193
- class Point( object ):
194
- def __init__( self, curve, x, y, order = None ):
195
- print "JERE", curve, x, y, order
196
- self.__curve = curve
197
- self.__x = x
198
- self.__y = y
199
- self.__order = order
200
- if self.__curve: assert self.__curve.contains_point( x, y )
201
- if order: assert self * order == INFINITY
202
-
203
- def __add__( self, other ):
204
- if other == INFINITY: return self
205
- if self == INFINITY: return other
206
- assert self.__curve == other.__curve
207
- if self.__x == other.__x:
208
- if ( self.__y + other.__y ) % self.__curve.p() == 0:
209
- return INFINITY
210
- else:
211
- return self.double()
212
-
213
- p = self.__curve.p()
214
- l = ( ( other.__y - self.__y ) * \
215
- inverse_mod( other.__x - self.__x, p ) ) % p
216
- x3 = ( l * l - self.__x - other.__x ) % p
217
- y3 = ( l * ( self.__x - x3 ) - self.__y ) % p
218
- return Point( self.__curve, x3, y3 )
219
-
220
- def __mul__( self, other ):
221
- def leftmost_bit( x ):
222
- assert x > 0
223
- result = 1L
224
- while result <= x: result = 2 * result
225
- return result / 2
226
-
227
- print "MULT ARG ", other
228
- e = other
229
- if self.__order: e = e % self.__order
230
- print "EEEE ", e, self.__order
231
- if e == 0: return INFINITY
232
- if self == INFINITY: return INFINITY
233
- assert e > 0
234
- e3 = 3 * e
235
- negative_self = Point( self.__curve, self.__x, -self.__y, self.__order )
236
- i = leftmost_bit( e3 ) / 2
237
- result = self
238
- while i > 1:
239
- result = result.double()
240
- if ( e3 & i ) != 0 and ( e & i ) == 0: result = result + self
241
- if ( e3 & i ) == 0 and ( e & i ) != 0: result = result + negative_self
242
- i = i / 2
243
- return result
244
-
245
- def __rmul__( self, other ):
246
- return self * other
247
-
248
- def __str__( self ):
249
- if self == INFINITY: return "infinity"
250
- return "(%d,%d)" % ( self.__x, self.__y )
251
-
252
- def double( self ):
253
- if self == INFINITY:
254
- return INFINITY
255
-
256
- p = self.__curve.p()
257
- a = self.__curve.a()
258
- l = ( ( 3 * self.__x * self.__x + a ) * \
259
- inverse_mod( 2 * self.__y, p ) ) % p
260
- x3 = ( l * l - 2 * self.__x ) % p
261
- y3 = ( l * ( self.__x - x3 ) - self.__y ) % p
262
- return Point( self.__curve, x3, y3 )
263
-
264
- def x( self ):
265
- return self.__x
266
-
267
- def y( self ):
268
- return self.__y
269
-
270
- def curve( self ):
271
- return self.__curve
272
-
273
- def order( self ):
274
- return self.__order
275
-
276
- INFINITY = Point( None, None, None )
277
-
278
- def str_to_long(b):
279
- res = 0
280
- pos = 1
281
- for a in reversed(b):
282
- res += ord(a) * pos
283
- pos *= 256
284
- return res
285
-
286
- class Public_key( object ):
287
- def __init__( self, generator, point, c ):
288
- self.curve = generator.curve()
289
- self.generator = generator
290
- self.point = point
291
- self.compressed = c
292
- n = generator.order()
293
- if not n:
294
- raise RuntimeError, "Generator point must have order."
295
- if not n * point == INFINITY:
296
- raise RuntimeError, "Generator point order is bad."
297
- if point.x() < 0 or n <= point.x() or point.y() < 0 or n <= point.y():
298
- raise RuntimeError, "Generator point has x or y out of range."
299
-
300
- def verify( self, hash, signature ):
301
- if isinstance(hash, str):
302
- hash=str_to_long(hash)
303
- G = self.generator
304
- n = G.order()
305
- r = signature.r
306
- s = signature.s
307
- if r < 1 or r > n-1: return False
308
- if s < 1 or s > n-1: return False
309
- c = inverse_mod( s, n )
310
- u1 = ( hash * c ) % n
311
- u2 = ( r * c ) % n
312
- xy = u1 * G + u2 * self.point
313
- v = xy.x() % n
314
- return v == r
315
-
316
- def ser(self):
317
- if self.compressed:
318
- if self.point.y() & 1:
319
- key = '03' + '%064x' % self.point.x()
320
- else:
321
- key = '02' + '%064x' % self.point.x()
322
- else:
323
- key = '04' + \
324
- '%064x' % self.point.x() + \
325
- '%064x' % self.point.y()
326
-
327
- return key.decode('hex')
328
-
329
-
330
- class Signature( object ):
331
- def __init__( self, r, s ):
332
- self.r = r
333
- self.s = s
334
-
335
- def ser(self):
336
- return ("%064x%064x"%(self.r,self.s)).decode('hex')
337
-
338
- class Private_key( object ):
339
- def __init__( self, public_key, secret_multiplier ):
340
- self.public_key = public_key
341
- self.secret_multiplier = secret_multiplier
342
-
343
- # def der( self ):
344
- # hex_der_key = '06052b8104000a30740201010420' + \
345
- # '%064x' % self.secret_multiplier + \
346
- # 'a00706052b8104000aa14403420004' + \
347
- # '%064x' % self.public_key.point.x() + \
348
- # '%064x' % self.public_key.point.y()
349
- # return hex_der_key.decode('hex')
350
-
351
- def sign( self, hash, random_k ):
352
- if isinstance(hash, str):
353
- hash=str_to_long(hash)
354
- G = self.public_key.generator
355
- n = G.order()
356
- k = random_k % n
357
- p1 = k * G
358
- r = p1.x()
359
- if r == 0: raise RuntimeError, "amazingly unlucky random number r"
360
- s = ( inverse_mod( k, n ) * \
361
- ( hash + ( self.secret_multiplier * r ) % n ) ) % n
362
- if s == 0: raise RuntimeError, "amazingly unlucky random number s"
363
- return Signature( r, s )
364
-
365
- class EC_KEY(object):
366
- def __init__( self, secret, c=False):
367
- curve = CurveFp( _p, _a, _b )
368
- generator = Point( curve, _Gx, _Gy, _r )
369
- self.pubkey = Public_key( generator, generator * secret, c )
370
- self.privkey = Private_key( self.pubkey, secret )
371
- self.secret = secret
372
-
373
- def format_msg_to_sign(msg):
374
- return "\x18Bitcoin Signed Message:\n"+chr(len(msg))+msg #todo: check 18
375
-
376
- def sqrt_mod(a, p):
377
- return pow(a, (p+1)/4, p)
378
-
379
- _p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2FL
380
- _r = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141L
381
- _b = 0x0000000000000000000000000000000000000000000000000000000000000007L
382
- _a = 0x0000000000000000000000000000000000000000000000000000000000000000L
383
- _Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798L
384
- _Gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8L
385
-
386
- curve_secp256k1 = CurveFp (_p, _a, _b)
387
- generator_secp256k1 = g = Point (curve_secp256k1, _Gx, _Gy, _r)
388
- randrange = random.SystemRandom().randrange
389
-
390
- # Signing/verifying
391
-
392
- def verify_message_Bitcoin(address, signature, message, pureECDSASigning=False):
393
- print "DECODE"
394
- print address
395
- print base64.b64encode(b58decode(address, None))
396
- networkversion=str_to_long(b58decode(address, None)) >> (8*24)
397
- print "COOL"
398
- print str_to_long(b58decode(address, None))
399
- print "NETWORK VERSION"
400
- print networkversion
401
- msg=message
402
- print msg
403
- if not pureECDSASigning:
404
- print "SHIT"
405
- print message
406
- print format_msg_to_sign(message)
407
- msg=Hash(format_msg_to_sign(message))
408
- print msg
409
-
410
- compressed=False
411
- curve = curve_secp256k1
412
- G = generator_secp256k1
413
- _a,_b,_p=curve.a(),curve.b(),curve.p()
414
-
415
- order = G.order()
416
- print "G ORDER ", order
417
- sig = base64.b64decode(signature)
418
- if len(sig) != 65:
419
- raise Exception("vmB","Bad signature")
420
- print "SIG ", sig
421
-
422
- hb = ord(sig[0])
423
- print "hb", hb
424
- r,s = map(str_to_long,[sig[1:33],sig[33:65]])
425
- print "r, s", r, s
426
-
427
- if hb < 27 or hb >= 35:
428
- raise Exception("vmB","Bad first byte")
429
- if hb >= 31:
430
- compressed = True
431
- hb -= 4
432
-
433
- recid = hb - 27
434
- x = (r + (recid/2) * order) % _p
435
- y2 = ( pow(x,3,_p) + _a*x + _b ) % _p
436
- print "y2, p", y2, _p
437
- yomy = sqrt_mod(y2, _p)
438
- print "yomy", yomy
439
- if (yomy - recid) % 2 == 0:
440
- y=yomy
441
- else:
442
- y=_p - yomy
443
- print "y", y
444
-
445
- R = Point(curve, x, y, order)
446
- print "R", R
447
- e = str_to_long(msg)
448
- minus_e = -e % order
449
- print "e, -e: ", e, minus_e
450
- inv_r = inverse_mod(r,order)
451
- print "inv_r", inv_r
452
- print "s", s
453
-
454
- Q = inv_r * ( R*s + G*minus_e )
455
- print "Q", Q
456
-
457
- public_key = Public_key(G, Q, compressed)
458
- print "SER", public_key.ser()
459
- addr = public_key_to_bc_address(public_key.ser(), networkversion)
460
- if address != addr:
461
- raise Exception("vmB","Bad address. Signing: %s, received: %s"%(addr,address))
462
-
463
-
464
- def sign_message(secret, message, pureECDSASigning=False):
465
- if len(secret) == 32:
466
- pkey = EC_KEY(str_to_long(secret))
467
- compressed = False
468
- elif len(secret) == 33:
469
- pkey = EC_KEY(str_to_long(secret[:-1]))
470
- secret=secret[:-1]
471
- compressed = True
472
- else:
473
- raise Exception("sm","Bad private key size")
474
-
475
- msg=message
476
- if not pureECDSASigning:
477
- msg=Hash(format_msg_to_sign(message))
478
-
479
- eckey = EC_KEY(str_to_long(secret), compressed)
480
- private_key = eckey.privkey
481
- public_key = eckey.pubkey
482
- addr = public_key_to_bc_address(GetPubKey(eckey,eckey.pubkey.compressed))
483
-
484
- sig = private_key.sign(msg, randomk())
485
- if not public_key.verify(msg, sig):
486
- raise Exception("sm","Problem signing message")
487
- return [sig,addr,compressed,public_key]
488
-
489
-
490
- def sign_message_Bitcoin(secret, msg, pureECDSASigning=False):
491
- sig,addr,compressed,public_key=sign_message(secret, msg, pureECDSASigning)
492
-
493
- for i in range(4):
494
- hb=27+i
495
- if compressed:
496
- hb+=4
497
- sign=base64.b64encode(chr(hb)+sig.ser())
498
- try:
499
- verify_message_Bitcoin(addr, sign, msg, pureECDSASigning)
500
- return {'address':addr, 'b64-signature':sign, 'signature':chr(hb)+sig.ser(), 'message':msg}
501
- except Exception as e:
502
- # print e.args
503
- pass
504
-
505
- raise Exception("smB","Unable to construct recoverable key")
506
-
507
- def FormatText(t, sigctx, verbose=False): #sigctx: False=what is displayed, True=what is signed
508
- r=''
509
- te=t.split('\n')
510
- for l in te:
511
- while len(l) and l[len(l)-1] in [' ', '\t', chr(9)]:
512
- l=l[:-1]
513
- if not len(l) or l[len(l)-1]!='\r':
514
- l+='\r'
515
- if not sigctx:
516
- if len(l) and l[0]=='-':
517
- l='- '+l[1:]
518
- r+=l+'\n'
519
- r=r[:-2]
520
-
521
- global FTVerbose
522
- if FTVerbose:
523
- print ' -- Sent: '+t.encode('hex')
524
- if sigctx:
525
- print ' -- Signed: '+r.encode('hex')
526
- else:
527
- print ' -- Displayed: '+r.encode('hex')
528
-
529
- return r
530
-
531
-
532
- def crc24(m):
533
- INIT = 0xB704CE
534
- POLY = 0x1864CFB
535
- crc = INIT
536
- r = ''
537
- for o in m:
538
- o=ord(o)
539
- crc ^= (o << 16)
540
- for i in xrange(8):
541
- crc <<= 1
542
- if crc & 0x1000000:
543
- crc ^= POLY
544
- for i in range(3):
545
- r += chr( ( crc & (0xff<<(8*i))) >> (8*i) )
546
- return r
547
-
548
- def chunks(t, n):
549
- return [t[i:i+n] for i in range(0, len(t), n)]
550
-
551
- def ASCIIArmory(block, name):
552
- r='-----BEGIN '+name+'-----\r\n'
553
- r+='\r\n'.join(chunks(base64.b64encode(block), 64))+'\r\n='
554
- r+=base64.b64encode(crc24(block))+'\r\n'
555
- r+='-----END '+name+'-----'
556
- return r
557
-
558
-
559
- #==============================================
560
-
561
- def verifySignature(addr, b64sig, msg):
562
- return verify_message_Bitcoin(addr, b64sig, FormatText(msg, True))
563
-
564
- def ASv0(privkey, msg):
565
- return sign_message_Bitcoin(privkey, FormatText(msg, True))
566
-
567
- def ASv1CS(privkey, msg):
568
- sig=ASv0(privkey, msg)
569
- r='-----BEGIN SIGNED BITCOIN MESSAGE-----\r\n\r\n'
570
- r+=FormatText(msg, False)+'\r\n'
571
- r+=ASCIIArmory(sig['signature'], 'BITCOIN SIGNATURE')
572
- return r
573
-
574
- def ASv1B64(privkey, msg):
575
- sig=ASv0(privkey, msg)
576
- return ASCIIArmory(sig['signature']+sig['message'], 'BITCOIN SIGNED MESSAGE')
577
-
578
-
579
-
580
- #==============================================
581
-
582
- #
583
- # Some tests with ugly output
584
- # You can delete the print commands in FormatText() after testing
585
- #
586
-
587
- pvk1='\x01'*32
588
- text0='Hello world!'
589
- text1='Hello world!\n'
590
- text2='Hello world!\n\t'
591
- text3='Hello world!\n-jackjack'
592
- text4='Hello world!\n-jackjack '
593
- text5='Hello world!'
594
-
595
- FTVerbose=True
596
- # sv0=ASv0(pvk1, text1)
597
- # print "STUFF TO SIGN"
598
- # print sv0
599
- # print "KK"
600
- # print verifySignature(sv0['address'], sv0['b64-signature'], sv0['message'])
601
- # print
602
- # print ASv1B64(pvk1, text1)
603
- # print
604
- # print ASv1CS(pvk1, text1)
605
- # print
606
- # print ASv1CS(pvk1, text2)
607
- # print
608
- # print ASv1CS(pvk1, text3)
609
- # print
610
- # print ASv1CS(pvk1, text4)
611
- # print
612
- # print ASv1CS(pvk1, text5)
613
- print verifySignature('13C5HZKutjMDeuc7f5mPj6XGpJCZu7xKh2', 'H55JIuwEi4YXzINOzx2oU6VsfBcTOScpFtp10pP/M4EWV336ClH65SObwPXnRf/fMXDu8hs8nweB42CtpWgngeM=', 'abc')
614
-
615
- #print verifySignature('13C5HZKutjMDeuc7f5mPj6XGpJCZu7xKh2', 'H55JIuwEi4YXzINOzx2oU6VsfBcTOScpFtp10pP/M4EWV336ClH65SObwPXnRf/fMXDu8hs8nweB42CtpWgngeM=', 'aaa')