Title: [SOLVED] python secp256k1
Post by: Lis on June 27, 2011, 03:42:02 PM
#! /usr/bin/env python
import random
class CurveFp( object ): def __init__( self, p, a, b ): self.__p = p self.__a = a self.__b = b
def p( self ): return self.__p
def a( self ): return self.__a
def b( self ): return self.__b
def contains_point( self, x, y ): return ( y * y - ( x * x * x + self.__a * x + self.__b ) ) % self.__p == 0
class Point( object ): def __init__( self, curve, x, y, order = None ): self.__curve = curve self.__x = x self.__y = y self.__order = order if self.__curve: assert self.__curve.contains_point( x, y ) if order: assert self * order == INFINITY def __add__( self, other ): if other == INFINITY: return self if self == INFINITY: return other assert self.__curve == other.__curve if self.__x == other.__x: if ( self.__y + other.__y ) % self.__curve.p() == 0: return INFINITY else: return self.double()
p = self.__curve.p() l = ( ( other.__y - self.__y ) * \ inverse_mod( other.__x - self.__x, p ) ) % p x3 = ( l * l - self.__x - other.__x ) % p y3 = ( l * ( self.__x - x3 ) - self.__y ) % p return Point( self.__curve, x3, y3 )
def __mul__( self, other ): def leftmost_bit( x ): assert x > 0 result = 1L while result <= x: result = 2 * result return result / 2
e = other if self.__order: e = e % self.__order if e == 0: return INFINITY if self == INFINITY: return INFINITY assert e > 0 e3 = 3 * e negative_self = Point( self.__curve, self.__x, -self.__y, self.__order ) i = leftmost_bit( e3 ) / 2 result = self while i > 1: result = result.double() if ( e3 & i ) != 0 and ( e & i ) == 0: result = result + self if ( e3 & i ) == 0 and ( e & i ) != 0: result = result + negative_self i = i / 2 return result
def __rmul__( self, other ): return self * other
def __str__( self ): if self == INFINITY: return "infinity" return "(%d,%d)" % ( self.__x, self.__y )
def double( self ): if self == INFINITY: return INFINITY
p = self.__curve.p() a = self.__curve.a() l = ( ( 3 * self.__x * self.__x + a ) * \ inverse_mod( 2 * self.__y, p ) ) % p x3 = ( l * l - 2 * self.__x ) % p y3 = ( l * ( self.__x - x3 ) - self.__y ) % p return Point( self.__curve, x3, y3 )
def x( self ): return self.__x
def y( self ): return self.__y
def curve( self ): return self.__curve def order( self ): return self.__order INFINITY = Point( None, None, None )
def inverse_mod( a, m ): if a < 0 or m <= a: a = a % m c, d = a, m uc, vc, ud, vd = 1, 0, 0, 1 while c != 0: q, c, d = divmod( d, c ) + ( c, ) uc, vc, ud, vd = ud - q*uc, vd - q*vc, uc, vc assert d == 1 if ud > 0: return ud else: return ud + m
# secp256k1 _p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2FL _r = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141L _b = 0x0000000000000000000000000000000000000000000000000000000000000007L _a = 0x0000000000000000000000000000000000000000000000000000000000000000L _Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798L _Gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8L
class Signature( object ): def __init__( self, r, s ): self.r = r self.s = s class Public_key( object ): def __init__( self, generator, point ): self.curve = generator.curve() self.generator = generator self.point = point n = generator.order() if not n: raise RuntimeError, "Generator point must have order." if not n * point == INFINITY: raise RuntimeError, "Generator point order is bad." if point.x() < 0 or n <= point.x() or point.y() < 0 or n <= point.y(): raise RuntimeError, "Generator point has x or y out of range."
def verifies( self, hash, signature ): G = self.generator n = G.order() r = signature.r s = signature.s if r < 1 or r > n-1: return False if s < 1 or s > n-1: return False c = inverse_mod( s, n ) u1 = ( hash * c ) % n u2 = ( r * c ) % n xy = u1 * G + u2 * self.point v = xy.x() % n return v == r
class Private_key( object ): def __init__( self, public_key, secret_multiplier ): self.public_key = public_key self.secret_multiplier = secret_multiplier
def der( self ): hex_der_key = '06052b8104000a30740201010420' + \ '%064x' % self.secret_multiplier + \ 'a00706052b8104000aa14403420004' + \ '%064x' % self.public_key.point.x() + \ '%064x' % self.public_key.point.y() return hex_der_key.decode('hex')
def sign( self, hash, random_k ): G = self.public_key.generator n = G.order() k = random_k % n p1 = k * G r = p1.x() if r == 0: raise RuntimeError, "amazingly unlucky random number r" s = ( inverse_mod( k, n ) * \ ( hash + ( self.secret_multiplier * r ) % n ) ) % n if s == 0: raise RuntimeError, "amazingly unlucky random number s" return Signature( r, s )
curve_256 = CurveFp( _p, _a, _b ) generator_256 = Point( curve_256, _Gx, _Gy, _r ) g = generator_256
if __name__ == "__main__": print '=======================================================================' ### generate privkey randrange = random.SystemRandom().randrange n = g.order() secret = randrange( 1, n ) ### set privkey #secret = 0xC85AFBACCF3E1EE40BDCD721A9AD1341344775D51840EFC0511E0182AE92F78EL ### print privkey print 'secret', hex(secret)
### generate pubkey pubkey = Public_key( g, g * secret ) ### set pubkey #pubkey = Public_key(g, Point( curve_256, 0x40f9f833a25c725402e242965410b5bb992dc4fea1328681f0a74571c3104e36L, # 0x0882ea6ae14b6b1316e71e76cc51867cba20cafabd349753058b8c4677be50caL)) ### print pubkey print 'pubkey', hex(pubkey.point.x()), hex(pubkey.point.y())
privkey = Private_key( pubkey, secret ) # set hash #hash = randrange( 1, n ) hash = 0x0000000000000000000000000000000000000000000000000000000000000000L
### make signature on hash signature = privkey.sign( hash, randrange( 1, n ) ) ### set signature #signature = Signature(0x0000000000000000000000000000000000000000000000000000000000000000L, # 0x0000000000000000000000000000000000000000000000000000000000000000L) ### print signature print 'signature', hex(signature.r), hex(signature.s)
#print '=======================================================================' print 'verifies', pubkey.verifies( hash, signature ) print '======================================================================='
Умеет, генерировать privkey, делать из него pubkey, подписывать хеш проверять подпись. Вопрос знатокам, у меня сигнатура получается 64 bytes 2x32b. Даже если добавить 0x30 спереди выходит 65b. В то время как http://blockexplorer.com/rawtx/a2844948747244e5582b385e86de85b386443353cfe6803091ac50257baf7ee7 30440220681233302fad9cb4f9ea61653d19cdea635ae59270ebbb837b9287f75ae90dae02203bf9d2d0b52cd1734ccaf7bebc831c128737fb1309f83b79cab500dc274b532201
71 bytes ЧЯДНТ??? зы. спасибо Sipa, за то что терпел мое каверканье международного, мне стыдно :-[ ззы. код народное достояние.
Title: Re: python secp256k1
Post by: LZ on June 28, 2011, 07:11:58 AM
Разберем вышеприведенный пример сигнатуры.
30 - какая-то DER (http://en.wikipedia.org/wiki/Distinguished_Encoding_Rules) метка
44 - длина, вроде hex(len(hex(signature.r))/2+len(hex(signature.s))/2+2)
02 - разделитель, далее используем r
20 - длина, вроде hex(len(hex(signature.r))/2)
681233302fad9cb4f9ea61653d19cdea635ae59270ebbb837b9287f75ae90dae - это hex(signature.r)
02 - разделитель, далее используем s
20 - длина, вроде hex(len(hex(signature.s))/2)
3bf9d2d0b52cd1734ccaf7bebc831c128737fb1309f83b79cab500dc274b5322 - это hex(signature.s)
01 - конец сигнатуры
Title: Re: python secp256k1
Post by: Lis on June 28, 2011, 09:51:23 AM
Спасибо большое в догонку еще код на общественное пользование. #!/usr/bin/env python # -*- coding: utf-8 -*-
import hashlib
b58chars = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
def hex_open_key_to_hex_hesh160(hex_open_key): h160 = hashlib.new('ripemd160') h160.update(hashlib.sha256(('04'+hex_open_key).decode('hex')).hexdigest().decode('hex')) return h160.hexdigest() def hex_hesh160_to_hex_addr_v0(hex_hesh160): return '00'+hex_hesh160+hashlib.sha256(hashlib.sha256(('00'+hex_hesh160).decode('hex')).hexdigest().decode('hex')).hexdigest()[0:8] def hex_addr_v0_to_hex_hesh160(hex_addr_v0): return hex_addr_v0[2:-8]
def hex_to_base58(hex_data): base58 = '' int_data = int(hex_data, 16) while int_data >= len(b58chars): base58 = b58chars[int_data%len(b58chars)] + base58 int_data = int_data/len(b58chars) base58 = b58chars[int_data%len(b58chars)] + base58 for i in xrange(len(hex_data)/2): if hex_data[i*2:i*2+2] == '00': base58 = '1' + base58 else: break return base58 def base58_to_hex(base58): hex_data = '' int_data = 0 for i in xrange(-1, -len(base58)-1, -1): int_data += (b58chars.index(base58[i]))*58**(-i-1) hex_data = hex(int_data)[2:-1] for i in xrange(len(base58)): if base58[i] == '1': hex_data = '00' + hex_data else: break return hex_data
hex_open_key = '40f9f833a25c725402e242965410b5bb992dc4fea1328681f0a74571c3104e360882ea6ae14b6b1316e71e76cc51867cba20cafabd349753058b8c4677be50ca' print hex_to_base58(hex_hesh160_to_hex_addr_v0(hex_open_key_to_hex_hesh160(hex_open_key)))
Код сырой будет, дописываться.
Title: Re: python secp256k1
Post by: Lis on July 09, 2011, 03:59:06 PM
excellent work )
Is it possible to write out privkey to file in PEM format directly == without pyopenssl and/or M2Crypto ?
Like this one example :
-----BEGIN EC PARAMETERS----- BgUrgQQACg== -----END EC PARAMETERS----- -----BEGIN EC PRIVATE KEY----- MHQCAQEEILcyvoUzP5fLtJAaEQnVvqOy+TW1P5/ui4olcu8Vi9lhoAcGBSuBBAAK oUQDQgAELa18gopT7X7Ii+Y3FEfAgssdCLjghXvXV926pyPiXSkqhbGkOfWi7s3+ xjBcZnMwKx18Pp4N6BI+7CaX6J7qDw== -----END EC PRIVATE KEY-----
Or maybe in DER form ?
I appreciate you help )
Да возможно постараюсь в понедельник
Title: Re: python secp256k1
Post by: Lis on July 12, 2011, 07:35:59 AM
Добавил der. Код в первом посте. Вызывается так: if __name__ == "__main__": secret = 0x0xc85afbaccf3e1ee40bdcd721a9ad1341344775d51840efc0511e0182ae92f78eL # Hal pubkey = Public_key( g, g * secret ) privkey = Private_key( pubkey, secret ) print privkey.der()
|