1 /**
2 * A minimal 128-bit integer type for curve25519-donna
3 *
4 * (C) 2014 Jack Lloyd
5 * (C) 2014-2015 Etienne Cimon
6 *
7 * License:
8 * Botan is released under the Simplified BSD License (see LICENSE.md)
9 */
10 module botan.utils.donna128;
11 
12 import botan.utils.mul128;
13 
14 struct donna128
15 {
16 public:
17 	void opAssign(donna128 other) {
18 		this.l = other.l;
19 		this.h = other.h;
20 	}
21 
22 	void opAssign(in ulong other) {
23 		this.l = other;
24 	}
25 
26 	donna128 opBinary(string op)(size_t shift) const
27 		if (op == ">>")
28 	{
29 		donna128 z = this;
30 		const ulong carry = z.h << (64 - shift);
31 		z.h = (z.h >> shift);
32 		z.l = (z.l >> shift) | carry;
33 		return z;
34 	}
35 
36 	donna128 opBinary(string op)(size_t shift) const
37 		if (op == "<<")
38 	{
39 		donna128 z = donna128(l, h);
40 		const ulong carry = z.l >> (64 - shift);
41 		z.l = (z.l << shift);
42 		z.h = (z.h << shift) | carry;
43 		return z;
44 	}
45 
46 	ulong opBinary(string op)(ulong mask) const
47 		if (op == "&")
48 	{
49 		return l & mask;
50 	}
51 
52 	ulong opOpAssign(string op)(ulong mask)
53 		if (op == "&")
54 	{
55 		h = 0;
56 		l &= mask;
57 		return l;
58 	}
59 
60 	donna128 opOpAssign(string op)(auto const ref donna128 x)
61 		if (op == "+")
62 	{
63 		l += x.l;
64 		h += (l < x.l);
65 		h += x.h;
66 		return donna128(l, h);
67 	}
68 
69 	donna128 opOpAssign(string op)(ulong x)
70 		if (op == "+")
71 	{
72 		l += x;
73 		h += (l < x);
74 		return donna128(l, h);
75 	}
76 
77 	donna128 opBinary(string op)(ulong y)
78 		if (op == "*")
79 	{
80 		assert(hi() == 0, "High 64 bits of donna128 set to zero during multiply");
81 
82 		ulong[2] lohi;
83 		mul64x64_128(this.lo(), y, lohi);
84 		return donna128(lohi[0], lohi[1]);
85 	}
86 
87 	donna128 opBinary(string op)(auto const ref donna128 y) const
88 		if (op == "+")
89 	{
90 		donna128 z = donna128(l, h);
91 		z += y;
92 		return z;
93 	}
94 
95 	donna128 opBinary(string op)(ulong y) const
96 		if (op == "+")
97 	{
98 		donna128 z = donna128(l, h);
99 		z += y;
100 		return z;
101 	}
102 
103 	donna128 opBinary(string op)(auto const ref donna128 y) const
104 		if (op == "|")
105 	{
106 		return donna128(this.lo() | y.lo(), this.hi() | y.hi());
107 	}
108 
109 	ulong lo() const { return l;}
110 	ulong hi() const { return h;}
111 	ulong l;
112 	ulong h;
113 }
114 
115 
116 ulong carry_shift(const donna128 a, size_t shift)
117 {
118     return (a >> shift).lo();
119 }
120 
121 ulong combine_lower(in donna128 a, size_t s1,
122                     in donna128 b, size_t s2)
123 {
124     donna128 z = (a >> s1) | (b << s2);
125     return z.lo();
126 }