Files
palemoon27/python/PyECC/ecc/elliptic.py
roytam1 688c3af674 import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1235021 - Re-emit ChromeManifestEntries from the jar manifest handler code in the FasterMake backend. r=gps (a8d899a6da)
- Bug 1233282 - Make CONFIGURE_DEFINE_FILES considered more as GENERATED_FILES in the emitter. r=gps (d29506fb55)
- Bug 1235021 - Add a RenamedSourcePath helper class. r=gps (62e78b867b)
- Bug 1235021 - Re-emit FinalTarget{,Preprocessed}Files from the jar manifest handler code in the FasterMake backend. r=gps (c37287a5d7)
- Bug 1235021 - Avoid passing defines to FasterMakeBackend._consume_jar_manifest. r=gps (dc0d17c3a6)
- Bug 1235021 - Move FasterMakeBackend._consume_jar_manifest to CommonBackend. r=gps (b9bb6b7d1e)
- Bug 1239217 - Add the notion of Partial and Hybrid build backends. r=gps Make the FasterMake backend a partial build backend. (219c0811e6)
- Bug 1239217 - Stop making the FasterMake build system refresh the backend on its own. r=gps (4f79f966ce)
- Bug 1241398 - Show the diff for created and deleted files in `mach build-backend --diff`. r=gps (d497d3aef8)
- Bug 1214885 - Add a "ChromeUrl" build backend to write out information useful for resolving chrome urls. r=glandium (83ad13d109)
- Bug 1216817 - Part 1: Add install_callback to artifacts. r=gps (95b4860d09)
- Bug 1216817 - Part 2: Narrow distdir to bindir in artifacts. r=gps (e48b531455)
- Bug 1216817 - Part 4: Add --enable-artifact-builds and MOZ_ARTIFACT_BUILDS. r=glandium (8d7ed76621)
- bug 1164816 - Import concurrent.futures into the tree. r=gps (bc83211833)
- bug 1190603 - import PyECC library r=gps,gerv (e0c5afeee0)
- Bug 1216817 - Part 5: Run |mach artifact install| automatically when asked. r=glandium (835c27d9c2)
- Bug 1216817 - Follow-up: Fix "KeyError: uMOZ_ARTIFACT_BUILDS" in config.status. r=bustage (e87e04e23b)
- Bug 1216817 - Follow-up: Fix "KeyError: u'MOZ_ARTIFACT_BUILDS'". r=bustage (797331293b)
- Bug 1207897 - Add a configure option to build multiple build backends. r=gps (35f62c27ca)
- Bug 1241398 - Allow to pass the --verbose flag down to config.status from `mach build-backend`. r=gps (78610c40d0)
- Bug 1236111 - part 1: avoid configure.in Windows-only goop when running with disable-compile-environment, r=gps (d27a7e522a)
- Bug 1236111 - part 2: fix mozbuild to use the file mode modifiers specified for opening when writing a FileAvoidWrite, r=gps,nalexander (e240c613b7)
- Bug 1207890 - Part 1: Add rich ArtifactJob extension point. r=glandium (e402f5fcec)
- Bug 1207890 - Part 2: Stop extracting build ID from artifacts. r=glandium (314d6895c1)
- Bug 1207890 - Part 3: Post-process downloaded artifacts. r=glandium (09d60ac030)
- Bug 1207890 - Part 4: Download and process Mac OS X artifacts. r=glandium (181ba370b1)
- Bug 1207890 - Pre: Make JarWriter handle inputs with read() but not seek(). r=glandium (6ebb5dfe94)
- Bug 1207890 - Post: Hacks to make --disable-compile-environment work on Mac OS X. r=glandium (c5f88b6adf)
- Bug 1207890 - Post: Move |mach artifact| command out of mobile/android. r=glandium (a06f97dfb9)
- Bug 1207890 - Post: Hack to make |mach run| for Mac OS X artifact builds. r=me (4c6d2f6bfe)
- Bug 1207890 - Follow-up: Fix |mach artifact install| for mobile/android. r=me (a2e4347ca9)
- Bug 1236111 - part 3: ensure calls to hg and mach work on Windows, and that we use the right file mode when writing artifacts, r=nalexander,gps (d0090a5a56)
- Bug 1236111 - part 4: actually add Windows support to artifact code, r=nalexander,gps (ab40057ffa)
- Bug 1236111 - part 0: improve logging from process mixin, r=gps (d85265c134)
- Bug 1241398 - Add a dry-run mode to mach build-backend. r=gps (b300169915)
- Bug 1239217 - Make the RecursiveMake build system create backend files generically. r=gps (fba90d6bcb)
- fix minor misspatch of 1240990 (b7d44692bc)
- Bug 1239296 - Use telemetry_handler to store build resource data r=gps (58d7c3a260)
- Bug 1244143 - Record whether or not an artifact build was used in build telemetry data r=gps (d1821d1987)
- Bug 1246264 - Ensure cache directory exists for artifacts installation r=chmanchester (ef5c4a0fba)
- bug 1237619: save resource usage for "what" builds r=gps (6a311c71bc)
- Bug 1239296 - Add telemetry_handler function to mach context r=gps (4a7a67740d)
- Bug 1246402 - Environment variable to disable mercurial setup check. r=gps (d9cf129b6c)
- Bug 1239296 - add post_dispatch_handler hook to mach r=gps (aa55c9a36e)
- Bug 1236110 - Extend mach artifact to handle Linux Desktop builds. r=gps (cb29ca6d1d)
- Bug 1234912 - Check for mozext and pushlog entries after |mach artifact install| hg failure. r=gps (7bfb064c7c)
- Bug 1239096 - Improve English is artifacts.py comments. r=me (38aa5ecb19)
- Bug 1238320 - Part 1 (Linux): Download test binaries necessary to run xpcshell tests and mochitests in artifact builds. r=nalexander (f6407791ae)
- Bug 1238320 - Part 2 (Mac): Download test binaries necessary to run xpcshell tests and mochitests in artifact builds. r=nalexander (4d72cfc6f2)
- Bug 1238320 - Part 3 (Windows): Download test binaries necessary to run xpcshell tests and mochitests in artifact builds. r=nalexander# Please enter the commit message for your changes. Lines starting (40ac9f9f7d)
- Bug 1239678 - fix dll inclusion pattern on Windows and the placement of nested dlls like browsercomps and clearkey, r=nalexander (ad9015c9d9)
- Bug 1239738 - Handle artifact builds with no test binaries cleanly. r=ahunt (ba1593837a)
- Bug 1240323 - Fix installation of binary components in a subdir of dist/bin for linux artifact builds. r=nalexander (2f4b719ea3)
- Bug 1240239 - Install test plugins in artifact based builds. r=nalexander (edc24f4fd2)
- Bug 1240667 - Detect a tree to use for artifact builds based on recent changesets. r=nalexander (947879cb19)
- Bug 1244941 - Don't fill install manifest with artifacts. r=nalexander (8fa9793c53)
- Bug 1237619: Record build objects in resource_usage.json r=gps (c323d21c9f)
- bug 1237619: Add system and command metadata to resouce_usage.json r=gps (c93fb18c37)
- Bug 1240059 - Treat psutil as optional in record_resource_usage. r=gps (c91103ebce)
- Bug 1244160 - Create json-schema for build telemetry data r=gps (d8b3419cfd)
- Bug 1250624 - Overall system resources is displayed twice; r=chmanchester (a115c86902)
- Bug 1144842 (part 1) - Don't use MOZ_PROFILING before all the places it can be set. r=glandium. (3c12a2e29a)
- Bug 1144842 (part 2) - Make --enable-dmd imply --enable-profiling. r=glandium. (85c9ff5c32)
- Bug 1144842 (part 3) - Remove --enable-dmd code from js/src/configure.in. r=glandium. (52cf663bc7)
- Bug 1204260 - Pre: Don't expose ANDROID_{BUILD,PLATFORM}_TOOLS. r=glandium,gbrown (d4f560dd46)
- Bug 1219803 - Support 'mach run' for Android; r=jmaher (5a1a1ab16e)
- Bug 1219807 - Add tooltool manifests for jimdb; r=jmaher (4d7a211569)
- Bug 1221846 - Get Task Tracer building on desktop r=cyu. (5d1a0fabe9)
- Bug 1216681 - Add a fileid utility to extract the breakpad GUID from object files for identification in fix_stack_using_bpsyms. r=ted (e53eb5acc6)
- Bug 1237156 - Only build the fileid utility when MOZ_CRASHREPORTER is set. r=ted.mielczarek (328a80ae18)
- Bug 1239866 - Remove signaling standalone tests. r=bwc (b05b091059)
2023-09-27 11:04:31 +08:00

382 lines
12 KiB
Python

# --- ELLIPTIC CURVE MATH ------------------------------------------------------
#
# curve definition: y^2 = x^3 - p*x - q
# over finite field: Z/nZ* (prime residue classes modulo a prime number n)
#
#
# COPYRIGHT (c) 2010 by Toni Mattis <solaris@live.de>
# ------------------------------------------------------------------------------
'''
Module for elliptic curve arithmetic over a prime field GF(n).
E(GF(n)) takes the form y**2 == x**3 - p*x - q (mod n) for a prime n.
0. Structures used by this module
PARAMETERS and SCALARS are non-negative (long) integers.
A POINT (x, y), usually denoted p1, p2, ...
is a pair of (long) integers where 0 <= x < n and 0 <= y < n
A POINT in PROJECTIVE COORDINATES, usually denoted jp1, jp2, ...
takes the form (X, Y, Z, Z**2, Z**3) where x = X / Z**2
and y = Y / z**3. This form is called Jacobian coordinates.
The NEUTRAL element "0" or "O" is represented by None
in both coordinate systems.
1. Basic Functions
euclid() Is the Extended Euclidean Algorithm.
inv() Computes the multiplicative inversion modulo n.
curve_q() Finds the curve parameter q (mod n)
when p and a point are given.
element() Tests whether a point (x, y) is on the curve.
2. Point transformations
to_projective() Converts a point (x, y) to projective coordinates.
from_projective() Converts a point from projective coordinates
to (x, y) using the transformation described above.
neg() Computes the inverse point -P in both coordinate
systems.
3. Slow point arithmetic
These algorithms make use of basic geometry and modular arithmetic
thus being suitable for small numbers and academic study.
add() Computes the sum of two (x, y)-points
mul() Perform scalar multiplication using "double & add"
4. Fast point arithmetic
These algorithms make use of projective coordinates, signed binary
expansion and a JSP-like approach (joint sparse form).
The following functions consume and return projective coordinates:
addf() Optimized point addition.
doublef() Optimized point doubling.
mulf() Highly optimized scalar multiplication.
muladdf() Highly optimized addition of two products.
The following functions use the optimized ones above but consume
and output (x, y)-coordinates for a more convenient usage:
mulp() Encapsulates mulf()
muladdp() Encapsulates muladdf()
For single additions add() is generally faster than an encapsulation of
addf() which would involve expensive coordinate transformations.
Hence there is no addp() and doublep().
'''
# BASIC MATH -------------------------------------------------------------------
def euclid(a, b):
'''Solve x*a + y*b = ggt(a, b) and return (x, y, ggt(a, b))'''
# Non-recursive approach hence suitable for large numbers
x = yy = 0
y = xx = 1
while b:
q = a // b
a, b = b, a % b
x, xx = xx - q * x, x
y, yy = yy - q * y, y
return xx, yy, a
def inv(a, n):
'''Perform inversion 1/a modulo n. a and n should be COPRIME.'''
# coprimality is not checked here in favour of performance
i = euclid(a, n)[0]
while i < 0:
i += n
return i
def curve_q(x, y, p, n):
'''Find curve parameter q mod n having point (x, y) and parameter p'''
return ((x * x - p) * x - y * y) % n
def element(point, p, q, n):
'''Test, whether the given point is on the curve (p, q, n)'''
if point:
x, y = point
return (x * x * x - p * x - q) % n == (y * y) % n
else:
return True
def to_projective(p):
'''Transform point p given as (x, y) to projective coordinates'''
if p:
return (p[0], p[1], 1, 1, 1)
else:
return None # Identity point (0)
def from_projective(jp, n):
'''Transform a point from projective coordinates to (x, y) mod n'''
if jp:
return (jp[0] * inv(jp[3], n)) % n, (jp[1] * inv(jp[4], n)) % n
else:
return None # Identity point (0)
def neg(p, n):
'''Compute the inverse point to p in any coordinate system'''
return (p[0], (n - p[1]) % n) + p[2:] if p else None
# POINT ADDITION ---------------------------------------------------------------
# addition of points in y**2 = x**3 - p*x - q over <Z/nZ*; +>
def add(p, q, n, p1, p2):
'''Add points p1 and p2 over curve (p, q, n)'''
if p1 and p2:
x1, y1 = p1
x2, y2 = p2
if (x1 - x2) % n:
s = ((y1 - y2) * inv(x1 - x2, n)) % n # slope
x = (s * s - x1 - x2) % n # intersection with curve
return (x, n - (y1 + s * (x - x1)) % n)
else:
if (y1 + y2) % n: # slope s calculated by derivation
s = ((3 * x1 * x1 - p) * inv(2 * y1, n)) % n
x = (s * s - 2 * x1) % n # intersection with curve
return (x, n - (y1 + s * (x - x1)) % n)
else:
return None
else: # either p1 is not none -> ret. p1, otherwiese p2, which may be
return p1 if p1 else p2 # none too.
# faster addition: redundancy in projective coordinates eliminates
# expensive inversions mod n.
def addf(p, q, n, jp1, jp2):
'''Add jp1 and jp2 in projective (jacobian) coordinates.'''
if jp1 and jp2:
x1, y1, z1, z1s, z1c = jp1
x2, y2, z2, z2s, z2c = jp2
s1 = (y1 * z2c) % n
s2 = (y2 * z1c) % n
u1 = (x1 * z2s) % n
u2 = (x2 * z1s) % n
if (u1 - u2) % n:
h = (u2 - u1) % n
r = (s2 - s1) % n
hs = (h * h) % n
hc = (hs * h) % n
x3 = (-hc - 2 * u1 * hs + r * r) % n
y3 = (-s1 * hc + r * (u1 * hs - x3)) % n
z3 = (z1 * z2 * h) % n
z3s = (z3 * z3) % n
z3c = (z3s * z3) % n
return (x3, y3, z3, z3s, z3c)
else:
if (s1 + s2) % n:
return doublef(p, q, n, jp1)
else:
return None
else:
return jp1 if jp1 else jp2
# explicit point doubling using redundant coordinates
def doublef(p, q, n, jp):
'''Double jp in projective (jacobian) coordinates'''
if not jp:
return None
x1, y1, z1, z1p2, z1p3 = jp
y1p2 = (y1 * y1) % n
a = (4 * x1 * y1p2) % n
b = (3 * x1 * x1 - p * z1p3 * z1) % n
x3 = (b * b - 2 * a) % n
y3 = (b * (a - x3) - 8 * y1p2 * y1p2) % n
z3 = (2 * y1 * z1) % n
z3p2 = (z3 * z3) % n
return x3, y3, z3, z3p2, (z3p2 * z3) % n
# SCALAR MULTIPLICATION --------------------------------------------------------
# scalar multiplication p1 * c = p1 + p1 + ... + p1 (c times) in O(log(n))
def mul(p, q, n, p1, c):
'''multiply point p1 by scalar c over curve (p, q, n)'''
res = None
while c > 0:
if c & 1:
res = add(p, q, n, res, p1)
c >>= 1 # c = c / 2
p1 = add(p, q, n, p1, p1) # p1 = p1 * 2
return res
# this method allows _signed_bin() to choose between 1 and -1. It will select
# the sign which leaves the higher number of zeroes in the binary
# representation (the higher GDB).
def _gbd(n):
'''Compute second greatest base-2 divisor'''
i = 1
if n <= 0: return 0
while not n % i:
i <<= 1
return i >> 2
# This method transforms n into a binary representation having signed bits.
# A signed binary expansion contains more zero-bits hence reducing the number
# of additions required by a multiplication algorithm.
#
# Example: 15 ( 0b1111 ) can be written as 16 - 1, resulting in (1,0,0,0,-1)
# and saving 2 additions. Subtraction can be performed as
# efficiently as addition.
def _signed_bin(n):
'''Transform n into an optimized signed binary representation'''
r = []
while n > 1:
if n & 1:
cp = _gbd(n + 1)
cn = _gbd(n - 1)
if cp > cn: # -1 leaves more zeroes -> subtract -1 (= +1)
r.append(-1)
n += 1
else: # +1 leaves more zeroes -> subtract +1 (= -1)
r.append(+1)
n -= 1
else:
r.append(0) # be glad about one more zero
n >>= 1
r.append(n)
return r[::-1]
# This multiplication algorithm combines signed binary expansion and
# fast addition using projective coordinates resulting in 5 to 10 times
# faster multiplication.
def mulf(p, q, n, jp1, c):
'''Multiply point jp1 by c in projective coordinates'''
sb = _signed_bin(c)
res = None
jp0 = neg(jp1, n) # additive inverse of jp1 to be used fot bit -1
for s in sb:
res = doublef(p, q, n, res)
if s:
res = addf(p, q, n, res, jp1) if s > 0 else \
addf(p, q, n, res, jp0)
return res
# Encapsulates mulf() in order to enable flat coordinates (x, y)
def mulp(p, q, n, p1, c):
'''Multiply point p by c using fast multiplication'''
return from_projective(mulf(p, q, n, to_projective(p1), c), n)
# Sum of two products using Shamir's trick and signed binary expansion
def muladdf(p, q, n, jp1, c1, jp2, c2):
'''Efficiently compute c1 * jp1 + c2 * jp2 in projective coordinates'''
s1 = _signed_bin(c1)
s2 = _signed_bin(c2)
diff = len(s2) - len(s1)
if diff > 0:
s1 = [0] * diff + s1
elif diff < 0:
s2 = [0] * -diff + s2
jp1p2 = addf(p, q, n, jp1, jp2)
jp1n2 = addf(p, q, n, jp1, neg(jp2, n))
precomp = ((None, jp2, neg(jp2, n)),
(jp1, jp1p2, jp1n2),
(neg(jp1, n), neg(jp1n2, n), neg(jp1p2, n)))
res = None
for i, j in zip(s1, s2):
res = doublef(p, q, n, res)
if i or j:
res = addf(p, q, n, res, precomp[i][j])
return res
# Encapsulate muladdf()
def muladdp(p, q, n, p1, c1, p2, c2):
'''Efficiently compute c1 * p1 + c2 * p2 in (x, y)-coordinates'''
return from_projective(muladdf(p, q, n,
to_projective(p1), c1,
to_projective(p2), c2), n)
# POINT COMPRESSION ------------------------------------------------------------
# Compute the square root modulo n
# Determine the sign-bit of a point allowing to reconstruct y-coordinates
# when x and the sign-bit are given:
def sign_bit(p1):
'''Return the signedness of a point p1'''
return p1[1] % 2 if p1 else 0
# Reconstruct the y-coordinate when curve parameters, x and the sign-bit of
# the y coordinate are given:
def y_from_x(x, p, q, n, sign):
'''Return the y coordinate over curve (p, q, n) for given (x, sign)'''
# optimized form of (x**3 - p*x - q) % n
a = (((x * x) % n - p) * x - q) % n
if __name__ == "__main__":
import rsa
import time
t = time.time()
n = rsa.get_prime(256/8, 20)
tp = time.time() - t
p = rsa.random.randint(1, n)
p1 = (rsa.random.randint(1, n), rsa.random.randint(1, n))
q = curve_q(p1[0], p1[1], p, n)
r1 = rsa.random.randint(1,n)
r2 = rsa.random.randint(1,n)
q1 = mulp(p, q, n, p1, r1)
q2 = mulp(p, q, n, p1, r2)
s1 = mulp(p, q, n, q1, r2)
s2 = mulp(p, q, n, q2, r1)
s1 == s2
tt = time.time() - t
def test(tcount, bits = 256):
n = rsa.get_prime(bits/8, 20)
p = rsa.random.randint(1, n)
p1 = (rsa.random.randint(1, n), rsa.random.randint(1, n))
q = curve_q(p1[0], p1[1], p, n)
p2 = mulp(p, q, n, p1, rsa.random.randint(1, n))
c1 = [rsa.random.randint(1, n) for i in xrange(tcount)]
c2 = [rsa.random.randint(1, n) for i in xrange(tcount)]
c = zip(c1, c2)
t = time.time()
for i, j in c:
from_projective(addf(p, q, n,
mulf(p, q, n, to_projective(p1), i),
mulf(p, q, n, to_projective(p2), j)), n)
t1 = time.time() - t
t = time.time()
for i, j in c:
muladdp(p, q, n, p1, i, p2, j)
t2 = time.time() - t
return tcount, t1, t2