utils/split-pieces, pub/ed25519.c: New utility makes field-element constants.
[catacomb] / utils / split-pieces
diff --git a/utils/split-pieces b/utils/split-pieces
new file mode 100755 (executable)
index 0000000..473e2fe
--- /dev/null
@@ -0,0 +1,83 @@
+#! /usr/bin/python
+
+from sys import argv, exit
+from itertools import cycle, izip
+import re as RX
+
+def bad_usage():
+  exit('usage: split-pieces { scaf WD | qf WD/N|WD,WD,... } N N ...')
+
+ARGC = 1
+def getarg(must = True):
+  global ARGC
+  if ARGC < len(argv): ARGC += 1; return argv[ARGC - 1]
+  elif must: bad_usage()
+  else: return None
+
+class ScafConvert (object):
+  def __init__(me, piecewd):
+    me.piecewd = piecewd
+    me.fmt = '0x%%0%dx' % ((piecewd + 3)/4)
+    me.mask = (1 << piecewd) - 1
+  @classmethod
+  def parse(cls):
+    return ScafConvert(int(getarg()))
+  def hack(me, n):
+    nn = []
+    while n:
+      nn.append(me.fmt % (n&me.mask))
+      n >>= me.piecewd
+    return nn
+  def unhack(me, nn):
+    return sum(n << i*me.piecewd for i, n in enumerate(nn))
+
+class QfConvert (object):
+  def __init__(me, p, wdseq):
+    me.p = p
+    me.wdseq = wdseq
+  @classmethod
+  def parse(cls):
+    p = eval(getarg())
+    arg = getarg()
+    if '/' in arg:
+      wd, n = map(int, arg.split('/'))
+      seq = [(wd*(i + 1) + n - 1)/n - (wd*i + n - 1)/n for i in xrange(n)]
+    else:
+      seq = map(int, arg.split(','))
+    print ";; piece widths = %r" % seq
+    return QfConvert(p, seq)
+  def hack(me, n):
+    if 2*n >= me.p: n -= p
+    nn = []
+    wds = cycle(me.wdseq)
+    while n:
+      wd = wds.next()
+      lim = 1 << wd; m = lim - 1
+      d = n&m; n >>= wd
+      if d >= lim/2: d -= lim; n += 1
+      nn.append(str(d))
+    return nn
+  def unhack(me, nn):
+    a = o = 0
+    for n, w in izip(nn, cycle(me.wdseq)):
+      a += n << o
+      o += w
+    if a < 0: a += me.p
+    return a
+
+R_split = RX.compile(r',\s*|\s+')
+def spliteval(arg): return map(eval, R_split.split(arg.strip()))
+
+convmap = { 'scaf': ScafConvert,
+            'unscaf': ScafConvert,
+            'qf': QfConvert,
+            'unqf': QfConvert }
+op = getarg()
+cvt = convmap[op].parse()
+if op.startswith('un'): prepare, conv, format = spliteval, cvt.unhack, str
+else: prepare, conv, format = eval, cvt.hack, lambda vv: ', '.join(vv)
+
+while True:
+  val = getarg(must = False)
+  if val is None: break
+  print format(conv(prepare(val)))