summaryrefslogtreecommitdiffstats
path: root/python/PyECC/ecc/encoding.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/PyECC/ecc/encoding.py')
-rw-r--r--python/PyECC/ecc/encoding.py178
1 files changed, 178 insertions, 0 deletions
diff --git a/python/PyECC/ecc/encoding.py b/python/PyECC/ecc/encoding.py
new file mode 100644
index 000000000..24d3eb5a8
--- /dev/null
+++ b/python/PyECC/ecc/encoding.py
@@ -0,0 +1,178 @@
+#
+# Encodings and Formats for Elliptic Curve Cryptography
+#
+
+import StringIO
+
+# Big-Endian Encoding
+
+def enc_long(n):
+ '''Encodes arbitrarily large number n to a sequence of bytes.
+ Big endian byte order is used.'''
+ s = ""
+ while n > 0:
+ s = chr(n & 0xFF) + s
+ n >>= 8
+ return s
+
+def enc_int(n):
+ '''Encodes an integer n to a 4-byte string.
+ Big endian byte order is used.'''
+ return chr((n >> 24) & 0xFF) + chr((n >> 16) & 0xFF) + \
+ chr((n >> 8) & 0xFF) + chr( n & 0xFF)
+
+def enc_fixed_long(n, length):
+ return enc_long(n)[:length].rjust(length, '\x00')
+
+def dec_long(s):
+ '''Decodes s to its numeric representation.
+ Big endian byte order is used.'''
+ n = 0
+ for c in s:
+ n = (n << 8) | ord(c)
+ return n
+
+# dec_int not necessary,
+# dec_long does the same when provided with 4 bytes input.
+
+# Chunks
+
+def enc_chunks(*args):
+ '''Chain given string args or sub-chunks to a single chunk'''
+ return ''.join([enc_int(len(a)) + a for a in args])
+
+def dec_chunks(s):
+ '''Split a chunk into strings or sub-chunks'''
+ i = 0
+ result = []
+ while i < len(s):
+ size = dec_long(s[i : i + 4])
+ i += 4
+ result.append(s[i : i + size])
+ i += size
+ return result
+
+# Point and signature data
+
+def enc_point(p):
+ '''Encode a point p = (x, y)'''
+ x, y = p
+ sx = enc_long(x)
+ sy = enc_long(y)
+ diff = len(sx) - len(sy)
+ if diff > 0:
+ sy = '\x00' * diff + sy
+ elif diff < 0:
+ sx = '\x00' * -diff + sx
+ return sx + sy
+
+def dec_point(s):
+ '''Decode an even length string s to a point(x, y)'''
+ d = len(s) / 2
+ return (dec_long(s[:d]), dec_long(s[d:]))
+
+
+class Encoder:
+
+ def __init__(self):
+ self._io = StringIO.StringIO()
+
+ def int(self, n, size = 4):
+ self._io.write(enc_fixed_long(n, size))
+ return self
+
+ def long(self, n, pre = 2):
+ lstr = enc_long(n)
+ self._io.write(enc_fixed_long(len(lstr), pre) + lstr)
+ return self
+
+ def str(self, s, pre = 2):
+ self._io.write(enc_fixed_long(len(s), pre) + s)
+ return self
+
+ def point(self, p, pre = 2):
+ lstr = enc_point(p)
+ self._io.write(enc_fixed_long(len(lstr), pre) + lstr)
+ return self
+
+ def chunk(self, enc, pre = 2):
+ lstr = enc.out()
+ self._io.write(enc_fixed_long(len(lstr), pre) + lstr)
+ return self
+
+ def out(self):
+ return self._io.getvalue()
+
+class Decoder:
+
+ def __init__(self, data, offset = 0):
+ self._io = StringIO.StringIO(data)
+ self._io.seek(offset)
+ self._res = []
+ self._limit = None
+ self._parent = None
+
+ def _ret(self):
+## if self._parent and self._io.tell() >= self._limit:
+## return self.exit()
+## else:
+## return self
+ return self
+
+ def int(self, size = 4):
+ self._res.append(dec_long(self._io.read(size)))
+ return self._ret()
+
+
+ def long(self, pre = 2):
+ llen = dec_long(self._io.read(pre))
+ self._res.append(dec_long(self._io.read(llen)))
+ return self._ret()
+
+ def str(self, pre = 2):
+ llen = dec_long(self._io.read(pre))
+ self._res.append(self._io.read(llen))
+ return self._ret()
+
+ def point(self, pre = 2):
+ llen = dec_long(self._io.read(pre))
+ self._res.append(dec_point(self._io.read(llen)))
+ return self._ret()
+
+ def enter(self, pre = 2):
+ llen = dec_long(self._io.read(pre))
+ subcoder = Decoder("")
+ subcoder._io = self._io
+ subcoder._parent = self
+ subcoder._limit = self._io.tell() + llen
+ return subcoder
+
+ def chunk(self, pre = 2):
+ llen = dec_long(self._io.read(pre))
+ self._res.append(Decoder(self._io.read(llen)))
+ return self._ret()
+
+ def exit(self):
+ if self._parent:
+ self._parent._io.seek(self._limit)
+ self._parent._res.append(self._res)
+ return self._parent
+ else:
+ raise RuntimeError, "Cannont exit top level Decoder"
+
+ def continues(self):
+ return (not self._limit) or (self._io.tell() < self._limit)
+
+ def out(self, exit_all = False):
+ if exit_all and self._parent:
+ return self.exit().out()
+ else:
+ r = self._res
+ self._res = []
+ return r
+
+ def only(self):
+ if self._res:
+ return self._res.pop(0)
+ else:
+ return RuntimeError, "Only what? (Empty decoder stack)"