1// seal.cpp - written and placed in the public domain by Wei Dai
2// updated to SEAL 3.0 by Leonard Janke
3
4#include "pch.h"
5
6#include "seal.h"
7#include "sha.h"
8#include "misc.h"
9
10NAMESPACE_BEGIN(CryptoPP)
11
12void SEAL_TestInstantiations()
13{
14	SEAL<>::Encryption x;
15}
16
17struct SEAL_Gamma
18{
19	SEAL_Gamma(const byte *key)
20		: H(5), Z(5), D(16), lastIndex(0xffffffff)
21	{
22		GetUserKey(BIG_ENDIAN_ORDER, H.begin(), 5, key, 20);
23		memset(D, 0, 64);
24	}
25
26	word32 Apply(word32 i);
27
28	SecBlock<word32> H, Z, D;
29	word32 lastIndex;
30};
31
32word32 SEAL_Gamma::Apply(word32 i)
33{
34	word32 shaIndex = i/5;
35	if (shaIndex != lastIndex)
36	{
37		memcpy(Z, H, 20);
38		D[0] = shaIndex;
39		SHA::Transform(Z, D);
40		lastIndex = shaIndex;
41	}
42	return Z[i%5];
43}
44
45template <class B>
46void SEAL_Policy<B>::CipherSetKey(const NameValuePairs &params, const byte *key, size_t length)
47{
48	m_insideCounter = m_outsideCounter = m_startCount = 0;
49
50	unsigned int L = params.GetIntValueWithDefault("NumberOfOutputBitsPerPositionIndex", 32*1024);
51	m_iterationsPerCount = L / 8192;
52
53	SEAL_Gamma gamma(key);
54	unsigned int i;
55
56	for (i=0; i<512; i++)
57		m_T[i] = gamma.Apply(i);
58
59	for (i=0; i<256; i++)
60		m_S[i] = gamma.Apply(0x1000+i);
61
62	m_R.New(4*(L/8192));
63
64	for (i=0; i<m_R.size(); i++)
65		m_R[i] = gamma.Apply(0x2000+i);
66}
67
68template <class B>
69void SEAL_Policy<B>::CipherResynchronize(byte *keystreamBuffer, const byte *IV, size_t length)
70{
71	assert(length==4);
72	m_outsideCounter = IV ? GetWord<word32>(false, BIG_ENDIAN_ORDER, IV) : 0;
73	m_startCount = m_outsideCounter;
74	m_insideCounter = 0;
75}
76
77template <class B>
78void SEAL_Policy<B>::SeekToIteration(lword iterationCount)
79{
80	m_outsideCounter = m_startCount + (unsigned int)(iterationCount / m_iterationsPerCount);
81	m_insideCounter = (unsigned int)(iterationCount % m_iterationsPerCount);
82}
83
84template <class B>
85void SEAL_Policy<B>::OperateKeystream(KeystreamOperation operation, byte *output, const byte *input, size_t iterationCount)
86{
87	word32 a, b, c, d, n1, n2, n3, n4;
88	unsigned int p, q;
89
90	for (size_t iteration = 0; iteration < iterationCount; ++iteration)
91	{
92#define Ttab(x) *(word32 *)((byte *)m_T.begin()+x)
93
94		a = m_outsideCounter ^ m_R[4*m_insideCounter];
95		b = rotrFixed(m_outsideCounter, 8U) ^ m_R[4*m_insideCounter+1];
96		c = rotrFixed(m_outsideCounter, 16U) ^ m_R[4*m_insideCounter+2];
97		d = rotrFixed(m_outsideCounter, 24U) ^ m_R[4*m_insideCounter+3];
98
99		for (unsigned int j=0; j<2; j++)
100		{
101			p = a & 0x7fc;
102			b += Ttab(p);
103			a = rotrFixed(a, 9U);
104
105			p = b & 0x7fc;
106			c += Ttab(p);
107			b = rotrFixed(b, 9U);
108
109			p = c & 0x7fc;
110			d += Ttab(p);
111			c = rotrFixed(c, 9U);
112
113			p = d & 0x7fc;
114			a += Ttab(p);
115			d = rotrFixed(d, 9U);
116		}
117
118		n1 = d, n2 = b, n3 = a, n4 = c;
119
120		p = a & 0x7fc;
121		b += Ttab(p);
122		a = rotrFixed(a, 9U);
123
124		p = b & 0x7fc;
125		c += Ttab(p);
126		b = rotrFixed(b, 9U);
127
128		p = c & 0x7fc;
129		d += Ttab(p);
130		c = rotrFixed(c, 9U);
131
132		p = d & 0x7fc;
133		a += Ttab(p);
134		d = rotrFixed(d, 9U);
135
136		// generate 8192 bits
137		for (unsigned int i=0; i<64; i++)
138		{
139			p = a & 0x7fc;
140			a = rotrFixed(a, 9U);
141			b += Ttab(p);
142			b ^= a;
143
144			q = b & 0x7fc;
145			b = rotrFixed(b, 9U);
146			c ^= Ttab(q);
147			c += b;
148
149			p = (p+c) & 0x7fc;
150			c = rotrFixed(c, 9U);
151			d += Ttab(p);
152			d ^= c;
153
154			q = (q+d) & 0x7fc;
155			d = rotrFixed(d, 9U);
156			a ^= Ttab(q);
157			a += d;
158
159			p = (p+a) & 0x7fc;
160			b ^= Ttab(p);
161			a = rotrFixed(a, 9U);
162
163			q = (q+b) & 0x7fc;
164			c += Ttab(q);
165			b = rotrFixed(b, 9U);
166
167			p = (p+c) & 0x7fc;
168			d ^= Ttab(p);
169			c = rotrFixed(c, 9U);
170
171			q = (q+d) & 0x7fc;
172			d = rotrFixed(d, 9U);
173			a += Ttab(q);
174
175#define SEAL_OUTPUT(x)	\
176	CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, B::ToEnum(), 0, b + m_S[4*i+0]);\
177	CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, B::ToEnum(), 1, c ^ m_S[4*i+1]);\
178	CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, B::ToEnum(), 2, d + m_S[4*i+2]);\
179	CRYPTOPP_KEYSTREAM_OUTPUT_WORD(x, B::ToEnum(), 3, a ^ m_S[4*i+3]);
180
181			CRYPTOPP_KEYSTREAM_OUTPUT_SWITCH(SEAL_OUTPUT, 4*4);
182
183			if (i & 1)
184			{
185				a += n3;
186				b += n4;
187				c ^= n3;
188				d ^= n4;
189			}
190			else
191			{
192				a += n1;
193				b += n2;
194				c ^= n1;
195				d ^= n2;
196			}
197		}
198
199		if (++m_insideCounter == m_iterationsPerCount)
200		{
201			++m_outsideCounter;
202			m_insideCounter = 0;
203		}
204	}
205
206	a = b = c = d = n1 = n2 = n3 = n4 = 0;
207	p = q = 0;
208}
209
210template class SEAL_Policy<BigEndian>;
211template class SEAL_Policy<LittleEndian>;
212
213NAMESPACE_END
214