1 #include "curve25519.hpp"
11 typedef uint32_t smallval_t
;
12 typedef uint32_t cond_t
;
14 inline void square(const element
& a
, unsigned count
= 1)
18 memcpy(t
, a
.n
, sizeof(t
));
19 for(unsigned c
= 0; c
< count
; c
++) {
20 memset(x
, 0, sizeof(x
));
21 for(unsigned i
= 0; i
< 10; i
++) {
22 x
[i
+ i
] += (uint64_t)t
[i
] * t
[i
];
23 for(unsigned j
= 0; j
< i
; j
++)
24 x
[i
+ j
] += ((uint64_t)t
[i
] * t
[j
]) << 1;
27 for(unsigned i = 0; i < 20; i++) {
28 std::cerr << "2^" << std::hex << std::uppercase << 26*i << "*"
29 << std::hex << std::uppercase << x[i] << "+";
31 std::cerr << "0" << std::endl;
33 //Multiplication by 608 can overflow, so reduce these.
35 for(unsigned i
= 0; i
< 20; i
++) {
40 x
[19] += (carry2
<< 26);
42 for(unsigned i = 0; i < 20; i++) {
43 std::cerr << "2^" << std::hex << std::uppercase << 26*i << "*"
44 << std::hex << std::uppercase << x[i] << "+";
46 std::cerr << "0" << std::endl;
50 for(unsigned i
= 0; i
< 10; i
++) {
51 x
[i
] = x
[i
] + x
[10 + i
] * 608 + carry
;
58 for(unsigned i
= 0; i
< 10; i
++)
61 memcpy(n
, t
, sizeof(n
));
64 inline void multiply(const element
& a
, const element
& b
)
67 memset(x
, 0, sizeof(x
));
68 for(unsigned i
= 0; i
< 10; i
++)
69 for(unsigned j
= 0; j
< 10; j
++)
70 x
[i
+ j
] += (uint64_t)a
.n
[i
] * b
.n
[j
];
72 //Multiplication by 608 can overflow, so reduce these.
74 for(unsigned i
= 9; i
< 20; i
++) {
79 x
[19] += (carry2
<< 26);
83 for(unsigned i
= 0; i
< 10; i
++) {
84 x
[i
] = x
[i
] + x
[10 + i
] * 608 + carry
;
90 for(unsigned i
= 0; i
< 10; i
++)
94 inline void diff_back(const element
& e
)
96 uint32_t C1
= (1<<28)-2432;
97 uint32_t C2
= (1<<28)-4;
98 n
[0] = e
.n
[0] + C1
- n
[0];
99 for(unsigned i
= 1; i
< 10; i
++)
100 n
[i
] = e
.n
[i
] + C2
- n
[i
];
102 for(unsigned i
= 0; i
< 10; i
++) {
107 n
[9] |= (carry
<< 26);
109 //a * b -> self (with constant b).
110 inline void multiply(const element
& a
, smallval_t b
)
113 for(unsigned i
= 0; i
< 10; i
++) {
114 uint64_t x
= (uint64_t)a
.n
[i
] * b
+ carry
;
115 n
[i
] = x
& 0x3FFFFFF;
118 carry
= ((carry
<< 5) | (n
[9] >> 21)) * 19;
122 //Reduce mod 2^255-19 and store to buffer.
123 inline void store(uint8_t* buffer
)
125 uint32_t carry
= (n
[9] >> 21) * 19 + 19;
127 for(int i
= 0; i
< 10; i
++) {
130 n
[i
] = n
[i
] & 0x3FFFFFF;
132 carry
= 19 - (n
[9] >> 21) * 19;
133 for(int i
= 0; i
< 10; i
++) {
135 carry
= (n
[i
] >> 26) & 1;
136 n
[i
] = n
[i
] & 0x3FFFFFF;
139 for(unsigned i
= 0; i
< 32; i
++) {
140 buffer
[i
] = n
[8 * i
/ 26] >> (8 * i
% 26);
142 buffer
[i
] |= n
[8 * i
/ 26 + 1] << (26 - 8 * i
% 26);
146 inline explicit element(const uint8_t* buffer
)
148 memset(n
, 0, sizeof(n
));
149 for(unsigned i
= 0; i
< 32; i
++) {
150 n
[8 * i
/ 26] |= (uint32_t)buffer
[i
] << (8 * i
% 26);
151 n
[8 * i
/ 26] &= 0x3FFFFFF;
152 if(8 * i
% 26 > 18) {
153 n
[8 * i
/ 26 + 1] |= (uint32_t)buffer
[i
] >> (26 - 8 * i
% 26);
160 memset(n
, 0, sizeof(n
));
162 //Construct small value.
163 inline element(smallval_t sval
)
165 memset(n
, 0, sizeof(n
));
169 inline void sum(const element
& e
)
172 for(int i
= 0; i
< 10; i
++) {
173 n
[i
] = n
[i
] + e
.n
[i
] + carry
;
175 n
[i
] = n
[i
] & 0x3FFFFFF;
179 //If condition=1, swap self,e.
180 inline void swap_cond(element
& e
, cond_t condition
)
182 condition
= -condition
;
183 for(int i
= 0; i
< 10; i
++) {
184 uint32_t t
= condition
& (n
[i
] ^ e
.n
[i
]);
189 void debug(const char* pfx
) const
192 std::cerr
<< pfx
<< ": ";
194 for(unsigned i
= 0; i
< 10*32; i
++) {
195 unsigned rbit
= 26*(i
>>5)+(i
&31);
196 if((n
[i
>>5] >> (i
&31)) & 1)
197 buf
[rbit
>>3]|=(1<<(rbit
&7));
199 for(unsigned i
= 33; i
< 34; i
--)
200 std::cerr
<< std::setw(2) << std::setfill('0') << std::hex
<< std::uppercase
202 std::cerr
<< std::endl
;
209 static void montgomery(element
& dblx
, element
& dblz
, element
& sumx
, element
& sumz
,
210 element
& ax
, element
& az
, element
& bx
, element
& bz
, const element
& diff
)
219 oax
.multiply(az
, bx
);
220 obx
.multiply(ax
, bz
);
223 dblx
.multiply(bx
, bz
);
225 tmp
.multiply(bz
, 121665);
227 dblz
.multiply(bx
, bz
);
233 sumz
.multiply(bz
, diff
);
236 static void cmultiply(element
& ox
, element
& oz
, const uint8_t* key
, const element
& base
)
238 element
x1a(1), z1a
, x2a(base
), z2a(1), x1b
, z1b(1), x2b
, z2b(1);
240 for(unsigned i
= 31; i
< 32; i
--) {
242 for(unsigned j
= 0; j
< 4; j
++) {
243 element::cond_t bit
= (x
>> 7);
244 x1a
.swap_cond(x2a
, bit
);
245 z1a
.swap_cond(z2a
, bit
);
246 montgomery(x1b
, z1b
, x2b
, z2b
, x1a
, z1a
, x2a
, z2a
, base
);
247 x1b
.swap_cond(x2b
, bit
);
248 z1b
.swap_cond(z2b
, bit
);
251 x1b
.swap_cond(x2b
, bit
);
252 z1b
.swap_cond(z2b
, bit
);
253 montgomery(x1a
, z1a
, x2a
, z2a
, x1b
, z1b
, x2b
, z2b
, base
);
254 x1a
.swap_cond(x2a
, bit
);
255 z1a
.swap_cond(z2a
, bit
);
263 static void invert(element
& out
, const element
& in
)
265 element r
, y
, g
, b
, c
;
290 void curve25519(uint8_t* _out
, const uint8_t* key
, const uint8_t* _base
)
292 element
base(_base
), outx
, outz
, zinv
;
293 cmultiply(outx
, outz
, key
, base
);
295 outz
.multiply(outx
, zinv
);
299 void curve25519_clamp(uint8_t* key
)
306 const uint8_t curve25519_base
[32] = {9};
312 int curve25519_donna(uint8_t *mypublic, const uint8_t *secret, const uint8_t *basepoint);
317 uint8_t buf[128] = {0};
318 FILE* fd = fopen("/dev/urandom", "rb");
322 fread(buf, 1, 32, fd);
326 curve25519(buf+64, buf, buf+32);
327 curve25519_donna(buf+96, buf, buf+32);
328 if(memcmp(buf+64,buf+96,32)) {
329 std::cerr << "Fail test: " << std::endl;
330 std::cerr << "key:\t";
331 for(unsigned i = 31; i < 32; i--)
332 std::cerr << std::hex << std::uppercase << std::setw(2) << std::setfill('0')
334 std::cerr << std::endl;
335 std::cerr << "point:\t";
336 for(unsigned i = 31; i < 32; i--)
337 std::cerr << std::hex << std::uppercase << std::setw(2) << std::setfill('0')
339 std::cerr << std::endl;
340 std::cerr << "res1:\t";
341 for(unsigned i = 31; i < 32; i--)
342 std::cerr << std::hex << std::uppercase << std::setw(2) << std::setfill('0')
344 std::cerr << std::endl;
345 std::cerr << "res2:\t";
346 for(unsigned i = 31; i < 32; i--)
347 std::cerr << std::hex << std::uppercase << std::setw(2) << std::setfill('0')
349 std::cerr << std::endl;
352 if(++ctr % 10000 == 0)
353 std::cerr << "Passed " << ctr << " tests." << std::endl;