add
This commit is contained in:
14
ccxt/static_dependencies/ecdsa/__init__.py
Normal file
14
ccxt/static_dependencies/ecdsa/__init__.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from .keys import SigningKey, VerifyingKey, BadSignatureError, BadDigestError
|
||||
from .curves import NIST192p, NIST224p, NIST256p, NIST384p, NIST521p, SECP256k1
|
||||
|
||||
# This code comes from http://github.com/warner/python-ecdsa
|
||||
#from ._version import get_versions
|
||||
__version__ = 'ccxt' # custom ccxt version
|
||||
#del get_versions
|
||||
|
||||
__all__ = ["curves", "der", "ecdsa", "ellipticcurve", "keys", "numbertheory",
|
||||
"util"]
|
||||
|
||||
_hush_pyflakes = [SigningKey, VerifyingKey, BadSignatureError, BadDigestError,
|
||||
NIST192p, NIST224p, NIST256p, NIST384p, NIST521p, SECP256k1]
|
||||
del _hush_pyflakes
|
||||
Binary file not shown.
Binary file not shown.
BIN
ccxt/static_dependencies/ecdsa/__pycache__/der.cpython-311.pyc
Normal file
BIN
ccxt/static_dependencies/ecdsa/__pycache__/der.cpython-311.pyc
Normal file
Binary file not shown.
BIN
ccxt/static_dependencies/ecdsa/__pycache__/ecdsa.cpython-311.pyc
Normal file
BIN
ccxt/static_dependencies/ecdsa/__pycache__/ecdsa.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
ccxt/static_dependencies/ecdsa/__pycache__/keys.cpython-311.pyc
Normal file
BIN
ccxt/static_dependencies/ecdsa/__pycache__/keys.cpython-311.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
ccxt/static_dependencies/ecdsa/__pycache__/util.cpython-311.pyc
Normal file
BIN
ccxt/static_dependencies/ecdsa/__pycache__/util.cpython-311.pyc
Normal file
Binary file not shown.
520
ccxt/static_dependencies/ecdsa/_version.py
Normal file
520
ccxt/static_dependencies/ecdsa/_version.py
Normal file
@@ -0,0 +1,520 @@
|
||||
|
||||
# This file helps to compute a version number in source trees obtained from
|
||||
# git-archive tarball (such as those provided by githubs download-from-tag
|
||||
# feature). Distribution tarballs (built by setup.py sdist) and build
|
||||
# directories (produced by setup.py build) will contain a much shorter file
|
||||
# that just contains the computed version number.
|
||||
|
||||
# This file is released into the public domain. Generated by
|
||||
# versioneer-0.17 (https://github.com/warner/python-versioneer)
|
||||
|
||||
"""Git implementation of _version.py."""
|
||||
|
||||
import errno
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
def get_keywords():
|
||||
"""Get the keywords needed to look up the version information."""
|
||||
# these strings will be replaced by git during git-archive.
|
||||
# setup.py/versioneer.py will grep for the variable names, so they must
|
||||
# each be defined on a line of their own. _version.py will just call
|
||||
# get_keywords().
|
||||
git_refnames = "$Format:%d$"
|
||||
git_full = "$Format:%H$"
|
||||
git_date = "$Format:%ci$"
|
||||
keywords = {"refnames": git_refnames, "full": git_full, "date": git_date}
|
||||
return keywords
|
||||
|
||||
|
||||
class VersioneerConfig:
|
||||
"""Container for Versioneer configuration parameters."""
|
||||
|
||||
|
||||
def get_config():
|
||||
"""Create, populate and return the VersioneerConfig() object."""
|
||||
# these strings are filled in when 'setup.py versioneer' creates
|
||||
# _version.py
|
||||
cfg = VersioneerConfig()
|
||||
cfg.VCS = "git"
|
||||
cfg.style = "pep440"
|
||||
cfg.tag_prefix = "python-ecdsa-"
|
||||
cfg.parentdir_prefix = "ecdsa-"
|
||||
cfg.versionfile_source = "ecdsa/_version.py"
|
||||
cfg.verbose = False
|
||||
return cfg
|
||||
|
||||
|
||||
class NotThisMethod(Exception):
|
||||
"""Exception raised if a method is not valid for the current scenario."""
|
||||
|
||||
|
||||
LONG_VERSION_PY = {}
|
||||
HANDLERS = {}
|
||||
|
||||
|
||||
def register_vcs_handler(vcs, method): # decorator
|
||||
"""Decorator to mark a method as the handler for a particular VCS."""
|
||||
def decorate(f):
|
||||
"""Store f in HANDLERS[vcs][method]."""
|
||||
if vcs not in HANDLERS:
|
||||
HANDLERS[vcs] = {}
|
||||
HANDLERS[vcs][method] = f
|
||||
return f
|
||||
return decorate
|
||||
|
||||
|
||||
def run_command(commands, args, cwd=None, verbose=False, hide_stderr=False,
|
||||
env=None):
|
||||
"""Call the given command(s)."""
|
||||
assert isinstance(commands, list)
|
||||
p = None
|
||||
for c in commands:
|
||||
try:
|
||||
dispcmd = str([c] + args)
|
||||
# remember shell=False, so use git.cmd on windows, not just git
|
||||
p = subprocess.Popen([c] + args, cwd=cwd, env=env,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=(subprocess.PIPE if hide_stderr
|
||||
else None))
|
||||
break
|
||||
except EnvironmentError:
|
||||
e = sys.exc_info()[1]
|
||||
if e.errno == errno.ENOENT:
|
||||
continue
|
||||
if verbose:
|
||||
print("unable to run %s" % dispcmd)
|
||||
print(e)
|
||||
return None, None
|
||||
else:
|
||||
if verbose:
|
||||
print("unable to find command, tried %s" % (commands,))
|
||||
return None, None
|
||||
stdout = p.communicate()[0].strip()
|
||||
if sys.version_info[0] >= 3:
|
||||
stdout = stdout.decode()
|
||||
if p.returncode != 0:
|
||||
if verbose:
|
||||
print("unable to run %s (error)" % dispcmd)
|
||||
print("stdout was %s" % stdout)
|
||||
return None, p.returncode
|
||||
return stdout, p.returncode
|
||||
|
||||
|
||||
def versions_from_parentdir(parentdir_prefix, root, verbose):
|
||||
"""Try to determine the version from the parent directory name.
|
||||
|
||||
Source tarballs conventionally unpack into a directory that includes both
|
||||
the project name and a version string. We will also support searching up
|
||||
two directory levels for an appropriately named parent directory
|
||||
"""
|
||||
rootdirs = []
|
||||
|
||||
for i in range(3):
|
||||
dirname = os.path.basename(root)
|
||||
if dirname.startswith(parentdir_prefix):
|
||||
return {"version": dirname[len(parentdir_prefix):],
|
||||
"full-revisionid": None,
|
||||
"dirty": False, "error": None, "date": None}
|
||||
else:
|
||||
rootdirs.append(root)
|
||||
root = os.path.dirname(root) # up a level
|
||||
|
||||
if verbose:
|
||||
print("Tried directories %s but none started with prefix %s" %
|
||||
(str(rootdirs), parentdir_prefix))
|
||||
raise NotThisMethod("rootdir doesn't start with parentdir_prefix")
|
||||
|
||||
|
||||
@register_vcs_handler("git", "get_keywords")
|
||||
def git_get_keywords(versionfile_abs):
|
||||
"""Extract version information from the given file."""
|
||||
# the code embedded in _version.py can just fetch the value of these
|
||||
# keywords. When used from setup.py, we don't want to import _version.py,
|
||||
# so we do it with a regexp instead. This function is not used from
|
||||
# _version.py.
|
||||
keywords = {}
|
||||
try:
|
||||
f = open(versionfile_abs, "r")
|
||||
for line in f.readlines():
|
||||
if line.strip().startswith("git_refnames ="):
|
||||
mo = re.search(r'=\s*"(.*)"', line)
|
||||
if mo:
|
||||
keywords["refnames"] = mo.group(1)
|
||||
if line.strip().startswith("git_full ="):
|
||||
mo = re.search(r'=\s*"(.*)"', line)
|
||||
if mo:
|
||||
keywords["full"] = mo.group(1)
|
||||
if line.strip().startswith("git_date ="):
|
||||
mo = re.search(r'=\s*"(.*)"', line)
|
||||
if mo:
|
||||
keywords["date"] = mo.group(1)
|
||||
f.close()
|
||||
except EnvironmentError:
|
||||
pass
|
||||
return keywords
|
||||
|
||||
|
||||
@register_vcs_handler("git", "keywords")
|
||||
def git_versions_from_keywords(keywords, tag_prefix, verbose):
|
||||
"""Get version information from git keywords."""
|
||||
if not keywords:
|
||||
raise NotThisMethod("no keywords at all, weird")
|
||||
date = keywords.get("date")
|
||||
if date is not None:
|
||||
# git-2.2.0 added "%cI", which expands to an ISO-8601 -compliant
|
||||
# datestamp. However we prefer "%ci" (which expands to an "ISO-8601
|
||||
# -like" string, which we must then edit to make compliant), because
|
||||
# it's been around since git-1.5.3, and it's too difficult to
|
||||
# discover which version we're using, or to work around using an
|
||||
# older one.
|
||||
date = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
|
||||
refnames = keywords["refnames"].strip()
|
||||
if refnames.startswith("$Format"):
|
||||
if verbose:
|
||||
print("keywords are unexpanded, not using")
|
||||
raise NotThisMethod("unexpanded keywords, not a git-archive tarball")
|
||||
refs = set([r.strip() for r in refnames.strip("()").split(",")])
|
||||
# starting in git-1.8.3, tags are listed as "tag: foo-1.0" instead of
|
||||
# just "foo-1.0". If we see a "tag: " prefix, prefer those.
|
||||
TAG = "tag: "
|
||||
tags = set([r[len(TAG):] for r in refs if r.startswith(TAG)])
|
||||
if not tags:
|
||||
# Either we're using git < 1.8.3, or there really are no tags. We use
|
||||
# a heuristic: assume all version tags have a digit. The old git %d
|
||||
# expansion behaves like git log --decorate=short and strips out the
|
||||
# refs/heads/ and refs/tags/ prefixes that would let us distinguish
|
||||
# between branches and tags. By ignoring refnames without digits, we
|
||||
# filter out many common branch names like "release" and
|
||||
# "stabilization", as well as "HEAD" and "master".
|
||||
tags = set([r for r in refs if re.search(r'\d', r)])
|
||||
if verbose:
|
||||
print("discarding '%s', no digits" % ",".join(refs - tags))
|
||||
if verbose:
|
||||
print("likely tags: %s" % ",".join(sorted(tags)))
|
||||
for ref in sorted(tags):
|
||||
# sorting will prefer e.g. "2.0" over "2.0rc1"
|
||||
if ref.startswith(tag_prefix):
|
||||
r = ref[len(tag_prefix):]
|
||||
if verbose:
|
||||
print("picking %s" % r)
|
||||
return {"version": r,
|
||||
"full-revisionid": keywords["full"].strip(),
|
||||
"dirty": False, "error": None,
|
||||
"date": date}
|
||||
# no suitable tags, so version is "0+unknown", but full hex is still there
|
||||
if verbose:
|
||||
print("no suitable tags, using unknown + full revision id")
|
||||
return {"version": "0+unknown",
|
||||
"full-revisionid": keywords["full"].strip(),
|
||||
"dirty": False, "error": "no suitable tags", "date": None}
|
||||
|
||||
|
||||
@register_vcs_handler("git", "pieces_from_vcs")
|
||||
def git_pieces_from_vcs(tag_prefix, root, verbose, run_command=run_command):
|
||||
"""Get version from 'git describe' in the root of the source tree.
|
||||
|
||||
This only gets called if the git-archive 'subst' keywords were *not*
|
||||
expanded, and _version.py hasn't already been rewritten with a short
|
||||
version string, meaning we're inside a checked out source tree.
|
||||
"""
|
||||
GITS = ["git"]
|
||||
if sys.platform == "win32":
|
||||
GITS = ["git.cmd", "git.exe"]
|
||||
|
||||
out, rc = run_command(GITS, ["rev-parse", "--git-dir"], cwd=root,
|
||||
hide_stderr=True)
|
||||
if rc != 0:
|
||||
if verbose:
|
||||
print("Directory %s not under git control" % root)
|
||||
raise NotThisMethod("'git rev-parse --git-dir' returned error")
|
||||
|
||||
# if there is a tag matching tag_prefix, this yields TAG-NUM-gHEX[-dirty]
|
||||
# if there isn't one, this yields HEX[-dirty] (no NUM)
|
||||
describe_out, rc = run_command(GITS, ["describe", "--tags", "--dirty",
|
||||
"--always", "--long",
|
||||
"--match", "%s*" % tag_prefix],
|
||||
cwd=root)
|
||||
# --long was added in git-1.5.5
|
||||
if describe_out is None:
|
||||
raise NotThisMethod("'git describe' failed")
|
||||
describe_out = describe_out.strip()
|
||||
full_out, rc = run_command(GITS, ["rev-parse", "HEAD"], cwd=root)
|
||||
if full_out is None:
|
||||
raise NotThisMethod("'git rev-parse' failed")
|
||||
full_out = full_out.strip()
|
||||
|
||||
pieces = {}
|
||||
pieces["long"] = full_out
|
||||
pieces["short"] = full_out[:7] # maybe improved later
|
||||
pieces["error"] = None
|
||||
|
||||
# parse describe_out. It will be like TAG-NUM-gHEX[-dirty] or HEX[-dirty]
|
||||
# TAG might have hyphens.
|
||||
git_describe = describe_out
|
||||
|
||||
# look for -dirty suffix
|
||||
dirty = git_describe.endswith("-dirty")
|
||||
pieces["dirty"] = dirty
|
||||
if dirty:
|
||||
git_describe = git_describe[:git_describe.rindex("-dirty")]
|
||||
|
||||
# now we have TAG-NUM-gHEX or HEX
|
||||
|
||||
if "-" in git_describe:
|
||||
# TAG-NUM-gHEX
|
||||
mo = re.search(r'^(.+)-(\d+)-g([0-9a-f]+)$', git_describe)
|
||||
if not mo:
|
||||
# unparseable. Maybe git-describe is misbehaving?
|
||||
pieces["error"] = ("unable to parse git-describe output: '%s'"
|
||||
% describe_out)
|
||||
return pieces
|
||||
|
||||
# tag
|
||||
full_tag = mo.group(1)
|
||||
if not full_tag.startswith(tag_prefix):
|
||||
if verbose:
|
||||
fmt = "tag '%s' doesn't start with prefix '%s'"
|
||||
print(fmt % (full_tag, tag_prefix))
|
||||
pieces["error"] = ("tag '%s' doesn't start with prefix '%s'"
|
||||
% (full_tag, tag_prefix))
|
||||
return pieces
|
||||
pieces["closest-tag"] = full_tag[len(tag_prefix):]
|
||||
|
||||
# distance: number of commits since tag
|
||||
pieces["distance"] = int(mo.group(2))
|
||||
|
||||
# commit: short hex revision ID
|
||||
pieces["short"] = mo.group(3)
|
||||
|
||||
else:
|
||||
# HEX: no tags
|
||||
pieces["closest-tag"] = None
|
||||
count_out, rc = run_command(GITS, ["rev-list", "HEAD", "--count"],
|
||||
cwd=root)
|
||||
pieces["distance"] = int(count_out) # total number of commits
|
||||
|
||||
# commit date: see ISO-8601 comment in git_versions_from_keywords()
|
||||
date = run_command(GITS, ["show", "-s", "--format=%ci", "HEAD"],
|
||||
cwd=root)[0].strip()
|
||||
pieces["date"] = date.strip().replace(" ", "T", 1).replace(" ", "", 1)
|
||||
|
||||
return pieces
|
||||
|
||||
|
||||
def plus_or_dot(pieces):
|
||||
"""Return a + if we don't already have one, else return a ."""
|
||||
if "+" in pieces.get("closest-tag", ""):
|
||||
return "."
|
||||
return "+"
|
||||
|
||||
|
||||
def render_pep440(pieces):
|
||||
"""Build up version string, with post-release "local version identifier".
|
||||
|
||||
Our goal: TAG[+DISTANCE.gHEX[.dirty]] . Note that if you
|
||||
get a tagged build and then dirty it, you'll get TAG+0.gHEX.dirty
|
||||
|
||||
Exceptions:
|
||||
1: no tags. git_describe was just HEX. 0+untagged.DISTANCE.gHEX[.dirty]
|
||||
"""
|
||||
if pieces["closest-tag"]:
|
||||
rendered = pieces["closest-tag"]
|
||||
if pieces["distance"] or pieces["dirty"]:
|
||||
rendered += plus_or_dot(pieces)
|
||||
rendered += "%d.g%s" % (pieces["distance"], pieces["short"])
|
||||
if pieces["dirty"]:
|
||||
rendered += ".dirty"
|
||||
else:
|
||||
# exception #1
|
||||
rendered = "0+untagged.%d.g%s" % (pieces["distance"],
|
||||
pieces["short"])
|
||||
if pieces["dirty"]:
|
||||
rendered += ".dirty"
|
||||
return rendered
|
||||
|
||||
|
||||
def render_pep440_pre(pieces):
|
||||
"""TAG[.post.devDISTANCE] -- No -dirty.
|
||||
|
||||
Exceptions:
|
||||
1: no tags. 0.post.devDISTANCE
|
||||
"""
|
||||
if pieces["closest-tag"]:
|
||||
rendered = pieces["closest-tag"]
|
||||
if pieces["distance"]:
|
||||
rendered += ".post.dev%d" % pieces["distance"]
|
||||
else:
|
||||
# exception #1
|
||||
rendered = "0.post.dev%d" % pieces["distance"]
|
||||
return rendered
|
||||
|
||||
|
||||
def render_pep440_post(pieces):
|
||||
"""TAG[.postDISTANCE[.dev0]+gHEX] .
|
||||
|
||||
The ".dev0" means dirty. Note that .dev0 sorts backwards
|
||||
(a dirty tree will appear "older" than the corresponding clean one),
|
||||
but you shouldn't be releasing software with -dirty anyways.
|
||||
|
||||
Exceptions:
|
||||
1: no tags. 0.postDISTANCE[.dev0]
|
||||
"""
|
||||
if pieces["closest-tag"]:
|
||||
rendered = pieces["closest-tag"]
|
||||
if pieces["distance"] or pieces["dirty"]:
|
||||
rendered += ".post%d" % pieces["distance"]
|
||||
if pieces["dirty"]:
|
||||
rendered += ".dev0"
|
||||
rendered += plus_or_dot(pieces)
|
||||
rendered += "g%s" % pieces["short"]
|
||||
else:
|
||||
# exception #1
|
||||
rendered = "0.post%d" % pieces["distance"]
|
||||
if pieces["dirty"]:
|
||||
rendered += ".dev0"
|
||||
rendered += "+g%s" % pieces["short"]
|
||||
return rendered
|
||||
|
||||
|
||||
def render_pep440_old(pieces):
|
||||
"""TAG[.postDISTANCE[.dev0]] .
|
||||
|
||||
The ".dev0" means dirty.
|
||||
|
||||
Eexceptions:
|
||||
1: no tags. 0.postDISTANCE[.dev0]
|
||||
"""
|
||||
if pieces["closest-tag"]:
|
||||
rendered = pieces["closest-tag"]
|
||||
if pieces["distance"] or pieces["dirty"]:
|
||||
rendered += ".post%d" % pieces["distance"]
|
||||
if pieces["dirty"]:
|
||||
rendered += ".dev0"
|
||||
else:
|
||||
# exception #1
|
||||
rendered = "0.post%d" % pieces["distance"]
|
||||
if pieces["dirty"]:
|
||||
rendered += ".dev0"
|
||||
return rendered
|
||||
|
||||
|
||||
def render_git_describe(pieces):
|
||||
"""TAG[-DISTANCE-gHEX][-dirty].
|
||||
|
||||
Like 'git describe --tags --dirty --always'.
|
||||
|
||||
Exceptions:
|
||||
1: no tags. HEX[-dirty] (note: no 'g' prefix)
|
||||
"""
|
||||
if pieces["closest-tag"]:
|
||||
rendered = pieces["closest-tag"]
|
||||
if pieces["distance"]:
|
||||
rendered += "-%d-g%s" % (pieces["distance"], pieces["short"])
|
||||
else:
|
||||
# exception #1
|
||||
rendered = pieces["short"]
|
||||
if pieces["dirty"]:
|
||||
rendered += "-dirty"
|
||||
return rendered
|
||||
|
||||
|
||||
def render_git_describe_long(pieces):
|
||||
"""TAG-DISTANCE-gHEX[-dirty].
|
||||
|
||||
Like 'git describe --tags --dirty --always -long'.
|
||||
The distance/hash is unconditional.
|
||||
|
||||
Exceptions:
|
||||
1: no tags. HEX[-dirty] (note: no 'g' prefix)
|
||||
"""
|
||||
if pieces["closest-tag"]:
|
||||
rendered = pieces["closest-tag"]
|
||||
rendered += "-%d-g%s" % (pieces["distance"], pieces["short"])
|
||||
else:
|
||||
# exception #1
|
||||
rendered = pieces["short"]
|
||||
if pieces["dirty"]:
|
||||
rendered += "-dirty"
|
||||
return rendered
|
||||
|
||||
|
||||
def render(pieces, style):
|
||||
"""Render the given version pieces into the requested style."""
|
||||
if pieces["error"]:
|
||||
return {"version": "unknown",
|
||||
"full-revisionid": pieces.get("long"),
|
||||
"dirty": None,
|
||||
"error": pieces["error"],
|
||||
"date": None}
|
||||
|
||||
if not style or style == "default":
|
||||
style = "pep440" # the default
|
||||
|
||||
if style == "pep440":
|
||||
rendered = render_pep440(pieces)
|
||||
elif style == "pep440-pre":
|
||||
rendered = render_pep440_pre(pieces)
|
||||
elif style == "pep440-post":
|
||||
rendered = render_pep440_post(pieces)
|
||||
elif style == "pep440-old":
|
||||
rendered = render_pep440_old(pieces)
|
||||
elif style == "git-describe":
|
||||
rendered = render_git_describe(pieces)
|
||||
elif style == "git-describe-long":
|
||||
rendered = render_git_describe_long(pieces)
|
||||
else:
|
||||
raise ValueError("unknown style '%s'" % style)
|
||||
|
||||
return {"version": rendered, "full-revisionid": pieces["long"],
|
||||
"dirty": pieces["dirty"], "error": None,
|
||||
"date": pieces.get("date")}
|
||||
|
||||
|
||||
def get_versions():
|
||||
"""Get version information or return default if unable to do so."""
|
||||
# I am in _version.py, which lives at ROOT/VERSIONFILE_SOURCE. If we have
|
||||
# __file__, we can work backwards from there to the root. Some
|
||||
# py2exe/bbfreeze/non-CPython implementations don't do __file__, in which
|
||||
# case we can only use expanded keywords.
|
||||
|
||||
cfg = get_config()
|
||||
verbose = cfg.verbose
|
||||
|
||||
try:
|
||||
return git_versions_from_keywords(get_keywords(), cfg.tag_prefix,
|
||||
verbose)
|
||||
except NotThisMethod:
|
||||
pass
|
||||
|
||||
try:
|
||||
root = os.path.realpath(__file__)
|
||||
# versionfile_source is the relative path from the top of the source
|
||||
# tree (where the .git directory might live) to this file. Invert
|
||||
# this to find the root from __file__.
|
||||
for i in cfg.versionfile_source.split('/'):
|
||||
root = os.path.dirname(root)
|
||||
except NameError:
|
||||
return {"version": "0+unknown", "full-revisionid": None,
|
||||
"dirty": None,
|
||||
"error": "unable to find root of source tree",
|
||||
"date": None}
|
||||
|
||||
try:
|
||||
pieces = git_pieces_from_vcs(cfg.tag_prefix, root, verbose)
|
||||
return render(pieces, cfg.style)
|
||||
except NotThisMethod:
|
||||
pass
|
||||
|
||||
try:
|
||||
if cfg.parentdir_prefix:
|
||||
return versions_from_parentdir(cfg.parentdir_prefix, root, verbose)
|
||||
except NotThisMethod:
|
||||
pass
|
||||
|
||||
return {"version": "0+unknown", "full-revisionid": None,
|
||||
"dirty": None,
|
||||
"error": "unable to compute version", "date": None}
|
||||
56
ccxt/static_dependencies/ecdsa/curves.py
Normal file
56
ccxt/static_dependencies/ecdsa/curves.py
Normal file
@@ -0,0 +1,56 @@
|
||||
from __future__ import division
|
||||
|
||||
from . import der, ecdsa
|
||||
|
||||
|
||||
class UnknownCurveError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def orderlen(order):
|
||||
return (1+len("%x" % order))//2 # bytes
|
||||
|
||||
|
||||
# the NIST curves
|
||||
class Curve:
|
||||
def __init__(self, name, curve, generator, oid, openssl_name=None):
|
||||
self.name = name
|
||||
self.openssl_name = openssl_name # maybe None
|
||||
self.curve = curve
|
||||
self.generator = generator
|
||||
self.order = generator.order()
|
||||
self.baselen = orderlen(self.order)
|
||||
self.verifying_key_length = 2*self.baselen
|
||||
self.signature_length = 2*self.baselen
|
||||
self.oid = oid
|
||||
self.encoded_oid = der.encode_oid(*oid)
|
||||
|
||||
NIST192p = Curve("NIST192p", ecdsa.curve_192,
|
||||
ecdsa.generator_192,
|
||||
(1, 2, 840, 10045, 3, 1, 1), "prime192v1")
|
||||
NIST224p = Curve("NIST224p", ecdsa.curve_224,
|
||||
ecdsa.generator_224,
|
||||
(1, 3, 132, 0, 33), "secp224r1")
|
||||
NIST256p = Curve("NIST256p", ecdsa.curve_256,
|
||||
ecdsa.generator_256,
|
||||
(1, 2, 840, 10045, 3, 1, 7), "prime256v1")
|
||||
NIST384p = Curve("NIST384p", ecdsa.curve_384,
|
||||
ecdsa.generator_384,
|
||||
(1, 3, 132, 0, 34), "secp384r1")
|
||||
NIST521p = Curve("NIST521p", ecdsa.curve_521,
|
||||
ecdsa.generator_521,
|
||||
(1, 3, 132, 0, 35), "secp521r1")
|
||||
SECP256k1 = Curve("SECP256k1", ecdsa.curve_secp256k1,
|
||||
ecdsa.generator_secp256k1,
|
||||
(1, 3, 132, 0, 10), "secp256k1")
|
||||
|
||||
curves = [NIST192p, NIST224p, NIST256p, NIST384p, NIST521p, SECP256k1]
|
||||
|
||||
|
||||
def find_curve(oid_curve):
|
||||
for c in curves:
|
||||
if c.oid == oid_curve:
|
||||
return c
|
||||
raise UnknownCurveError("I don't know about the curve with oid %s."
|
||||
"I only know about these: %s" %
|
||||
(oid_curve, [c.name for c in curves]))
|
||||
221
ccxt/static_dependencies/ecdsa/der.py
Normal file
221
ccxt/static_dependencies/ecdsa/der.py
Normal file
@@ -0,0 +1,221 @@
|
||||
from __future__ import division
|
||||
|
||||
import binascii
|
||||
import base64
|
||||
|
||||
|
||||
class UnexpectedDER(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def encode_constructed(tag, value):
|
||||
return int.to_bytes(0xa0+tag, 1, 'big') + encode_length(len(value)) + value
|
||||
|
||||
|
||||
def encode_integer(r):
|
||||
assert r >= 0 # can't support negative numbers yet
|
||||
h = ("%x" % r).encode()
|
||||
if len(h) % 2:
|
||||
h = b'0' + h
|
||||
s = binascii.unhexlify(h)
|
||||
num = s[0] if isinstance(s[0], int) else ord(s[0])
|
||||
if num <= 0x7f:
|
||||
return b'\x02' + int.to_bytes(len(s), 1, 'big') + s
|
||||
else:
|
||||
# DER integers are two's complement, so if the first byte is
|
||||
# 0x80-0xff then we need an extra 0x00 byte to prevent it from
|
||||
# looking negative.
|
||||
return b'\x02' + int.to_bytes(len(s)+1, 1, 'big') + b'\x00' + s
|
||||
|
||||
|
||||
def encode_bitstring(s):
|
||||
return b'\x03' + encode_length(len(s)) + s
|
||||
|
||||
|
||||
def encode_octet_string(s):
|
||||
return b'\x04' + encode_length(len(s)) + s
|
||||
|
||||
|
||||
def encode_oid(first, second, *pieces):
|
||||
assert first <= 2
|
||||
assert second <= 39
|
||||
encoded_pieces = [int.to_bytes(40*first+second, 1, 'big')] + [encode_number(p)
|
||||
for p in pieces]
|
||||
body = b''.join(encoded_pieces)
|
||||
return b'\x06' + encode_length(len(body)) + body
|
||||
|
||||
|
||||
def encode_sequence(*encoded_pieces):
|
||||
total_len = sum([len(p) for p in encoded_pieces])
|
||||
return b'\x30' + encode_length(total_len) + b''.join(encoded_pieces)
|
||||
|
||||
|
||||
def encode_number(n):
|
||||
b128_digits = []
|
||||
while n:
|
||||
b128_digits.insert(0, (n & 0x7f) | 0x80)
|
||||
n = n >> 7
|
||||
if not b128_digits:
|
||||
b128_digits.append(0)
|
||||
b128_digits[-1] &= 0x7f
|
||||
return b''.join([int.to_bytes(d, 1, 'big') for d in b128_digits])
|
||||
|
||||
|
||||
def remove_constructed(string):
|
||||
s0 = string[0] if isinstance(string[0], int) else ord(string[0])
|
||||
if (s0 & 0xe0) != 0xa0:
|
||||
raise UnexpectedDER("wanted constructed tag (0xa0-0xbf), got 0x%02x"
|
||||
% s0)
|
||||
tag = s0 & 0x1f
|
||||
length, llen = read_length(string[1:])
|
||||
body = string[1+llen:1+llen+length]
|
||||
rest = string[1+llen+length:]
|
||||
return tag, body, rest
|
||||
|
||||
|
||||
def remove_sequence(string):
|
||||
if not string.startswith(b'\x30'):
|
||||
n = string[0] if isinstance(string[0], int) else ord(string[0])
|
||||
raise UnexpectedDER("wanted sequence (0x30), got 0x%02x" % n)
|
||||
length, lengthlength = read_length(string[1:])
|
||||
endseq = 1+lengthlength+length
|
||||
return string[1+lengthlength:endseq], string[endseq:]
|
||||
|
||||
|
||||
def remove_octet_string(string):
|
||||
if not string.startswith(b'\x04'):
|
||||
n = string[0] if isinstance(string[0], int) else ord(string[0])
|
||||
raise UnexpectedDER("wanted octetstring (0x04), got 0x%02x" % n)
|
||||
length, llen = read_length(string[1:])
|
||||
body = string[1+llen:1+llen+length]
|
||||
rest = string[1+llen+length:]
|
||||
return body, rest
|
||||
|
||||
|
||||
def remove_object(string):
|
||||
if not string.startswith(b'\x06'):
|
||||
n = string[0] if isinstance(string[0], int) else ord(string[0])
|
||||
raise UnexpectedDER("wanted object (0x06), got 0x%02x" % n)
|
||||
length, lengthlength = read_length(string[1:])
|
||||
body = string[1+lengthlength:1+lengthlength+length]
|
||||
rest = string[1+lengthlength+length:]
|
||||
numbers = []
|
||||
while body:
|
||||
n, ll = read_number(body)
|
||||
numbers.append(n)
|
||||
body = body[ll:]
|
||||
n0 = numbers.pop(0)
|
||||
first = n0//40
|
||||
second = n0-(40*first)
|
||||
numbers.insert(0, first)
|
||||
numbers.insert(1, second)
|
||||
return tuple(numbers), rest
|
||||
|
||||
|
||||
def remove_integer(string):
|
||||
if not string.startswith(b'\x02'):
|
||||
n = string[0] if isinstance(string[0], int) else ord(string[0])
|
||||
raise UnexpectedDER("wanted integer (0x02), got 0x%02x" % n)
|
||||
length, llen = read_length(string[1:])
|
||||
numberbytes = string[1+llen:1+llen+length]
|
||||
rest = string[1+llen+length:]
|
||||
nbytes = numberbytes[0] if isinstance(numberbytes[0], int) else ord(numberbytes[0])
|
||||
assert nbytes < 0x80 # can't support negative numbers yet
|
||||
return int(binascii.hexlify(numberbytes), 16), rest
|
||||
|
||||
|
||||
def read_number(string):
|
||||
number = 0
|
||||
llen = 0
|
||||
# base-128 big endian, with b7 set in all but the last byte
|
||||
while True:
|
||||
if llen > len(string):
|
||||
raise UnexpectedDER("ran out of length bytes")
|
||||
number = number << 7
|
||||
d = string[llen] if isinstance(string[llen], int) else ord(string[llen])
|
||||
number += (d & 0x7f)
|
||||
llen += 1
|
||||
if not d & 0x80:
|
||||
break
|
||||
return number, llen
|
||||
|
||||
|
||||
def encode_length(l):
|
||||
assert l >= 0
|
||||
if l < 0x80:
|
||||
return int.to_bytes(l, 1, 'big')
|
||||
s = ("%x" % l).encode()
|
||||
if len(s) % 2:
|
||||
s = b'0' + s
|
||||
s = binascii.unhexlify(s)
|
||||
llen = len(s)
|
||||
return int.to_bytes(0x80 | llen, 1, 'big') + s
|
||||
|
||||
|
||||
def read_length(string):
|
||||
num = string[0] if isinstance(string[0], int) else ord(string[0])
|
||||
if not (num & 0x80):
|
||||
# short form
|
||||
return (num & 0x7f), 1
|
||||
# else long-form: b0&0x7f is number of additional base256 length bytes,
|
||||
# big-endian
|
||||
llen = num & 0x7f
|
||||
if llen > len(string)-1:
|
||||
raise UnexpectedDER("ran out of length bytes")
|
||||
return int(binascii.hexlify(string[1:1+llen]), 16), 1+llen
|
||||
|
||||
|
||||
def remove_bitstring(string):
|
||||
num = string[0] if isinstance(string[0], int) else ord(string[0])
|
||||
if not string.startswith(b'\x03'):
|
||||
raise UnexpectedDER("wanted bitstring (0x03), got 0x%02x" % num)
|
||||
length, llen = read_length(string[1:])
|
||||
body = string[1+llen:1+llen+length]
|
||||
rest = string[1+llen+length:]
|
||||
return body, rest
|
||||
|
||||
# SEQUENCE([1, STRING(secexp), cont[0], OBJECT(curvename), cont[1], BINTSTRING)
|
||||
|
||||
|
||||
# signatures: (from RFC3279)
|
||||
# ansi-X9-62 OBJECT IDENTIFIER ::= {
|
||||
# iso(1) member-body(2) us(840) 10045 }
|
||||
#
|
||||
# id-ecSigType OBJECT IDENTIFIER ::= {
|
||||
# ansi-X9-62 signatures(4) }
|
||||
# ecdsa-with-SHA1 OBJECT IDENTIFIER ::= {
|
||||
# id-ecSigType 1 }
|
||||
## so 1,2,840,10045,4,1
|
||||
## so 0x42, .. ..
|
||||
|
||||
# Ecdsa-Sig-Value ::= SEQUENCE {
|
||||
# r INTEGER,
|
||||
# s INTEGER }
|
||||
|
||||
# id-public-key-type OBJECT IDENTIFIER ::= { ansi-X9.62 2 }
|
||||
#
|
||||
# id-ecPublicKey OBJECT IDENTIFIER ::= { id-publicKeyType 1 }
|
||||
|
||||
# I think the secp224r1 identifier is (t=06,l=05,v=2b81040021)
|
||||
# secp224r1 OBJECT IDENTIFIER ::= {
|
||||
# iso(1) identified-organization(3) certicom(132) curve(0) 33 }
|
||||
# and the secp384r1 is (t=06,l=05,v=2b81040022)
|
||||
# secp384r1 OBJECT IDENTIFIER ::= {
|
||||
# iso(1) identified-organization(3) certicom(132) curve(0) 34 }
|
||||
|
||||
def unpem(pem):
|
||||
if isinstance(pem, str):
|
||||
pem = pem.encode()
|
||||
|
||||
d = b''.join([l.strip() for l in pem.split(b'\n')
|
||||
if l and not l.startswith(b'-----')])
|
||||
return base64.b64decode(d)
|
||||
|
||||
|
||||
def topem(der, name):
|
||||
b64 = base64.b64encode(der)
|
||||
lines = [("-----BEGIN %s-----\n" % name).encode()]
|
||||
lines.extend([b64[start:start+64]+b'\n'
|
||||
for start in range(0, len(b64), 64)])
|
||||
lines.append(("-----END %s-----\n" % name).encode())
|
||||
return b''.join(lines)
|
||||
310
ccxt/static_dependencies/ecdsa/ecdsa.py
Normal file
310
ccxt/static_dependencies/ecdsa/ecdsa.py
Normal file
@@ -0,0 +1,310 @@
|
||||
#! /usr/bin/env python
|
||||
|
||||
"""
|
||||
Implementation of Elliptic-Curve Digital Signatures.
|
||||
|
||||
Classes and methods for elliptic-curve signatures:
|
||||
private keys, public keys, signatures,
|
||||
NIST prime-modulus curves with modulus lengths of
|
||||
192, 224, 256, 384, and 521 bits.
|
||||
|
||||
Example:
|
||||
|
||||
# (In real-life applications, you would probably want to
|
||||
# protect against defects in SystemRandom.)
|
||||
from random import SystemRandom
|
||||
randrange = SystemRandom().randrange
|
||||
|
||||
# Generate a public/private key pair using the NIST Curve P-192:
|
||||
|
||||
g = generator_192
|
||||
n = g.order()
|
||||
secret = randrange( 1, n )
|
||||
pubkey = Public_key( g, g * secret )
|
||||
privkey = Private_key( pubkey, secret )
|
||||
|
||||
# Signing a hash value:
|
||||
|
||||
hash = randrange( 1, n )
|
||||
signature = privkey.sign( hash, randrange( 1, n ) )
|
||||
|
||||
# Verifying a signature for a hash value:
|
||||
|
||||
if pubkey.verifies( hash, signature ):
|
||||
print_("Demo verification succeeded.")
|
||||
else:
|
||||
print_("*** Demo verification failed.")
|
||||
|
||||
# Verification fails if the hash value is modified:
|
||||
|
||||
if pubkey.verifies( hash-1, signature ):
|
||||
print_("**** Demo verification failed to reject tampered hash.")
|
||||
else:
|
||||
print_("Demo verification correctly rejected tampered hash.")
|
||||
|
||||
Version of 2009.05.16.
|
||||
|
||||
Revision history:
|
||||
2005.12.31 - Initial version.
|
||||
2008.11.25 - Substantial revisions introducing new classes.
|
||||
2009.05.16 - Warn against using random.randrange in real applications.
|
||||
2009.05.17 - Use random.SystemRandom by default.
|
||||
|
||||
Written in 2005 by Peter Pearson and placed in the public domain.
|
||||
"""
|
||||
|
||||
from . import ellipticcurve
|
||||
from . import numbertheory
|
||||
|
||||
|
||||
class RSZeroError(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
class Signature(object):
|
||||
"""ECDSA signature.
|
||||
"""
|
||||
|
||||
def __init__(self, r, s, recovery_param):
|
||||
self.r = r
|
||||
self.s = s
|
||||
self.recovery_param = recovery_param
|
||||
|
||||
def recover_public_keys(self, hash, generator):
|
||||
"""Returns two public keys for which the signature is valid
|
||||
hash is signed hash
|
||||
generator is the used generator of the signature
|
||||
"""
|
||||
curve = generator.curve()
|
||||
n = generator.order()
|
||||
r = self.r
|
||||
s = self.s
|
||||
e = hash
|
||||
x = r
|
||||
|
||||
# Compute the curve point with x as x-coordinate
|
||||
alpha = (pow(x, 3, curve.p()) + (curve.a() * x) + curve.b()) % curve.p()
|
||||
beta = numbertheory.square_root_mod_prime(alpha, curve.p())
|
||||
y = beta if beta % 2 == 0 else curve.p() - beta
|
||||
|
||||
# Compute the public key
|
||||
R1 = ellipticcurve.Point(curve, x, y, n)
|
||||
Q1 = numbertheory.inverse_mod(r, n) * (s * R1 + (-e % n) * generator)
|
||||
Pk1 = Public_key(generator, Q1)
|
||||
|
||||
# And the second solution
|
||||
R2 = ellipticcurve.Point(curve, x, -y, n)
|
||||
Q2 = numbertheory.inverse_mod(r, n) * (s * R2 + (-e % n) * generator)
|
||||
Pk2 = Public_key(generator, Q2)
|
||||
|
||||
return [Pk1, Pk2]
|
||||
|
||||
|
||||
class Public_key(object):
|
||||
"""Public key for ECDSA.
|
||||
"""
|
||||
|
||||
def __init__(self, generator, point):
|
||||
"""generator is the Point that generates the group,
|
||||
point is the Point that defines the public key.
|
||||
"""
|
||||
|
||||
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 == ellipticcurve.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):
|
||||
"""Verify that signature is a valid signature of hash.
|
||||
Return True if the signature is valid.
|
||||
"""
|
||||
|
||||
# From X9.62 J.3.1.
|
||||
|
||||
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 = numbertheory.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):
|
||||
"""Private key for ECDSA.
|
||||
"""
|
||||
|
||||
def __init__(self, public_key, secret_multiplier):
|
||||
"""public_key is of class Public_key;
|
||||
secret_multiplier is a large integer.
|
||||
"""
|
||||
|
||||
self.public_key = public_key
|
||||
self.secret_multiplier = secret_multiplier
|
||||
|
||||
def sign(self, hash, random_k):
|
||||
"""Return a signature for the provided hash, using the provided
|
||||
random nonce. It is absolutely vital that random_k be an unpredictable
|
||||
number in the range [1, self.public_key.point.order()-1]. If
|
||||
an attacker can guess random_k, he can compute our private key from a
|
||||
single signature. Also, if an attacker knows a few high-order
|
||||
bits (or a few low-order bits) of random_k, he can compute our private
|
||||
key from many signatures. The generation of nonces with adequate
|
||||
cryptographic strength is very difficult and far beyond the scope
|
||||
of this comment.
|
||||
|
||||
May raise RuntimeError, in which case retrying with a new
|
||||
random value k is in order.
|
||||
"""
|
||||
|
||||
G = self.public_key.generator
|
||||
n = G.order()
|
||||
k = random_k % n
|
||||
p1 = k * G
|
||||
r = p1.x() % n
|
||||
if r == 0:
|
||||
raise RSZeroError("amazingly unlucky random number r")
|
||||
s = (numbertheory.inverse_mod(k, n) *
|
||||
(hash + (self.secret_multiplier * r) % n)) % n
|
||||
if s == 0:
|
||||
raise RSZeroError("amazingly unlucky random number s")
|
||||
recovery_param = p1.y() % 2 or (2 if p1.x() == k else 0)
|
||||
return Signature(r, s, recovery_param)
|
||||
|
||||
|
||||
def int_to_string(x):
|
||||
"""Convert integer x into a string of bytes, as per X9.62."""
|
||||
assert x >= 0
|
||||
if x == 0:
|
||||
return b'\0'
|
||||
result = []
|
||||
while x:
|
||||
ordinal = x & 0xFF
|
||||
result.append(int.to_bytes(ordinal, 1, 'big'))
|
||||
x >>= 8
|
||||
|
||||
result.reverse()
|
||||
return b''.join(result)
|
||||
|
||||
|
||||
def string_to_int(s):
|
||||
"""Convert a string of bytes into an integer, as per X9.62."""
|
||||
result = 0
|
||||
for c in s:
|
||||
if not isinstance(c, int):
|
||||
c = ord(c)
|
||||
result = 256 * result + c
|
||||
return result
|
||||
|
||||
|
||||
def digest_integer(m):
|
||||
"""Convert an integer into a string of bytes, compute
|
||||
its SHA-1 hash, and convert the result to an integer."""
|
||||
#
|
||||
# I don't expect this function to be used much. I wrote
|
||||
# it in order to be able to duplicate the examples
|
||||
# in ECDSAVS.
|
||||
#
|
||||
from hashlib import sha1
|
||||
return string_to_int(sha1(int_to_string(m)).digest())
|
||||
|
||||
|
||||
def point_is_valid(generator, x, y):
|
||||
"""Is (x,y) a valid public key based on the specified generator?"""
|
||||
|
||||
# These are the tests specified in X9.62.
|
||||
|
||||
n = generator.order()
|
||||
curve = generator.curve()
|
||||
if x < 0 or n <= x or y < 0 or n <= y:
|
||||
return False
|
||||
if not curve.contains_point(x, y):
|
||||
return False
|
||||
if not n * ellipticcurve.Point(curve, x, y) == ellipticcurve.INFINITY:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
# NIST Curve P-192:
|
||||
_p = 6277101735386680763835789423207666416083908700390324961279
|
||||
_r = 6277101735386680763835789423176059013767194773182842284081
|
||||
# s = 0x3045ae6fc8422f64ed579528d38120eae12196d5L
|
||||
# c = 0x3099d2bbbfcb2538542dcd5fb078b6ef5f3d6fe2c745de65L
|
||||
_b = 0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1
|
||||
_Gx = 0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012
|
||||
_Gy = 0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811
|
||||
|
||||
curve_192 = ellipticcurve.CurveFp(_p, -3, _b)
|
||||
generator_192 = ellipticcurve.Point(curve_192, _Gx, _Gy, _r)
|
||||
|
||||
# NIST Curve P-224:
|
||||
_p = 26959946667150639794667015087019630673557916260026308143510066298881
|
||||
_r = 26959946667150639794667015087019625940457807714424391721682722368061
|
||||
# s = 0xbd71344799d5c7fcdc45b59fa3b9ab8f6a948bc5L
|
||||
# c = 0x5b056c7e11dd68f40469ee7f3c7a7d74f7d121116506d031218291fbL
|
||||
_b = 0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4
|
||||
_Gx = 0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21
|
||||
_Gy = 0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34
|
||||
|
||||
curve_224 = ellipticcurve.CurveFp(_p, -3, _b)
|
||||
generator_224 = ellipticcurve.Point(curve_224, _Gx, _Gy, _r)
|
||||
|
||||
# NIST Curve P-256:
|
||||
_p = 115792089210356248762697446949407573530086143415290314195533631308867097853951
|
||||
_r = 115792089210356248762697446949407573529996955224135760342422259061068512044369
|
||||
# s = 0xc49d360886e704936a6678e1139d26b7819f7e90L
|
||||
# c = 0x7efba1662985be9403cb055c75d4f7e0ce8d84a9c5114abcaf3177680104fa0dL
|
||||
_b = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b
|
||||
_Gx = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296
|
||||
_Gy = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5
|
||||
|
||||
curve_256 = ellipticcurve.CurveFp(_p, -3, _b)
|
||||
generator_256 = ellipticcurve.Point(curve_256, _Gx, _Gy, _r)
|
||||
|
||||
# NIST Curve P-384:
|
||||
_p = 39402006196394479212279040100143613805079739270465446667948293404245721771496870329047266088258938001861606973112319
|
||||
_r = 39402006196394479212279040100143613805079739270465446667946905279627659399113263569398956308152294913554433653942643
|
||||
# s = 0xa335926aa319a27a1d00896a6773a4827acdac73L
|
||||
# c = 0x79d1e655f868f02fff48dcdee14151ddb80643c1406d0ca10dfe6fc52009540a495e8042ea5f744f6e184667cc722483L
|
||||
_b = 0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef
|
||||
_Gx = 0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7
|
||||
_Gy = 0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f
|
||||
|
||||
curve_384 = ellipticcurve.CurveFp(_p, -3, _b)
|
||||
generator_384 = ellipticcurve.Point(curve_384, _Gx, _Gy, _r)
|
||||
|
||||
# NIST Curve P-521:
|
||||
_p = 6864797660130609714981900799081393217269435300143305409394463459185543183397656052122559640661454554977296311391480858037121987999716643812574028291115057151
|
||||
_r = 6864797660130609714981900799081393217269435300143305409394463459185543183397655394245057746333217197532963996371363321113864768612440380340372808892707005449
|
||||
# s = 0xd09e8800291cb85396cc6717393284aaa0da64baL
|
||||
# c = 0x0b48bfa5f420a34949539d2bdfc264eeeeb077688e44fbf0ad8f6d0edb37bd6b533281000518e19f1b9ffbe0fe9ed8a3c2200b8f875e523868c70c1e5bf55bad637L
|
||||
_b = 0x051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00
|
||||
_Gx = 0xc6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66
|
||||
_Gy = 0x11839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650
|
||||
|
||||
curve_521 = ellipticcurve.CurveFp(_p, -3, _b)
|
||||
generator_521 = ellipticcurve.Point(curve_521, _Gx, _Gy, _r)
|
||||
|
||||
# Certicom secp256-k1
|
||||
_a = 0x0000000000000000000000000000000000000000000000000000000000000000
|
||||
_b = 0x0000000000000000000000000000000000000000000000000000000000000007
|
||||
_p = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2f
|
||||
_Gx = 0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798
|
||||
_Gy = 0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8
|
||||
_r = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141
|
||||
|
||||
curve_secp256k1 = ellipticcurve.CurveFp(_p, _a, _b)
|
||||
generator_secp256k1 = ellipticcurve.Point(curve_secp256k1, _Gx, _Gy, _r)
|
||||
197
ccxt/static_dependencies/ecdsa/ellipticcurve.py
Normal file
197
ccxt/static_dependencies/ecdsa/ellipticcurve.py
Normal file
@@ -0,0 +1,197 @@
|
||||
#! /usr/bin/env python
|
||||
#
|
||||
# Implementation of elliptic curves, for cryptographic applications.
|
||||
#
|
||||
# This module doesn't provide any way to choose a random elliptic
|
||||
# curve, nor to verify that an elliptic curve was chosen randomly,
|
||||
# because one can simply use NIST's standard curves.
|
||||
#
|
||||
# Notes from X9.62-1998 (draft):
|
||||
# Nomenclature:
|
||||
# - Q is a public key.
|
||||
# The "Elliptic Curve Domain Parameters" include:
|
||||
# - q is the "field size", which in our case equals p.
|
||||
# - p is a big prime.
|
||||
# - G is a point of prime order (5.1.1.1).
|
||||
# - n is the order of G (5.1.1.1).
|
||||
# Public-key validation (5.2.2):
|
||||
# - Verify that Q is not the point at infinity.
|
||||
# - Verify that X_Q and Y_Q are in [0,p-1].
|
||||
# - Verify that Q is on the curve.
|
||||
# - Verify that nQ is the point at infinity.
|
||||
# Signature generation (5.3):
|
||||
# - Pick random k from [1,n-1].
|
||||
# Signature checking (5.4.2):
|
||||
# - Verify that r and s are in [1,n-1].
|
||||
#
|
||||
# Version of 2008.11.25.
|
||||
#
|
||||
# Revision history:
|
||||
# 2005.12.31 - Initial version.
|
||||
# 2008.11.25 - Change CurveFp.is_on to contains_point.
|
||||
#
|
||||
# Written in 2005 by Peter Pearson and placed in the public domain.
|
||||
|
||||
from __future__ import division
|
||||
|
||||
from . import numbertheory
|
||||
|
||||
|
||||
class CurveFp(object):
|
||||
"""Elliptic Curve over the field of integers modulo a prime."""
|
||||
|
||||
def __init__(self, p, a, b):
|
||||
"""The curve of points satisfying y^2 = x^3 + a*x + b (mod p)."""
|
||||
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):
|
||||
"""Is the point (x,y) on this curve?"""
|
||||
return (y * y - (x * x * x + self.__a * x + self.__b)) % self.__p == 0
|
||||
|
||||
def __str__(self):
|
||||
return "CurveFp(p=%d, a=%d, b=%d)" % (self.__p, self.__a, self.__b)
|
||||
|
||||
|
||||
class Point(object):
|
||||
"""A point on an elliptic curve. Altering x and y is forbidding,
|
||||
but they can be read by the x() and y() methods."""
|
||||
|
||||
def __init__(self, curve, x, y, order=None):
|
||||
"""curve, x, y, order; order (optional) is the order of this point."""
|
||||
self.__curve = curve
|
||||
self.__x = x
|
||||
self.__y = y
|
||||
self.__order = order
|
||||
# self.curve is allowed to be None only for INFINITY:
|
||||
if self.__curve:
|
||||
assert self.__curve.contains_point(x, y)
|
||||
if order:
|
||||
assert self * order == INFINITY
|
||||
|
||||
def __eq__(self, other):
|
||||
"""Return True if the points are identical, False otherwise."""
|
||||
if self.__curve == other.__curve \
|
||||
and self.__x == other.__x \
|
||||
and self.__y == other.__y:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
def __add__(self, other):
|
||||
"""Add one point to another point."""
|
||||
|
||||
# X9.62 B.3:
|
||||
|
||||
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) * \
|
||||
numbertheory.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):
|
||||
"""Multiply a point by an integer."""
|
||||
|
||||
def leftmost_bit(x):
|
||||
assert x > 0
|
||||
result = 1
|
||||
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
|
||||
|
||||
# From X9.62 D.3.2:
|
||||
|
||||
e3 = 3 * e
|
||||
negative_self = Point(self.__curve, self.__x, -self.__y, self.__order)
|
||||
i = leftmost_bit(e3) // 2
|
||||
result = self
|
||||
# print_("Multiplying %s by %d (e3 = %d):" % (self, other, e3))
|
||||
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
|
||||
# print_(". . . i = %d, result = %s" % ( i, result ))
|
||||
i = i // 2
|
||||
|
||||
return result
|
||||
|
||||
def __rmul__(self, other):
|
||||
"""Multiply a point by an integer."""
|
||||
|
||||
return self * other
|
||||
|
||||
def __str__(self):
|
||||
if self == INFINITY:
|
||||
return "infinity"
|
||||
return "(%d,%d)" % (self.__x, self.__y)
|
||||
|
||||
def double(self):
|
||||
"""Return a new point that is twice the old."""
|
||||
|
||||
if self == INFINITY:
|
||||
return INFINITY
|
||||
|
||||
# X9.62 B.3:
|
||||
|
||||
p = self.__curve.p()
|
||||
a = self.__curve.a()
|
||||
|
||||
l = ((3 * self.__x * self.__x + a) * \
|
||||
numbertheory.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
|
||||
|
||||
|
||||
# This one point is the Point At Infinity for all purposes:
|
||||
INFINITY = Point(None, None, None)
|
||||
332
ccxt/static_dependencies/ecdsa/keys.py
Normal file
332
ccxt/static_dependencies/ecdsa/keys.py
Normal file
@@ -0,0 +1,332 @@
|
||||
import binascii
|
||||
|
||||
from . import ecdsa
|
||||
from . import der
|
||||
from . import rfc6979
|
||||
from .curves import NIST192p, find_curve
|
||||
from .ecdsa import RSZeroError
|
||||
from .util import string_to_number, number_to_string, randrange
|
||||
from .util import sigencode_string, sigdecode_string
|
||||
from .util import oid_ecPublicKey, encoded_oid_ecPublicKey
|
||||
from hashlib import sha1
|
||||
|
||||
|
||||
class BadSignatureError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class BadDigestError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class VerifyingKey:
|
||||
def __init__(self, _error__please_use_generate=None):
|
||||
if not _error__please_use_generate:
|
||||
raise TypeError("Please use VerifyingKey.generate() to "
|
||||
"construct me")
|
||||
|
||||
@classmethod
|
||||
def from_public_point(klass, point, curve=NIST192p, hashfunc=sha1):
|
||||
self = klass(_error__please_use_generate=True)
|
||||
self.curve = curve
|
||||
self.default_hashfunc = hashfunc
|
||||
self.pubkey = ecdsa.Public_key(curve.generator, point)
|
||||
self.pubkey.order = curve.order
|
||||
return self
|
||||
|
||||
@classmethod
|
||||
def from_string(klass, string, curve=NIST192p, hashfunc=sha1,
|
||||
validate_point=True):
|
||||
order = curve.order
|
||||
assert (len(string) == curve.verifying_key_length), \
|
||||
(len(string), curve.verifying_key_length)
|
||||
xs = string[:curve.baselen]
|
||||
ys = string[curve.baselen:]
|
||||
assert len(xs) == curve.baselen, (len(xs), curve.baselen)
|
||||
assert len(ys) == curve.baselen, (len(ys), curve.baselen)
|
||||
x = string_to_number(xs)
|
||||
y = string_to_number(ys)
|
||||
if validate_point:
|
||||
assert ecdsa.point_is_valid(curve.generator, x, y)
|
||||
from . import ellipticcurve
|
||||
point = ellipticcurve.Point(curve.curve, x, y, order)
|
||||
return klass.from_public_point(point, curve, hashfunc)
|
||||
|
||||
@classmethod
|
||||
def from_pem(klass, string):
|
||||
return klass.from_der(der.unpem(string))
|
||||
|
||||
@classmethod
|
||||
def from_der(klass, string):
|
||||
# [[oid_ecPublicKey,oid_curve], point_str_bitstring]
|
||||
s1, empty = der.remove_sequence(string)
|
||||
if empty != b'':
|
||||
raise der.UnexpectedDER("trailing junk after DER pubkey: %s" %
|
||||
binascii.hexlify(empty))
|
||||
s2, point_str_bitstring = der.remove_sequence(s1)
|
||||
# s2 = oid_ecPublicKey,oid_curve
|
||||
oid_pk, rest = der.remove_object(s2)
|
||||
oid_curve, empty = der.remove_object(rest)
|
||||
if empty != b'':
|
||||
raise der.UnexpectedDER("trailing junk after DER pubkey objects: %s" %
|
||||
binascii.hexlify(empty))
|
||||
assert oid_pk == oid_ecPublicKey, (oid_pk, oid_ecPublicKey)
|
||||
curve = find_curve(oid_curve)
|
||||
point_str, empty = der.remove_bitstring(point_str_bitstring)
|
||||
if empty != b'':
|
||||
raise der.UnexpectedDER("trailing junk after pubkey pointstring: %s" %
|
||||
binascii.hexlify(empty))
|
||||
assert point_str.startswith(b'\x00\x04')
|
||||
return klass.from_string(point_str[2:], curve)
|
||||
|
||||
@classmethod
|
||||
def from_public_key_recovery(klass, signature, data, curve, hashfunc=sha1, sigdecode=sigdecode_string):
|
||||
# Given a signature and corresponding message this function
|
||||
# returns a list of verifying keys for this signature and message
|
||||
|
||||
digest = hashfunc(data).digest()
|
||||
return klass.from_public_key_recovery_with_digest(signature, digest, curve, hashfunc=sha1, sigdecode=sigdecode)
|
||||
|
||||
@classmethod
|
||||
def from_public_key_recovery_with_digest(klass, signature, digest, curve, hashfunc=sha1, sigdecode=sigdecode_string):
|
||||
# Given a signature and corresponding digest this function
|
||||
# returns a list of verifying keys for this signature and message
|
||||
|
||||
generator = curve.generator
|
||||
r, s = sigdecode(signature, generator.order())
|
||||
sig = ecdsa.Signature(r, s)
|
||||
|
||||
digest_as_number = string_to_number(digest)
|
||||
pks = sig.recover_public_keys(digest_as_number, generator)
|
||||
|
||||
# Transforms the ecdsa.Public_key object into a VerifyingKey
|
||||
verifying_keys = [klass.from_public_point(pk.point, curve, hashfunc) for pk in pks]
|
||||
return verifying_keys
|
||||
|
||||
def to_string(self):
|
||||
# VerifyingKey.from_string(vk.to_string()) == vk as long as the
|
||||
# curves are the same: the curve itself is not included in the
|
||||
# serialized form
|
||||
order = self.pubkey.order
|
||||
x_str = number_to_string(self.pubkey.point.x(), order)
|
||||
y_str = number_to_string(self.pubkey.point.y(), order)
|
||||
return x_str + y_str
|
||||
|
||||
def to_pem(self):
|
||||
return der.topem(self.to_der(), "PUBLIC KEY")
|
||||
|
||||
def to_der(self):
|
||||
order = self.pubkey.order
|
||||
x_str = number_to_string(self.pubkey.point.x(), order)
|
||||
y_str = number_to_string(self.pubkey.point.y(), order)
|
||||
point_str = b'\x00\x04' + x_str + y_str
|
||||
return der.encode_sequence(der.encode_sequence(encoded_oid_ecPublicKey,
|
||||
self.curve.encoded_oid),
|
||||
der.encode_bitstring(point_str))
|
||||
|
||||
def verify(self, signature, data, hashfunc=None, sigdecode=sigdecode_string):
|
||||
hashfunc = hashfunc or self.default_hashfunc
|
||||
digest = hashfunc(data).digest()
|
||||
return self.verify_digest(signature, digest, sigdecode)
|
||||
|
||||
def verify_digest(self, signature, digest, sigdecode=sigdecode_string):
|
||||
if len(digest) > self.curve.baselen:
|
||||
raise BadDigestError("this curve (%s) is too short "
|
||||
"for your digest (%d)" % (self.curve.name,
|
||||
8 * len(digest)))
|
||||
number = string_to_number(digest)
|
||||
r, s = sigdecode(signature, self.pubkey.order)
|
||||
sig = ecdsa.Signature(r, s)
|
||||
if self.pubkey.verifies(number, sig):
|
||||
return True
|
||||
raise BadSignatureError
|
||||
|
||||
|
||||
class SigningKey:
|
||||
def __init__(self, _error__please_use_generate=None):
|
||||
if not _error__please_use_generate:
|
||||
raise TypeError("Please use SigningKey.generate() to construct me")
|
||||
|
||||
@classmethod
|
||||
def generate(klass, curve=NIST192p, entropy=None, hashfunc=sha1):
|
||||
secexp = randrange(curve.order, entropy)
|
||||
return klass.from_secret_exponent(secexp, curve, hashfunc)
|
||||
|
||||
# to create a signing key from a short (arbitrary-length) seed, convert
|
||||
# that seed into an integer with something like
|
||||
# secexp=util.randrange_from_seed__X(seed, curve.order), and then pass
|
||||
# that integer into SigningKey.from_secret_exponent(secexp, curve)
|
||||
|
||||
@classmethod
|
||||
def from_secret_exponent(klass, secexp, curve=NIST192p, hashfunc=sha1):
|
||||
self = klass(_error__please_use_generate=True)
|
||||
self.curve = curve
|
||||
self.default_hashfunc = hashfunc
|
||||
self.baselen = curve.baselen
|
||||
n = curve.order
|
||||
assert 1 <= secexp < n
|
||||
pubkey_point = curve.generator * secexp
|
||||
pubkey = ecdsa.Public_key(curve.generator, pubkey_point)
|
||||
pubkey.order = n
|
||||
self.verifying_key = VerifyingKey.from_public_point(pubkey_point, curve,
|
||||
hashfunc)
|
||||
self.privkey = ecdsa.Private_key(pubkey, secexp)
|
||||
self.privkey.order = n
|
||||
return self
|
||||
|
||||
@classmethod
|
||||
def from_string(klass, string, curve=NIST192p, hashfunc=sha1):
|
||||
assert len(string) == curve.baselen, (len(string), curve.baselen)
|
||||
secexp = string_to_number(string)
|
||||
return klass.from_secret_exponent(secexp, curve, hashfunc)
|
||||
|
||||
@classmethod
|
||||
def from_pem(klass, string, hashfunc=sha1):
|
||||
# the privkey pem file has two sections: "EC PARAMETERS" and "EC
|
||||
# PRIVATE KEY". The first is redundant.
|
||||
if isinstance(string, str):
|
||||
string = string.encode()
|
||||
privkey_pem = string[string.index(b'-----BEGIN EC PRIVATE KEY-----'):]
|
||||
return klass.from_der(der.unpem(privkey_pem), hashfunc)
|
||||
|
||||
@classmethod
|
||||
def from_der(klass, string, hashfunc=sha1):
|
||||
# SEQ([int(1), octetstring(privkey),cont[0], oid(secp224r1),
|
||||
# cont[1],bitstring])
|
||||
s, empty = der.remove_sequence(string)
|
||||
if empty != b'':
|
||||
raise der.UnexpectedDER("trailing junk after DER privkey: %s" %
|
||||
binascii.hexlify(empty))
|
||||
one, s = der.remove_integer(s)
|
||||
if one != 1:
|
||||
raise der.UnexpectedDER("expected '1' at start of DER privkey,"
|
||||
" got %d" % one)
|
||||
privkey_str, s = der.remove_octet_string(s)
|
||||
tag, curve_oid_str, s = der.remove_constructed(s)
|
||||
if tag != 0:
|
||||
raise der.UnexpectedDER("expected tag 0 in DER privkey,"
|
||||
" got %d" % tag)
|
||||
curve_oid, empty = der.remove_object(curve_oid_str)
|
||||
if empty != b'':
|
||||
raise der.UnexpectedDER("trailing junk after DER privkey "
|
||||
"curve_oid: %s" % binascii.hexlify(empty))
|
||||
curve = find_curve(curve_oid)
|
||||
|
||||
# we don't actually care about the following fields
|
||||
#
|
||||
# tag, pubkey_bitstring, s = der.remove_constructed(s)
|
||||
# if tag != 1:
|
||||
# raise der.UnexpectedDER("expected tag 1 in DER privkey, got %d"
|
||||
# % tag)
|
||||
# pubkey_str = der.remove_bitstring(pubkey_bitstring)
|
||||
# if empty != "":
|
||||
# raise der.UnexpectedDER("trailing junk after DER privkey "
|
||||
# "pubkeystr: %s" % binascii.hexlify(empty))
|
||||
|
||||
# our from_string method likes fixed-length privkey strings
|
||||
if len(privkey_str) < curve.baselen:
|
||||
privkey_str = b'\x00' * (curve.baselen - len(privkey_str)) + privkey_str
|
||||
return klass.from_string(privkey_str, curve, hashfunc)
|
||||
|
||||
def to_string(self):
|
||||
secexp = self.privkey.secret_multiplier
|
||||
s = number_to_string(secexp, self.privkey.order)
|
||||
return s
|
||||
|
||||
def to_pem(self):
|
||||
# TODO: "BEGIN ECPARAMETERS"
|
||||
return der.topem(self.to_der(), "EC PRIVATE KEY")
|
||||
|
||||
def to_der(self):
|
||||
# SEQ([int(1), octetstring(privkey),cont[0], oid(secp224r1),
|
||||
# cont[1],bitstring])
|
||||
encoded_vk = b'\x00\x04' + self.get_verifying_key().to_string()
|
||||
return der.encode_sequence(der.encode_integer(1),
|
||||
der.encode_octet_string(self.to_string()),
|
||||
der.encode_constructed(0, self.curve.encoded_oid),
|
||||
der.encode_constructed(1, der.encode_bitstring(encoded_vk)),
|
||||
)
|
||||
|
||||
def get_verifying_key(self):
|
||||
return self.verifying_key
|
||||
|
||||
def sign_deterministic(self, data, hashfunc=None,
|
||||
sigencode=sigencode_string,
|
||||
extra_entropy=b''):
|
||||
hashfunc = hashfunc or self.default_hashfunc
|
||||
digest = hashfunc(data).digest()
|
||||
|
||||
return self.sign_digest_deterministic(
|
||||
digest, hashfunc=hashfunc, sigencode=sigencode,
|
||||
extra_entropy=extra_entropy)
|
||||
|
||||
def sign_digest_deterministic(self, digest, hashfunc=None,
|
||||
sigencode=sigencode_string,
|
||||
extra_entropy=b''):
|
||||
"""
|
||||
Calculates 'k' from data itself, removing the need for strong
|
||||
random generator and producing deterministic (reproducible) signatures.
|
||||
See RFC 6979 for more details.
|
||||
"""
|
||||
secexp = self.privkey.secret_multiplier
|
||||
|
||||
def simple_r_s(r, s, order, v):
|
||||
return r, s, order, v
|
||||
|
||||
retry_gen = 0
|
||||
while True:
|
||||
k = rfc6979.generate_k(
|
||||
self.curve.generator.order(), secexp, hashfunc, digest,
|
||||
retry_gen=retry_gen, extra_entropy=extra_entropy)
|
||||
try:
|
||||
r, s, order, v = self.sign_digest(digest, sigencode=simple_r_s, k=k)
|
||||
break
|
||||
except RSZeroError:
|
||||
retry_gen += 1
|
||||
|
||||
return sigencode(r, s, order, v)
|
||||
|
||||
def sign(self, data, entropy=None, hashfunc=None, sigencode=sigencode_string, k=None):
|
||||
"""
|
||||
hashfunc= should behave like hashlib.sha1 . The output length of the
|
||||
hash (in bytes) must not be longer than the length of the curve order
|
||||
(rounded up to the nearest byte), so using SHA256 with nist256p is
|
||||
ok, but SHA256 with nist192p is not. (In the 2**-96ish unlikely event
|
||||
of a hash output larger than the curve order, the hash will
|
||||
effectively be wrapped mod n).
|
||||
|
||||
Use hashfunc=hashlib.sha1 to match openssl's -ecdsa-with-SHA1 mode,
|
||||
or hashfunc=hashlib.sha256 for openssl-1.0.0's -ecdsa-with-SHA256.
|
||||
"""
|
||||
|
||||
hashfunc = hashfunc or self.default_hashfunc
|
||||
h = hashfunc(data).digest()
|
||||
return self.sign_digest(h, entropy, sigencode, k)
|
||||
|
||||
def sign_digest(self, digest, entropy=None, sigencode=sigencode_string, k=None):
|
||||
if len(digest) > self.curve.baselen:
|
||||
raise BadDigestError("this curve (%s) is too short "
|
||||
"for your digest (%d)" % (self.curve.name,
|
||||
8 * len(digest)))
|
||||
number = string_to_number(digest)
|
||||
r, s, v = self.sign_number(number, entropy, k)
|
||||
return sigencode(r, s, self.privkey.order, v)
|
||||
|
||||
def sign_number(self, number, entropy=None, k=None):
|
||||
# returns a pair of numbers
|
||||
order = self.privkey.order
|
||||
# privkey.sign() may raise RuntimeError in the amazingly unlikely
|
||||
# (2**-192) event that r=0 or s=0, because that would leak the key.
|
||||
# We could re-try with a different 'k', but we couldn't test that
|
||||
# code, so I choose to allow the signature to fail instead.
|
||||
|
||||
# If k is set, it is used directly. In other cases
|
||||
# it is generated using entropy function
|
||||
if k is not None:
|
||||
_k = k
|
||||
else:
|
||||
_k = randrange(order, entropy)
|
||||
|
||||
assert 1 <= _k < order
|
||||
sig = self.privkey.sign(number, _k)
|
||||
return sig.r, sig.s, sig.recovery_param
|
||||
531
ccxt/static_dependencies/ecdsa/numbertheory.py
Normal file
531
ccxt/static_dependencies/ecdsa/numbertheory.py
Normal file
@@ -0,0 +1,531 @@
|
||||
#! /usr/bin/env python
|
||||
#
|
||||
# Provide some simple capabilities from number theory.
|
||||
#
|
||||
# Version of 2008.11.14.
|
||||
#
|
||||
# Written in 2005 and 2006 by Peter Pearson and placed in the public domain.
|
||||
# Revision history:
|
||||
# 2008.11.14: Use pow(base, exponent, modulus) for modular_exp.
|
||||
# Make gcd and lcm accept arbitrarly many arguments.
|
||||
|
||||
from __future__ import division
|
||||
|
||||
from functools import reduce
|
||||
|
||||
import math
|
||||
|
||||
|
||||
class Error(Exception):
|
||||
"""Base class for exceptions in this module."""
|
||||
pass
|
||||
|
||||
|
||||
class SquareRootError(Error):
|
||||
pass
|
||||
|
||||
|
||||
class NegativeExponentError(Error):
|
||||
pass
|
||||
|
||||
|
||||
def modular_exp(base, exponent, modulus):
|
||||
"Raise base to exponent, reducing by modulus"
|
||||
if exponent < 0:
|
||||
raise NegativeExponentError("Negative exponents (%d) not allowed" \
|
||||
% exponent)
|
||||
return pow(base, exponent, modulus)
|
||||
|
||||
|
||||
# result = 1L
|
||||
# x = exponent
|
||||
# b = base + 0L
|
||||
# while x > 0:
|
||||
# if x % 2 > 0: result = (result * b) % modulus
|
||||
# x = x // 2
|
||||
# b = (b * b) % modulus
|
||||
# return result
|
||||
|
||||
|
||||
def polynomial_reduce_mod(poly, polymod, p):
|
||||
"""Reduce poly by polymod, integer arithmetic modulo p.
|
||||
|
||||
Polynomials are represented as lists of coefficients
|
||||
of increasing powers of x."""
|
||||
|
||||
# This module has been tested only by extensive use
|
||||
# in calculating modular square roots.
|
||||
|
||||
# Just to make this easy, require a monic polynomial:
|
||||
assert polymod[-1] == 1
|
||||
|
||||
assert len(polymod) > 1
|
||||
|
||||
while len(poly) >= len(polymod):
|
||||
if poly[-1] != 0:
|
||||
for i in range(2, len(polymod) + 1):
|
||||
poly[-i] = (poly[-i] - poly[-1] * polymod[-i]) % p
|
||||
poly = poly[0:-1]
|
||||
|
||||
return poly
|
||||
|
||||
|
||||
def polynomial_multiply_mod(m1, m2, polymod, p):
|
||||
"""Polynomial multiplication modulo a polynomial over ints mod p.
|
||||
|
||||
Polynomials are represented as lists of coefficients
|
||||
of increasing powers of x."""
|
||||
|
||||
# This is just a seat-of-the-pants implementation.
|
||||
|
||||
# This module has been tested only by extensive use
|
||||
# in calculating modular square roots.
|
||||
|
||||
# Initialize the product to zero:
|
||||
|
||||
prod = (len(m1) + len(m2) - 1) * [0]
|
||||
|
||||
# Add together all the cross-terms:
|
||||
|
||||
for i in range(len(m1)):
|
||||
for j in range(len(m2)):
|
||||
prod[i + j] = (prod[i + j] + m1[i] * m2[j]) % p
|
||||
|
||||
return polynomial_reduce_mod(prod, polymod, p)
|
||||
|
||||
|
||||
def polynomial_exp_mod(base, exponent, polymod, p):
|
||||
"""Polynomial exponentiation modulo a polynomial over ints mod p.
|
||||
|
||||
Polynomials are represented as lists of coefficients
|
||||
of increasing powers of x."""
|
||||
|
||||
# Based on the Handbook of Applied Cryptography, algorithm 2.227.
|
||||
|
||||
# This module has been tested only by extensive use
|
||||
# in calculating modular square roots.
|
||||
|
||||
assert exponent < p
|
||||
|
||||
if exponent == 0:
|
||||
return [1]
|
||||
|
||||
G = base
|
||||
k = exponent
|
||||
if k % 2 == 1:
|
||||
s = G
|
||||
else:
|
||||
s = [1]
|
||||
|
||||
while k > 1:
|
||||
k = k // 2
|
||||
G = polynomial_multiply_mod(G, G, polymod, p)
|
||||
if k % 2 == 1:
|
||||
s = polynomial_multiply_mod(G, s, polymod, p)
|
||||
|
||||
return s
|
||||
|
||||
|
||||
def jacobi(a, n):
|
||||
"""Jacobi symbol"""
|
||||
|
||||
# Based on the Handbook of Applied Cryptography (HAC), algorithm 2.149.
|
||||
|
||||
# This function has been tested by comparison with a small
|
||||
# table printed in HAC, and by extensive use in calculating
|
||||
# modular square roots.
|
||||
|
||||
assert n >= 3
|
||||
assert n % 2 == 1
|
||||
a = a % n
|
||||
if a == 0:
|
||||
return 0
|
||||
if a == 1:
|
||||
return 1
|
||||
a1, e = a, 0
|
||||
while a1 % 2 == 0:
|
||||
a1, e = a1 // 2, e + 1
|
||||
if e % 2 == 0 or n % 8 == 1 or n % 8 == 7:
|
||||
s = 1
|
||||
else:
|
||||
s = -1
|
||||
if a1 == 1:
|
||||
return s
|
||||
if n % 4 == 3 and a1 % 4 == 3:
|
||||
s = -s
|
||||
return s * jacobi(n % a1, a1)
|
||||
|
||||
|
||||
def square_root_mod_prime(a, p):
|
||||
"""Modular square root of a, mod p, p prime."""
|
||||
|
||||
# Based on the Handbook of Applied Cryptography, algorithms 3.34 to 3.39.
|
||||
|
||||
# This module has been tested for all values in [0,p-1] for
|
||||
# every prime p from 3 to 1229.
|
||||
|
||||
assert 0 <= a < p
|
||||
assert 1 < p
|
||||
|
||||
if a == 0:
|
||||
return 0
|
||||
if p == 2:
|
||||
return a
|
||||
|
||||
jac = jacobi(a, p)
|
||||
if jac == -1:
|
||||
raise SquareRootError("%d has no square root modulo %d" \
|
||||
% (a, p))
|
||||
|
||||
if p % 4 == 3:
|
||||
return modular_exp(a, (p + 1) // 4, p)
|
||||
|
||||
if p % 8 == 5:
|
||||
d = modular_exp(a, (p - 1) // 4, p)
|
||||
if d == 1:
|
||||
return modular_exp(a, (p + 3) // 8, p)
|
||||
if d == p - 1:
|
||||
return (2 * a * modular_exp(4 * a, (p - 5) // 8, p)) % p
|
||||
raise RuntimeError("Shouldn't get here.")
|
||||
|
||||
for b in range(2, p):
|
||||
if jacobi(b * b - 4 * a, p) == -1:
|
||||
f = (a, -b, 1)
|
||||
ff = polynomial_exp_mod((0, 1), (p + 1) // 2, f, p)
|
||||
assert ff[1] == 0
|
||||
return ff[0]
|
||||
raise RuntimeError("No b found.")
|
||||
|
||||
|
||||
def inverse_mod(a, m):
|
||||
"""Inverse of a mod m."""
|
||||
|
||||
if a < 0 or m <= a:
|
||||
a = a % m
|
||||
|
||||
# From Ferguson and Schneier, roughly:
|
||||
|
||||
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
|
||||
|
||||
# At this point, d is the GCD, and ud*a+vd*m = d.
|
||||
# If d == 1, this means that ud is a inverse.
|
||||
|
||||
assert d == 1
|
||||
if ud > 0:
|
||||
return ud
|
||||
else:
|
||||
return ud + m
|
||||
|
||||
|
||||
def gcd2(a, b):
|
||||
"""Greatest common divisor using Euclid's algorithm."""
|
||||
while a:
|
||||
a, b = b % a, a
|
||||
return b
|
||||
|
||||
|
||||
def gcd(*a):
|
||||
"""Greatest common divisor.
|
||||
|
||||
Usage: gcd([ 2, 4, 6 ])
|
||||
or: gcd(2, 4, 6)
|
||||
"""
|
||||
|
||||
if len(a) > 1:
|
||||
return reduce(gcd2, a)
|
||||
if hasattr(a[0], "__iter__"):
|
||||
return reduce(gcd2, a[0])
|
||||
return a[0]
|
||||
|
||||
|
||||
def lcm2(a, b):
|
||||
"""Least common multiple of two integers."""
|
||||
|
||||
return (a * b) // gcd(a, b)
|
||||
|
||||
|
||||
def lcm(*a):
|
||||
"""Least common multiple.
|
||||
|
||||
Usage: lcm([ 3, 4, 5 ])
|
||||
or: lcm(3, 4, 5)
|
||||
"""
|
||||
|
||||
if len(a) > 1:
|
||||
return reduce(lcm2, a)
|
||||
if hasattr(a[0], "__iter__"):
|
||||
return reduce(lcm2, a[0])
|
||||
return a[0]
|
||||
|
||||
|
||||
def factorization(n):
|
||||
"""Decompose n into a list of (prime,exponent) pairs."""
|
||||
|
||||
assert isinstance(n, int)
|
||||
|
||||
if n < 2:
|
||||
return []
|
||||
|
||||
result = []
|
||||
d = 2
|
||||
|
||||
# Test the small primes:
|
||||
|
||||
for d in smallprimes:
|
||||
if d > n:
|
||||
break
|
||||
q, r = divmod(n, d)
|
||||
if r == 0:
|
||||
count = 1
|
||||
while d <= n:
|
||||
n = q
|
||||
q, r = divmod(n, d)
|
||||
if r != 0:
|
||||
break
|
||||
count = count + 1
|
||||
result.append((d, count))
|
||||
|
||||
# If n is still greater than the last of our small primes,
|
||||
# it may require further work:
|
||||
|
||||
if n > smallprimes[-1]:
|
||||
if is_prime(n): # If what's left is prime, it's easy:
|
||||
result.append((n, 1))
|
||||
else: # Ugh. Search stupidly for a divisor:
|
||||
d = smallprimes[-1]
|
||||
while 1:
|
||||
d = d + 2 # Try the next divisor.
|
||||
q, r = divmod(n, d)
|
||||
if q < d: # n < d*d means we're done, n = 1 or prime.
|
||||
break
|
||||
if r == 0: # d divides n. How many times?
|
||||
count = 1
|
||||
n = q
|
||||
while d <= n: # As long as d might still divide n,
|
||||
q, r = divmod(n, d) # see if it does.
|
||||
if r != 0:
|
||||
break
|
||||
n = q # It does. Reduce n, increase count.
|
||||
count = count + 1
|
||||
result.append((d, count))
|
||||
if n > 1:
|
||||
result.append((n, 1))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def phi(n):
|
||||
"""Return the Euler totient function of n."""
|
||||
|
||||
assert isinstance(n, int)
|
||||
|
||||
if n < 3:
|
||||
return 1
|
||||
|
||||
result = 1
|
||||
ff = factorization(n)
|
||||
for f in ff:
|
||||
e = f[1]
|
||||
if e > 1:
|
||||
result = result * f[0] ** (e - 1) * (f[0] - 1)
|
||||
else:
|
||||
result = result * (f[0] - 1)
|
||||
return result
|
||||
|
||||
|
||||
def carmichael(n):
|
||||
"""Return Carmichael function of n.
|
||||
|
||||
Carmichael(n) is the smallest integer x such that
|
||||
m**x = 1 mod n for all m relatively prime to n.
|
||||
"""
|
||||
|
||||
return carmichael_of_factorized(factorization(n))
|
||||
|
||||
|
||||
def carmichael_of_factorized(f_list):
|
||||
"""Return the Carmichael function of a number that is
|
||||
represented as a list of (prime,exponent) pairs.
|
||||
"""
|
||||
|
||||
if len(f_list) < 1:
|
||||
return 1
|
||||
|
||||
result = carmichael_of_ppower(f_list[0])
|
||||
for i in range(1, len(f_list)):
|
||||
result = lcm(result, carmichael_of_ppower(f_list[i]))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def carmichael_of_ppower(pp):
|
||||
"""Carmichael function of the given power of the given prime.
|
||||
"""
|
||||
|
||||
p, a = pp
|
||||
if p == 2 and a > 2:
|
||||
return 2 ** (a - 2)
|
||||
else:
|
||||
return (p - 1) * p ** (a - 1)
|
||||
|
||||
|
||||
def order_mod(x, m):
|
||||
"""Return the order of x in the multiplicative group mod m.
|
||||
"""
|
||||
|
||||
# Warning: this implementation is not very clever, and will
|
||||
# take a long time if m is very large.
|
||||
|
||||
if m <= 1:
|
||||
return 0
|
||||
|
||||
assert gcd(x, m) == 1
|
||||
|
||||
z = x
|
||||
result = 1
|
||||
while z != 1:
|
||||
z = (z * x) % m
|
||||
result = result + 1
|
||||
return result
|
||||
|
||||
|
||||
def largest_factor_relatively_prime(a, b):
|
||||
"""Return the largest factor of a relatively prime to b.
|
||||
"""
|
||||
|
||||
while 1:
|
||||
d = gcd(a, b)
|
||||
if d <= 1:
|
||||
break
|
||||
b = d
|
||||
while 1:
|
||||
q, r = divmod(a, d)
|
||||
if r > 0:
|
||||
break
|
||||
a = q
|
||||
return a
|
||||
|
||||
|
||||
def kinda_order_mod(x, m):
|
||||
"""Return the order of x in the multiplicative group mod m',
|
||||
where m' is the largest factor of m relatively prime to x.
|
||||
"""
|
||||
|
||||
return order_mod(x, largest_factor_relatively_prime(m, x))
|
||||
|
||||
|
||||
def is_prime(n):
|
||||
"""Return True if x is prime, False otherwise.
|
||||
|
||||
We use the Miller-Rabin test, as given in Menezes et al. p. 138.
|
||||
This test is not exact: there are composite values n for which
|
||||
it returns True.
|
||||
|
||||
In testing the odd numbers from 10000001 to 19999999,
|
||||
about 66 composites got past the first test,
|
||||
5 got past the second test, and none got past the third.
|
||||
Since factors of 2, 3, 5, 7, and 11 were detected during
|
||||
preliminary screening, the number of numbers tested by
|
||||
Miller-Rabin was (19999999 - 10000001)*(2/3)*(4/5)*(6/7)
|
||||
= 4.57 million.
|
||||
"""
|
||||
|
||||
# (This is used to study the risk of false positives:)
|
||||
global miller_rabin_test_count
|
||||
|
||||
miller_rabin_test_count = 0
|
||||
|
||||
if n <= smallprimes[-1]:
|
||||
if n in smallprimes:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
if gcd(n, 2 * 3 * 5 * 7 * 11) != 1:
|
||||
return False
|
||||
|
||||
# Choose a number of iterations sufficient to reduce the
|
||||
# probability of accepting a composite below 2**-80
|
||||
# (from Menezes et al. Table 4.4):
|
||||
|
||||
t = 40
|
||||
n_bits = 1 + int(math.log(n, 2))
|
||||
for k, tt in ((100, 27),
|
||||
(150, 18),
|
||||
(200, 15),
|
||||
(250, 12),
|
||||
(300, 9),
|
||||
(350, 8),
|
||||
(400, 7),
|
||||
(450, 6),
|
||||
(550, 5),
|
||||
(650, 4),
|
||||
(850, 3),
|
||||
(1300, 2),
|
||||
):
|
||||
if n_bits < k:
|
||||
break
|
||||
t = tt
|
||||
|
||||
# Run the test t times:
|
||||
|
||||
s = 0
|
||||
r = n - 1
|
||||
while (r % 2) == 0:
|
||||
s = s + 1
|
||||
r = r // 2
|
||||
for i in range(t):
|
||||
a = smallprimes[i]
|
||||
y = modular_exp(a, r, n)
|
||||
if y != 1 and y != n - 1:
|
||||
j = 1
|
||||
while j <= s - 1 and y != n - 1:
|
||||
y = modular_exp(y, 2, n)
|
||||
if y == 1:
|
||||
miller_rabin_test_count = i + 1
|
||||
return False
|
||||
j = j + 1
|
||||
if y != n - 1:
|
||||
miller_rabin_test_count = i + 1
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def next_prime(starting_value):
|
||||
"Return the smallest prime larger than the starting value."
|
||||
|
||||
if starting_value < 2:
|
||||
return 2
|
||||
result = (starting_value + 1) | 1
|
||||
while not is_prime(result):
|
||||
result = result + 2
|
||||
return result
|
||||
|
||||
|
||||
smallprimes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41,
|
||||
43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
|
||||
101, 103, 107, 109, 113, 127, 131, 137, 139, 149,
|
||||
151, 157, 163, 167, 173, 179, 181, 191, 193, 197,
|
||||
199, 211, 223, 227, 229, 233, 239, 241, 251, 257,
|
||||
263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
|
||||
317, 331, 337, 347, 349, 353, 359, 367, 373, 379,
|
||||
383, 389, 397, 401, 409, 419, 421, 431, 433, 439,
|
||||
443, 449, 457, 461, 463, 467, 479, 487, 491, 499,
|
||||
503, 509, 521, 523, 541, 547, 557, 563, 569, 571,
|
||||
577, 587, 593, 599, 601, 607, 613, 617, 619, 631,
|
||||
641, 643, 647, 653, 659, 661, 673, 677, 683, 691,
|
||||
701, 709, 719, 727, 733, 739, 743, 751, 757, 761,
|
||||
769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
|
||||
839, 853, 857, 859, 863, 877, 881, 883, 887, 907,
|
||||
911, 919, 929, 937, 941, 947, 953, 967, 971, 977,
|
||||
983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033,
|
||||
1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093,
|
||||
1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163,
|
||||
1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229]
|
||||
|
||||
miller_rabin_test_count = 0
|
||||
|
||||
100
ccxt/static_dependencies/ecdsa/rfc6979.py
Normal file
100
ccxt/static_dependencies/ecdsa/rfc6979.py
Normal file
@@ -0,0 +1,100 @@
|
||||
'''
|
||||
RFC 6979:
|
||||
Deterministic Usage of the Digital Signature Algorithm (DSA) and
|
||||
Elliptic Curve Digital Signature Algorithm (ECDSA)
|
||||
|
||||
http://tools.ietf.org/html/rfc6979
|
||||
|
||||
Many thanks to Coda Hale for his implementation in Go language:
|
||||
https://github.com/codahale/rfc6979
|
||||
'''
|
||||
|
||||
import hmac
|
||||
from binascii import hexlify
|
||||
from .util import number_to_string, number_to_string_crop
|
||||
|
||||
|
||||
def bit_length(num):
|
||||
# http://docs.python.org/dev/library/stdtypes.html#int.bit_length
|
||||
s = bin(num) # binary representation: bin(-37) --> '-0b100101'
|
||||
s = s.lstrip('-0b') # remove leading zeros and minus sign
|
||||
return len(s) # len('100101') --> 6
|
||||
|
||||
|
||||
def bits2int(data, qlen):
|
||||
x = int(hexlify(data), 16)
|
||||
l = len(data) * 8
|
||||
|
||||
if l > qlen:
|
||||
return x >> (l - qlen)
|
||||
return x
|
||||
|
||||
|
||||
def bits2octets(data, order):
|
||||
z1 = bits2int(data, bit_length(order))
|
||||
z2 = z1 - order
|
||||
|
||||
if z2 < 0:
|
||||
z2 = z1
|
||||
|
||||
return number_to_string_crop(z2, order)
|
||||
|
||||
|
||||
# https://tools.ietf.org/html/rfc6979#section-3.2
|
||||
def generate_k(order, secexp, hash_func, data, retry_gen=0, extra_entropy=b''):
|
||||
'''
|
||||
order - order of the DSA generator used in the signature
|
||||
secexp - secure exponent (private key) in numeric form
|
||||
hash_func - reference to the same hash function used for generating hash
|
||||
data - hash in binary form of the signing data
|
||||
retry_gen - int - how many good 'k' values to skip before returning
|
||||
extra_entropy - extra added data in binary form as per section-3.6 of
|
||||
rfc6979
|
||||
'''
|
||||
|
||||
qlen = bit_length(order)
|
||||
holen = hash_func().digest_size
|
||||
rolen = (qlen + 7) / 8
|
||||
bx = number_to_string(secexp, order) + bits2octets(data, order) + \
|
||||
extra_entropy
|
||||
|
||||
# Step B
|
||||
v = b'\x01' * holen
|
||||
|
||||
# Step C
|
||||
k = b'\x00' * holen
|
||||
|
||||
# Step D
|
||||
|
||||
k = hmac.new(k, v + b'\x00' + bx, hash_func).digest()
|
||||
|
||||
# Step E
|
||||
v = hmac.new(k, v, hash_func).digest()
|
||||
|
||||
# Step F
|
||||
k = hmac.new(k, v + b'\x01' + bx, hash_func).digest()
|
||||
|
||||
# Step G
|
||||
v = hmac.new(k, v, hash_func).digest()
|
||||
|
||||
# Step H
|
||||
while True:
|
||||
# Step H1
|
||||
t = b''
|
||||
|
||||
# Step H2
|
||||
while len(t) < rolen:
|
||||
v = hmac.new(k, v, hash_func).digest()
|
||||
t += v
|
||||
|
||||
# Step H3
|
||||
secret = bits2int(t, qlen)
|
||||
|
||||
if secret >= 1 and secret < order:
|
||||
if retry_gen <= 0:
|
||||
return secret
|
||||
else:
|
||||
retry_gen -= 1
|
||||
|
||||
k = hmac.new(k, v + b'\x00', hash_func).digest()
|
||||
v = hmac.new(k, v, hash_func).digest()
|
||||
266
ccxt/static_dependencies/ecdsa/util.py
Normal file
266
ccxt/static_dependencies/ecdsa/util.py
Normal file
@@ -0,0 +1,266 @@
|
||||
from __future__ import division
|
||||
|
||||
import os
|
||||
import math
|
||||
import binascii
|
||||
from hashlib import sha256
|
||||
from . import der
|
||||
from .curves import orderlen
|
||||
|
||||
# RFC5480:
|
||||
# The "unrestricted" algorithm identifier is:
|
||||
# id-ecPublicKey OBJECT IDENTIFIER ::= {
|
||||
# iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 }
|
||||
|
||||
oid_ecPublicKey = (1, 2, 840, 10045, 2, 1)
|
||||
encoded_oid_ecPublicKey = der.encode_oid(*oid_ecPublicKey)
|
||||
|
||||
|
||||
def randrange(order, entropy=None):
|
||||
"""Return a random integer k such that 1 <= k < order, uniformly
|
||||
distributed across that range. For simplicity, this only behaves well if
|
||||
'order' is fairly close (but below) a power of 256. The try-try-again
|
||||
algorithm we use takes longer and longer time (on average) to complete as
|
||||
'order' falls, rising to a maximum of avg=512 loops for the worst-case
|
||||
(256**k)+1 . All of the standard curves behave well. There is a cutoff at
|
||||
10k loops (which raises RuntimeError) to prevent an infinite loop when
|
||||
something is really broken like the entropy function not working.
|
||||
|
||||
Note that this function is not declared to be forwards-compatible: we may
|
||||
change the behavior in future releases. The entropy= argument (which
|
||||
should get a callable that behaves like os.urandom) can be used to
|
||||
achieve stability within a given release (for repeatable unit tests), but
|
||||
should not be used as a long-term-compatible key generation algorithm.
|
||||
"""
|
||||
# we could handle arbitrary orders (even 256**k+1) better if we created
|
||||
# candidates bit-wise instead of byte-wise, which would reduce the
|
||||
# worst-case behavior to avg=2 loops, but that would be more complex. The
|
||||
# change would be to round the order up to a power of 256, subtract one
|
||||
# (to get 0xffff..), use that to get a byte-long mask for the top byte,
|
||||
# generate the len-1 entropy bytes, generate one extra byte and mask off
|
||||
# the top bits, then combine it with the rest. Requires jumping back and
|
||||
# forth between strings and integers a lot.
|
||||
|
||||
if entropy is None:
|
||||
entropy = os.urandom
|
||||
assert order > 1
|
||||
bytes = orderlen(order)
|
||||
dont_try_forever = 10000 # gives about 2**-60 failures for worst case
|
||||
while dont_try_forever > 0:
|
||||
dont_try_forever -= 1
|
||||
candidate = string_to_number(entropy(bytes)) + 1
|
||||
if 1 <= candidate < order:
|
||||
return candidate
|
||||
continue
|
||||
raise RuntimeError("randrange() tried hard but gave up, either something"
|
||||
" is very wrong or you got realllly unlucky. Order was"
|
||||
" %x" % order)
|
||||
|
||||
|
||||
class PRNG:
|
||||
# this returns a callable which, when invoked with an integer N, will
|
||||
# return N pseudorandom bytes. Note: this is a short-term PRNG, meant
|
||||
# primarily for the needs of randrange_from_seed__trytryagain(), which
|
||||
# only needs to run it a few times per seed. It does not provide
|
||||
# protection against state compromise (forward security).
|
||||
def __init__(self, seed):
|
||||
self.generator = self.block_generator(seed)
|
||||
|
||||
def __call__(self, numbytes):
|
||||
a = [next(self.generator) for i in range(numbytes)]
|
||||
return bytes(a)
|
||||
|
||||
def block_generator(self, seed):
|
||||
counter = 0
|
||||
while True:
|
||||
for byte in sha256(("prng-%d-%s" % (counter, seed)).encode()).digest():
|
||||
yield byte
|
||||
counter += 1
|
||||
|
||||
|
||||
def randrange_from_seed__overshoot_modulo(seed, order):
|
||||
# hash the data, then turn the digest into a number in [1,order).
|
||||
#
|
||||
# We use David-Sarah Hopwood's suggestion: turn it into a number that's
|
||||
# sufficiently larger than the group order, then modulo it down to fit.
|
||||
# This should give adequate (but not perfect) uniformity, and simple
|
||||
# code. There are other choices: try-try-again is the main one.
|
||||
base = PRNG(seed)(2 * orderlen(order))
|
||||
number = (int(binascii.hexlify(base), 16) % (order - 1)) + 1
|
||||
assert 1 <= number < order, (1, number, order)
|
||||
return number
|
||||
|
||||
|
||||
def lsb_of_ones(numbits):
|
||||
return (1 << numbits) - 1
|
||||
|
||||
|
||||
def bits_and_bytes(order):
|
||||
bits = int(math.log(order - 1, 2) + 1)
|
||||
bytes = bits // 8
|
||||
extrabits = bits % 8
|
||||
return bits, bytes, extrabits
|
||||
|
||||
|
||||
# the following randrange_from_seed__METHOD() functions take an
|
||||
# arbitrarily-sized secret seed and turn it into a number that obeys the same
|
||||
# range limits as randrange() above. They are meant for deriving consistent
|
||||
# signing keys from a secret rather than generating them randomly, for
|
||||
# example a protocol in which three signing keys are derived from a master
|
||||
# secret. You should use a uniformly-distributed unguessable seed with about
|
||||
# curve.baselen bytes of entropy. To use one, do this:
|
||||
# seed = os.urandom(curve.baselen) # or other starting point
|
||||
# secexp = ecdsa.util.randrange_from_seed__trytryagain(sed, curve.order)
|
||||
# sk = SigningKey.from_secret_exponent(secexp, curve)
|
||||
|
||||
def randrange_from_seed__truncate_bytes(seed, order, hashmod=sha256):
|
||||
# hash the seed, then turn the digest into a number in [1,order), but
|
||||
# don't worry about trying to uniformly fill the range. This will lose,
|
||||
# on average, four bits of entropy.
|
||||
bits, _bytes, extrabits = bits_and_bytes(order)
|
||||
if extrabits:
|
||||
_bytes += 1
|
||||
base = hashmod(seed).digest()[:_bytes]
|
||||
base = "\x00" * (_bytes - len(base)) + base
|
||||
number = 1 + int(binascii.hexlify(base), 16)
|
||||
assert 1 <= number < order
|
||||
return number
|
||||
|
||||
|
||||
def randrange_from_seed__truncate_bits(seed, order, hashmod=sha256):
|
||||
# like string_to_randrange_truncate_bytes, but only lose an average of
|
||||
# half a bit
|
||||
bits = int(math.log(order - 1, 2) + 1)
|
||||
maxbytes = (bits + 7) // 8
|
||||
base = hashmod(seed).digest()[:maxbytes]
|
||||
base = "\x00" * (maxbytes - len(base)) + base
|
||||
topbits = 8 * maxbytes - bits
|
||||
if topbits:
|
||||
base = int.to_bytes(ord(base[0]) & lsb_of_ones(topbits), 1, 'big') + base[1:]
|
||||
number = 1 + int(binascii.hexlify(base), 16)
|
||||
assert 1 <= number < order
|
||||
return number
|
||||
|
||||
|
||||
def randrange_from_seed__trytryagain(seed, order):
|
||||
# figure out exactly how many bits we need (rounded up to the nearest
|
||||
# bit), so we can reduce the chance of looping to less than 0.5 . This is
|
||||
# specified to feed from a byte-oriented PRNG, and discards the
|
||||
# high-order bits of the first byte as necessary to get the right number
|
||||
# of bits. The average number of loops will range from 1.0 (when
|
||||
# order=2**k-1) to 2.0 (when order=2**k+1).
|
||||
assert order > 1
|
||||
bits, bytes, extrabits = bits_and_bytes(order)
|
||||
generate = PRNG(seed)
|
||||
while True:
|
||||
extrabyte = b''
|
||||
if extrabits:
|
||||
extrabyte = int.to_bytes(ord(generate(1)) & lsb_of_ones(extrabits), 1, 'big')
|
||||
guess = string_to_number(extrabyte + generate(bytes)) + 1
|
||||
if 1 <= guess < order:
|
||||
return guess
|
||||
|
||||
|
||||
def number_to_string(num, order):
|
||||
l = orderlen(order)
|
||||
fmt_str = "%0" + str(2 * l) + "x"
|
||||
string = binascii.unhexlify((fmt_str % num).encode())
|
||||
assert len(string) == l, (len(string), l)
|
||||
return string
|
||||
|
||||
|
||||
def number_to_string_crop(num, order):
|
||||
l = orderlen(order)
|
||||
fmt_str = "%0" + str(2 * l) + "x"
|
||||
string = binascii.unhexlify((fmt_str % num).encode())
|
||||
return string[:l]
|
||||
|
||||
|
||||
def string_to_number(string):
|
||||
return int(binascii.hexlify(string), 16)
|
||||
|
||||
|
||||
def string_to_number_fixedlen(string, order):
|
||||
l = orderlen(order)
|
||||
assert len(string) == l, (len(string), l)
|
||||
return int(binascii.hexlify(string), 16)
|
||||
|
||||
|
||||
# these methods are useful for the sigencode= argument to SK.sign() and the
|
||||
# sigdecode= argument to VK.verify(), and control how the signature is packed
|
||||
# or unpacked.
|
||||
|
||||
def sigencode_strings(r, s, order, v=None):
|
||||
r_str = number_to_string(r, order)
|
||||
s_str = number_to_string(s, order)
|
||||
return r_str, s_str, v
|
||||
|
||||
|
||||
def sigencode_string(r, s, order, v=None):
|
||||
# for any given curve, the size of the signature numbers is
|
||||
# fixed, so just use simple concatenation
|
||||
r_str, s_str, v = sigencode_strings(r, s, order)
|
||||
return r_str + s_str
|
||||
|
||||
|
||||
def sigencode_der(r, s, order, v=None):
|
||||
return der.encode_sequence(der.encode_integer(r), der.encode_integer(s))
|
||||
|
||||
|
||||
# canonical versions of sigencode methods
|
||||
# these enforce low S values, by negating the value (modulo the order) if above order/2
|
||||
# see CECKey::Sign() https://github.com/bitcoin/bitcoin/blob/master/src/key.cpp#L214
|
||||
def sigencode_strings_canonize(r, s, order, v=None):
|
||||
if s > order / 2:
|
||||
s = order - s
|
||||
if v is not None:
|
||||
v ^= 1
|
||||
return sigencode_strings(r, s, order, v)
|
||||
|
||||
|
||||
def sigencode_string_canonize(r, s, order, v=None):
|
||||
if s > order / 2:
|
||||
s = order - s
|
||||
if v is not None:
|
||||
v ^= 1
|
||||
return sigencode_string(r, s, order, v)
|
||||
|
||||
|
||||
def sigencode_der_canonize(r, s, order, v=None):
|
||||
if s > order / 2:
|
||||
s = order - s
|
||||
if v is not None:
|
||||
v ^= 1
|
||||
return sigencode_der(r, s, order, v)
|
||||
|
||||
|
||||
def sigdecode_string(signature, order):
|
||||
l = orderlen(order)
|
||||
assert len(signature) == 2 * l, (len(signature), 2 * l)
|
||||
r = string_to_number_fixedlen(signature[:l], order)
|
||||
s = string_to_number_fixedlen(signature[l:], order)
|
||||
return r, s
|
||||
|
||||
|
||||
def sigdecode_strings(rs_strings, order):
|
||||
(r_str, s_str) = rs_strings
|
||||
l = orderlen(order)
|
||||
assert len(r_str) == l, (len(r_str), l)
|
||||
assert len(s_str) == l, (len(s_str), l)
|
||||
r = string_to_number_fixedlen(r_str, order)
|
||||
s = string_to_number_fixedlen(s_str, order)
|
||||
return r, s
|
||||
|
||||
|
||||
def sigdecode_der(sig_der, order):
|
||||
# return der.encode_sequence(der.encode_integer(r), der.encode_integer(s))
|
||||
rs_strings, empty = der.remove_sequence(sig_der)
|
||||
if empty != b'':
|
||||
raise der.UnexpectedDER("trailing junk after DER sig: %s" %
|
||||
binascii.hexlify(empty))
|
||||
r, rest = der.remove_integer(rs_strings)
|
||||
s, empty = der.remove_integer(rest)
|
||||
if empty != b'':
|
||||
raise der.UnexpectedDER("trailing junk after DER numbers: %s" %
|
||||
binascii.hexlify(empty))
|
||||
return r, s
|
||||
Reference in New Issue
Block a user