A wrapper of the OpenSSL elliptic curve functions for easy Python manipulation.
In Python, dealing directly with the OpenSSL library (through PyElliptic) easily becomes a hassle with the use of C pointers and string buffers.
To make things easier, I decided to make a wrapper for PyElliptic to make the manipulation of elliptic curves and points more Pythonic.
The wrapper has been tested with all recommended SEC curves (secp192k1
, secp192r1
, secp224k1
, secp224r1
, secp256k1
, secp256r1
, secp384r1
, secp521r1
, sect163k1
, sect163r1
, sect163r2
, sect233k1
, sect233r1
, sect239k1
, sect283k1
, sect283r1
, sect409k1
, sect409r1
, sect571k1
and sect571r1
).
Especially point addition and multiplication is way easier, as the following console example usage shows:
>>> from curve import Curve
>>> c = Curve( 'secp256k1' )
>>> c
Curve<Equation: y^2 = x^3+7 (mod p), Field: Prime field, p: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F>
>>> c.p
115792089237316195423570985008687907853269984665640564039457584007908834671663L
>>> c.a
0
>>> c.b
7
>>> c.order
115792089237316195423570985008687907852837564279074904382605163141518161494337L
>>> c.G
Point<0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798, 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8>
>>> c.G.x
55066263022277343669578718895168534326250603453777594175500187360389116729240L
>>> c.G.y
32670510020758816978083085130507043184471273380659243275938904335757337482424L
>>> 4 * c.G + (255 * c.G)
Point<0xC2C80F844B70599812D625460F60340E3E6F36054A14546E6DC25D47376BEA9B, 0x86CA160D68F4D4E718B495B891D3B1B573B871A702B4CF6123ABD4483AA79C64>
>>> from keypair import KeyPair
>>> kp = KeyPair( c )
>>> kp
KeyPair<Private:0x5091AD80EEE3FB065A6E3FF126A112C4905F8E79566E22396807A55ADE1B5C6F, Public:Point<0x13FCF42341462150B8366F11659E396DF88D19F65D533CEEAC78C9EC6F94B45D, 0x18DDDF6DCA0C097FC0359E680BAED36403D77657ABE7F76E64E1B787D90C485A>>
>>> kp.private_key
36442418189203456142546292588071998273845228785350611568921618467649899682927L
>>> kp.public_key
Point<0x13FCF42341462150B8366F11659E396DF88D19F65D533CEEAC78C9EC6F94B45D, 0x18DDDF6DCA0C097FC0359E680BAED36403D77657ABE7F76E64E1B787D90C485A>
A curve can be initialized in three ways; by its name, id or by a pointer to an OpenSSL EC_GROUP
instance:
>>> from curve import Curve
>>> Curve( curvename='secp256k1' )
Curve<Equation: y^2 = x^3+7 (mod p), Field: Prime field, p: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F>
>>> Curve( curveid=714 )
Curve<Equation: y^2 = x^3+7 (mod p), Field: Prime field, p: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F>
>>> from pyelliptic.openssl import OpenSSL
>>> Curve( openssl_group=OpenSSL.EC_GROUP_new_by_curve_name( 714 ) )
Curve<Equation: y^2 = x^3+7 (mod p), Field: Prime field, p: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F>
Depending on whether the curve is over a prime field, Fp, or a power-of-2 field, F2m, the curve has slightly different properties:
prime_type
: Either'prime'
or'power-of-two'
G
: The basePoint
(or generator) of the curve.order
: The order of the curve (amount of elements)h
: The cofactor of the curvea
: The curve coefficient ab
: The curve coefficient bp
(Only Fp): The prime p specifying the fieldm
(Only F2m): The integer m specifying the fieldpoly_coeffs
(Only F2m): The degrees of the polynomials specifying the fieldos_group
: A pointer to the underlyingEC_GROUP
instance.
>>> from curve import Curve
>>> c1 = Curve( 'secp256k1' )
>>> c2 = Curve( 'sect239k1' )
>>> c1
Curve<Equation: y^2 = x^3+7 (mod p), Field: Prime field, p: 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F>
>>> c2
Curve<Equation: y^2+xy = x^3+1, Field: Power-of-two field, f(x): x^239+x^158+1>
>>> c1.field_type
'prime'
>>> c2.field_type
'power-of-two'
>>> c1.G
Point<0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798, 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8>
>>> c2.G
Point<0x29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC, 0x76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA>
>>> c1.order
115792089237316195423570985008687907852837564279074904382605163141518161494337L
>>> c1.h
1
>>> c1.a
0
>>> c1.b
7
>>> c1.p
115792089237316195423570985008687907853269984665640564039457584007908834671663L
>>> c2.m
239
>>> c2.poly_coeffs
[158]
You can get the base point from the G
property of a curve as described above:
>>> from curve import Curve
>>> Curve( 'secp256k1' ).G
Point<0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798, 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8>
You can also create a point on a curve from either (1) the x and y coordinates of the point or (2) by a pointer to an OpenSSL EC_POINT
instance:
>>> from curve import Curve
>>> from point import Point
>>> c = Curve( 'secp256k1' )
>>> Point( c, x=255, y=255 ) # Invalid coordinates, only a demonstration
Point<0xFF, 0xFF>
>>> from pyelliptic.openssl import OpenSSL
>>> Point( c, openssl_point=OpenSSL.EC_POINT_new( c.os_group ) )
Point<0x0, 0x0>
Finally, you can hash a string directly onto a curve (using the 'try-and-increment' method for finding points close to a certain x coordinate):
>>> from curve import Curve
>>> c = Curve( 'secp256k1' )
>>> c.hash_to_point( 'somestring' )
Point<0xE4998BB769D5AF19526738527E13ECF753F5CC7AA60DD0ADF94BB0A248CF577A, 0x79FCD45DD59999C5D916FB31C0F023B4A1A1BCD63F11FD3D3E31D5C5E7D79C1D>
>>> c.hash_to_point( 'someotherstring' )
Point<0xB661EE62474532EF1C8EA78B1CE3634E2EEC06B8E256E46A5CE25DF0FFABF332, 0x1DAB745A01B745CA9BF276D8E990E8EF11CFA954C5956DF9BF4C0684FABB00A6>
Point addition and multiplication is intuitive:
>>> from curve import Curve
>>> c = Curve( 'secp256k1' )
>>> c.G
Point<0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798, 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8>
>>> 2 * c.G
Point<0xC6047F9441ED7D6D3045406E95C07CD85C778E4B8CEF3CA7ABAC09B95C709EE5, 0x1AE168FEA63DC339A3C58419466CEAEEF7F632653266D0E1236431A950CFE52A>
>>> c.G + c.G
Point<0xC6047F9441ED7D6D3045406E95C07CD85C778E4B8CEF3CA7ABAC09B95C709EE5, 0x1AE168FEA63DC339A3C58419466CEAEEF7F632653266D0E1236431A950CFE52A>
>>> ( 5 * c.G ) + ( 256 * c.G )
Point<0x9CF606744CF4B5F3FDF989D3F19FB2652D00CFE1D5FCD692A323CE11A28E7553, 0x8147CBF7B973FCC15B57B6A3CFAD6863EDD0F30E3C45B85DC300C513C247759D>
x
: The x coordinatey
: The y coordinateos_point
: A pointer to the underlyingEC_POINT
instance.
A key pair is a structure that contains a private and a public key for a given curve.
A key pair for a curve can be generated randomly or by providing a private key:
>>> from curve import Curve
>>> from keypair import KeyPair
>>> c = Curve( 'secp256k1' )
>>> KeyPair( c ) # Random key pair
KeyPair<Private:0x94087552C3C72CC867E555854B9DD6392A611A40C168B0C6B7AEFC63DD9F5818, Public:Point<0x7C3FF4B9AE4D4EFCD22185F5ED7B6C8EF79CFF83AC0A3DFA4A258CDDBFC2AC3E, 0xEBFD9904CB8398524022BCDC268D6B03207737F35E7591EE5ACEE338D5272733>>
>>> KeyPair( c, private_key=12345 )
KeyPair<Private:0x3039, Public:Point<0xF01D6B9018AB421DD410404CB869072065522BF85734008F105CF385A023A80F, 0xEBA29D0F0C5408ED681984DC525982ABEFCCD9F7FF01DD26DA4999CF3F6A295>>
Alternatively, you can provide a pointer to an OpenSSL EC_KEY
instance:
>>> from curve import Curve
>>> from keypair import KeyPair
>>> from pyelliptic.openssl import OpenSSL
>>> c = Curve( 'secp256k1' )
>>> k = OpenSSL.EC_KEY_new_by_curve_name( 714 )
>>> OpenSSL.EC_KEY_generate_key( k )
1
>>> KeyPair( c, os_key=k )
KeyPair<Private:0xECBCB11DB69B0A8876986571E336A4F486E7B2C355712D2FA32C9836A153AAA, Public:Point<0x732F6911AC325F41CEAB478D4D5AE3EB033A06EA8ECC03AF58CF2FF022A1FE
5, 0x156B3C906BB70070B946F8565C425FEA00EA3350A71073F5B4818C96D41610C6>>
private_key
: The private key (an integer)public_key
: The public key (aPoint
)os_key
: A pointer to the underlyingEC_KEY
instance.