Bitcoin Forum
February 07, 2023, 06:31:33 PM *
News: Latest Bitcoin Core release: 24.0.1 [Torrent]
 
   Home   Help Search Login Register More  
Pages: [1]
  Print  
Author Topic: [SOLVED] python secp256k1  (Read 10586 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
1675794693
Hero Member
*
Offline Offline

Posts: 1675794693

View Profile Personal Message (Offline)

Ignore
1675794693
Reply with quote  #2

1675794693
Report to moderator
1675794693
Hero Member
*
Offline Offline

Posts: 1675794693

View Profile Personal Message (Offline)

Ignore
1675794693
Reply with quote  #2

1675794693
Report to moderator
Whoever mines the block which ends up containing your transaction will get its fee.
Advertised sites are not endorsed by the Bitcoin Forum. They may be unsafe, untrustworthy, or illegal in your jurisdiction.
1675794693
Hero Member
*
Offline Offline

Posts: 1675794693

View Profile Personal Message (Offline)

Ignore
1675794693
Reply with quote  #2

1675794693
Report to moderator
1675794693
Hero Member
*
Offline Offline

Posts: 1675794693

View Profile Personal Message (Offline)

Ignore
1675794693
Reply with quote  #2

1675794693
Report to moderator
1675794693
Hero Member
*
Offline Offline

Posts: 1675794693

View Profile Personal Message (Offline)

Ignore
1675794693
Reply with quote  #2

1675794693
Report to moderator
LZ
Legendary
*
Offline Offline

Activity: 1722
Merit: 1069


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!