Bitcoin Forum
December 15, 2024, 03:37:55 AM *
News: Latest Bitcoin Core release: 28.0 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: [SOLVED] python secp256k1  (Read 10661 times)
Lis (OP)
Sr. Member
****
Offline Offline

Activity: 293
Merit: 251


Spice must flow!


View Profile
June 27, 2011, 03:42:02 PM
Last edit: July 14, 2011, 07:08:35 AM by Lis
 #1

Code:
#! /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
Code:
30440220681233302fad9cb4f9ea61653d19cdea635ae59270ebbb837b9287f75ae90dae02203bf9d2d0b52cd1734ccaf7bebc831c128737fb1309f83b79cab500dc274b532201
71 bytes
ЧЯДНТHuh

зы. спасибо Sipa, за то что терпел мое каверканье международного, мне стыдно  Embarrassed
ззы. код народное достояние.

You would like to thank?
btc: 14tAPpwzrfZqBeFVvfBZHiBdByYhsoFofn
LZ
Legendary
*
Offline Offline

Activity: 1722
Merit: 1072


P2P Cryptocurrency


View Profile
June 28, 2011, 07:11:58 AM
Last edit: June 28, 2011, 12:09:58 PM by lzsaver
 #2

Разберем вышеприведенный пример сигнатуры.

30 - какая-то DER метка

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 - конец сигнатуры

My OpenPGP fingerprint: 5099EB8C0F2E68C63B4ECBB9A9D0993E04143362
Lis (OP)
Sr. Member
****
Offline Offline

Activity: 293
Merit: 251


Spice must flow!


View Profile
June 28, 2011, 09:51:23 AM
Last edit: July 13, 2011, 09:44:27 AM by Lis
 #3

Спасибо большое

в догонку еще код на общественное пользование.
Code:
#!/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)))


Код сырой будет, дописываться.

You would like to thank?
btc: 14tAPpwzrfZqBeFVvfBZHiBdByYhsoFofn
Lis (OP)
Sr. Member
****
Offline Offline

Activity: 293
Merit: 251


Spice must flow!


View Profile
July 09, 2011, 03:59:06 PM
 #4

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 )
Да возможно
постараюсь в понедельник

You would like to thank?
btc: 14tAPpwzrfZqBeFVvfBZHiBdByYhsoFofn
Lis (OP)
Sr. Member
****
Offline Offline

Activity: 293
Merit: 251


Spice must flow!


View Profile
July 12, 2011, 07:35:59 AM
Last edit: July 12, 2011, 10:40:16 AM by Lis
 #5

Добавил der. Код в первом посте.
Вызывается так:
Code:
if __name__ == "__main__":
  secret = 0x0xc85afbaccf3e1ee40bdcd721a9ad1341344775d51840efc0511e0182ae92f78eL # Hal
  pubkey = Public_key( g, g * secret )
  privkey = Private_key( pubkey, secret )
  print privkey.der()

You would like to thank?
btc: 14tAPpwzrfZqBeFVvfBZHiBdByYhsoFofn
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.19 | SMF © 2006-2009, Simple Machines Valid XHTML 1.0! Valid CSS!