137 lines
3.8 KiB
Python
137 lines
3.8 KiB
Python
"""
|
|
*******************************************************************************
|
|
* Ledger Blue
|
|
* (c) 2016 Ledger
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
********************************************************************************
|
|
"""
|
|
|
|
import hashlib
|
|
try:
|
|
import secp256k1
|
|
USE_SECP = secp256k1.HAS_ECDH
|
|
except ImportError:
|
|
USE_SECP = False
|
|
|
|
if not USE_SECP:
|
|
import ecpy
|
|
from builtins import int
|
|
from ecpy.curves import Curve, Point
|
|
from ecpy.keys import ECPublicKey, ECPrivateKey
|
|
from ecpy.ecdsa import ECDSA
|
|
CURVE_SECP256K1 = Curve.get_curve('secp256k1')
|
|
SIGNER = ECDSA()
|
|
|
|
class PublicKey(object):
|
|
def __init__(self, pubkey=None, raw=False, flags=None, ctx=None):
|
|
if USE_SECP:
|
|
if flags == None:
|
|
flags = secp256k1.FLAG_VERIFY
|
|
self.obj = secp256k1.PublicKey(pubkey, raw, flags, ctx)
|
|
else:
|
|
if not raw:
|
|
raise Exception("Non raw init unsupported")
|
|
pubkey = pubkey[1:]
|
|
x = int.from_bytes(pubkey[0:32], 'big')
|
|
y = int.from_bytes(pubkey[32:], 'big')
|
|
self.obj = ECPublicKey(Point(x, y, CURVE_SECP256K1))
|
|
|
|
def ecdsa_deserialize(self, ser_sig):
|
|
if USE_SECP:
|
|
return self.obj.ecdsa_deserialize(ser_sig)
|
|
else:
|
|
return ser_sig
|
|
|
|
def serialize(self, compressed=True):
|
|
if USE_SECP:
|
|
return self.obj.serialize(compressed)
|
|
else:
|
|
if not compressed:
|
|
out = b"\x04"
|
|
out += self.obj.W.x.to_bytes(32, 'big')
|
|
out += self.obj.W.y.to_bytes(32, 'big')
|
|
else:
|
|
out = b"\x03" if ((self.obj.W.y & 1) != 0) else "\x02"
|
|
out += self.obj.W.x.to_bytes(32, 'big')
|
|
return out
|
|
|
|
def ecdh(self, scalar):
|
|
if USE_SECP:
|
|
return self.obj.ecdh(scalar)
|
|
else:
|
|
scalar = int.from_bytes(scalar, 'big')
|
|
point = self.obj.W * scalar
|
|
# libsecp256k1 style secret
|
|
out = b"\x03" if ((point.y & 1) != 0) else b"\x02"
|
|
out += point.x.to_bytes(32, 'big')
|
|
hash = hashlib.sha256()
|
|
hash.update(out)
|
|
return hash.digest()
|
|
|
|
def ecdsa_verify(self, msg, raw_sig, raw=False, digest=hashlib.sha256):
|
|
if USE_SECP:
|
|
return self.obj.ecdsa_verify(msg, raw_sig, raw, digest)
|
|
else:
|
|
if not raw:
|
|
h = digest()
|
|
h.update(msg)
|
|
msg = h.digest()
|
|
raw_sig = bytearray(raw_sig)
|
|
return SIGNER.verify(msg, raw_sig, self.obj)
|
|
|
|
class PrivateKey(object):
|
|
|
|
def __init__(self, privkey=None, raw=True, flags=None, ctx=None):
|
|
if USE_SECP:
|
|
if flags == None:
|
|
flags = secp256k1.ALL_FLAGS
|
|
self.obj = secp256k1.PrivateKey(privkey, raw, flags, ctx)
|
|
self.pubkey = self.obj.pubkey
|
|
else:
|
|
if not raw:
|
|
raise Exception("Non raw init unsupported")
|
|
if privkey == None:
|
|
privkey = ecpy.ecrand.rnd(CURVE_SECP256K1.order)
|
|
else:
|
|
privkey = int.from_bytes(privkey,'big')
|
|
self.obj = ECPrivateKey(privkey, CURVE_SECP256K1)
|
|
pubkey = self.obj.get_public_key().W
|
|
out = b"\x04"
|
|
out += pubkey.x.to_bytes(32, 'big')
|
|
out += pubkey.y.to_bytes(32, 'big')
|
|
self.pubkey = PublicKey(out, raw=True)
|
|
|
|
def serialize(self):
|
|
if USE_SECP:
|
|
return self.obj.serialize()
|
|
else:
|
|
return "%.64x"%self.obj.d
|
|
|
|
def ecdsa_serialize(self, raw_sig):
|
|
if USE_SECP:
|
|
return self.obj.ecdsa_serialize(raw_sig)
|
|
else:
|
|
return raw_sig
|
|
|
|
def ecdsa_sign(self, msg, raw=False, digest=hashlib.sha256):
|
|
if USE_SECP:
|
|
return self.obj.ecdsa_sign(msg, raw, digest)
|
|
else:
|
|
if not raw:
|
|
h = digest()
|
|
h.update(msg)
|
|
msg = h.digest()
|
|
signature = SIGNER.sign(msg, self.obj)
|
|
return bytearray(signature)
|