chiark / gitweb /
rand/rand-x86ish.S: Hoist argument register allocation outside.
[catacomb] / utils / strobe
1 #! /usr/bin/python
2
3 import catacomb as CAT
4
5 I = 1
6 A = 2
7 C = 4
8 T = 8
9 M = 16
10 INIT = 256
11
12 def dump_keccak_state(what, state):
13   buf = CAT.ReadBuffer(state + CAT.ByteString.zero(200 - len(state)))
14   print ";; %s [round 0]" % what
15   print ";; uncomplemented state..."
16   for i in xrange(5):
17     print ";;\t%s" % " ".join(["%016x" % buf.getu64l() for j in xrange(5)])
18   print
19
20 class Strobe (object):
21   def __init__(me, sec = 128, _copy = None):
22     if _copy is None:
23       me.k = CAT.Keccak1600()
24       me.r = (1600 - 2*sec)/8
25       me.f = 0
26       me.p0 = 0
27       buf = CAT.WriteBuffer()
28       buf.putu8(1).putu8(me.r)
29       buf.putu8(1).putu8(0)
30       buf.putu8(1).putu8(12*8).put('STROBEv1.0.2')
31       ##dump_keccak_state("init", buf.contents)
32       me.k.mix(buf.contents).step()
33       me.buf = CAT.WriteBuffer()
34       me.mask = me.k.extract(me.r - 2)
35       ##dump_keccak_state("final", me.mask)
36     else:
37       me.k = _copy.k.dup()
38       me.r = _copy.r
39       me.f = _copy.f
40       me.p0 = _copy.p0
41       me.buf = CAT.WriteBuffer().put(_copy.buf.contents)
42       me.mask = me._copy.mask
43
44   def _crank(me):
45     me.buf.putu8(me.p0); me.p0 = 0
46     if me.buf.size == me.r - 1: me.buf.putu8(0x84)
47     else: me.buf.putu8(0x04).zero(me.r - me.buf.size - 1).putu8(0x80)
48     ##dump_keccak_state("buffer", me.buf.contents)
49     ##dump_keccak_state("init", me.buf.contents ^ me.k.extract(me.r))
50     me.k.mix(me.buf.contents).step()
51     me.mask = me.k.extract(me.r - 2)
52     ##dump_keccak_state("final", me.mask)
53     me.buf = CAT.WriteBuffer()
54
55   def process(me, op, input):
56     if not op&T:
57       opf = op
58     else:
59       if not me.f&INIT: me.f |= INIT | (op&I)
60       opf = op ^ (me.f&255)
61     me.buf.putu8(me.p0); me.p0 = me.buf.size
62     if me.buf.size >= me.r - 2: me._crank()
63     me.buf.putu8(opf)
64     if op&C or me.buf.size >= me.r - 2: me._crank()
65
66     if op&(I | T) == I or op&(I | A) == 0: buf = CAT.ByteString.zero(input)
67     else: buf = CAT.ByteString(input)
68     out = CAT.WriteBuffer()
69     i, j, sz = 0, me.buf.size, len(buf)
70
71     while i < sz:
72       spare = me.r - j - 2
73       n = min(spare, sz - i); x = buf[i:i + n]; i += n
74       if not op&C: out.put(x); me.buf.put(x)
75       else:
76         y = x ^ me.mask[j:j + n]; out.put(y)
77         if op&I or not op&T: me.buf.put(y)
78         else: me.buf.put(x)
79       if n == spare: me._crank(); j = 0
80
81     if op&(I | A | C | T) != (I | C | T): return out.contents
82     elif out.contents == CAT.ByteString.zero(out.size): return me
83     else: raise ValueError, 'verify failed'
84
85 st0 = Strobe()
86 st1 = Strobe()
87
88 st0.process(A | M, 'testing')
89 st1.process(A | M, 'testing')
90
91 print 'prf(10) -> %s' % hex(st0.process(I | A | C, 10))
92 st1.process(I | A | C, 10)
93
94 print 'ad("Hello")'
95 st0.process(A, 'Hello')
96 st1.process(A, 'Hello')
97
98 c0 = st0.process(A | C | T, 'World');
99 st1.process(I | A | C | T, c0)
100 print 'encout("World") -> %s' %  hex(c0)
101
102 print 'clrout("foo")'
103 st0.process(A | T, 'foo');
104 st1.process(I | A | T, 'foo')
105
106 print 'clrin("bar")'
107 st1.process(A | T, 'bar')
108 st0.process(I | A | T, 'bar')
109
110 m1 = st0.process(I | A | C | T, 'baz')
111 st1.process(A | C | T, m1) #  backwards in time
112 print 'encin("baz") -> %s' % hex(m1)
113
114 for i in xrange(200):
115   c = st0.process(A | C | T, i*'X')
116   m = st1.process(I | A | C | T, c)
117   print "  0 encout\n\t=%s\n\t!%s;" % (i*'X', hex(c))
118   print "  1 encin\n\t!%s\n\t=%s;" % (hex(c), i*'X')
119
120 r0 = st0.process(I | A | C, 123)
121 r1 = st1.process(I | A | C, 123)
122 print 'prf(123) -> %s' % hex(r0)
123 assert r0 == r1
124
125 t = st0.process(C | T, 16)
126 print 'macout(16) -> %s' % hex(t)
127 st1.process(I | C | T, t)
128
129 k = 'this is my super-secret key'
130 print 'key("%s")' % k
131 st0.process(A | C, k)
132 st1.process(A | C, k)
133
134 r0 = st0.process(I | A | C, 32)
135 r1 = st1.process(I | A | C, 32)
136 print 'prf(32) -> %s' % hex(r0)
137 assert r0 == r1
138
139 print 'ratchet(32)'
140 st0.process(C, 32)
141 st1.process(C, 32)
142
143 t0 = CAT.bytes('b2084ebdfabd50768c91eebc190132cc')
144 st0.process(I | C | T, t0)
145 t1 = st1.process(C | T, 16)
146 assert t1 == t0
147 print 'macin(%s)' % hex(t0)