]> git.siccegge.de Git - software/DIPE.git/blob - src/DIPE.cxx
integrate secret sharing
[software/DIPE.git] / src / DIPE.cxx
1 #include "DIPE.h"
2 #include "DIPE_Internal.h"
3
4 #include <string.h>
5 #include <nettle/hkdf.h>
6 #include <nettle/hmac.h>
7 #include <sys/random.h>
8 #include <nettle/gcm.h>
9 #include <nettle/memops.h>
10 #include <arpa/inet.h>
11 #include <algorithm>
12 #include <errno.h>
13
14 using std::min;
15 using std::max;
16
17
18
19 namespace {
20 size_t dipe_h_length(element_t elem, size_t dimension) {
21 return 16 /*cid*/ + dimension * element_length_in_bytes(elem);
22 }
23
24 void dipe_generate_h(const char* cid, element_t* y, size_t dimension, unsigned char* result) {
25 memcpy(result, cid, 16);
26 unsigned char* next_element = result+16;
27 for (size_t i = 0; i < dimension; ++i) {
28 element_to_bytes(next_element, y[i]);
29 next_element += element_length_in_bytes(y[0]);
30 }
31 }
32
33 void dipe_generate_aeskey(element_t encapkey, uint8_t* aeskey) {
34 struct hmac_sha256_ctx ctx;
35 uint8_t salt[SHA256_DIGEST_SIZE];
36 memset(salt, 0, SHA256_DIGEST_SIZE);
37 size_t elen = element_length_in_bytes(encapkey);
38 uint8_t coded[elen];
39 element_to_bytes(coded, encapkey);
40
41 hmac_sha256_set_key(&ctx, SHA256_DIGEST_SIZE, salt);
42 hkdf_extract(&ctx,
43 (nettle_hash_update_func *)hmac_sha256_update,
44 (nettle_hash_digest_func *)hmac_sha256_digest,
45 SHA256_DIGEST_SIZE,
46 elen, coded,
47 aeskey);
48 }
49
50 /* Data format is iv | enc(4 byte len | ptxt | 0 padding) | tag
51 */
52 int dipe_aes_encrypt(uint8_t* key, uint8_t* iv, size_t ptxt_len, uint8_t* ptxt, size_t ctxt_len, uint8_t* ctxt) {
53 struct gcm_aes128_ctx ctx;
54 uint8_t block[16];
55 uint32_t coded_ptxtlen;
56
57 ctxt_len -= 16; /* Tag */
58 if (ctxt_len < ptxt_len + 4) return 0;
59
60 memset(block, 0, 16);
61 gcm_aes128_set_key(&ctx, key);
62 gcm_aes128_set_iv(&ctx, 12, iv);
63
64 /* First Block */
65 coded_ptxtlen = htonl(ptxt_len);
66 memcpy(block, &coded_ptxtlen, 4);
67 memcpy(block+4, ptxt, min((size_t)12, ptxt_len));
68 ptxt_len -= min((size_t)12, ptxt_len);
69 ptxt += 12;
70
71 while (ctxt_len >= 16) {
72 gcm_aes128_encrypt(&ctx, 16, ctxt, block);
73 memset(block, 0, 16);
74 ctxt_len -= 16;
75 ctxt += 16;
76
77 if (ptxt_len > 0) {
78 memcpy(block, ptxt, min((size_t)16, ptxt_len));
79 ptxt += 16;
80 ptxt_len -= min((size_t)16, ptxt_len);
81 }
82 }
83
84 if (ctxt_len > 0) {
85 gcm_aes128_encrypt(&ctx, ctxt_len, ctxt, block);
86 ctxt += ctxt_len;
87 }
88
89 gcm_aes128_digest(&ctx, 16, ctxt);
90 return 0;
91 }
92
93 int dipe_aes_decrypt(uint8_t* key, uint8_t* iv, size_t len, uint8_t* ctxt, uint8_t* ptxt) {
94 struct gcm_aes128_ctx ctx;
95 uint8_t block[16];
96
97 gcm_aes128_set_key(&ctx, key);
98 gcm_aes128_set_iv(&ctx, 12, iv);
99 len -= 16; /* GCM tag */
100
101
102 gcm_aes128_decrypt(&ctx, min((size_t)16, len), block, ctxt);
103 uint32_t ptxtlen = 0;
104 memcpy(&ptxtlen, block, 4);
105 memcpy(ptxt, block+4, min((size_t)12, len-4));
106 ptxtlen = ntohl(ptxtlen);
107 ctxt += min((size_t)16, len); len -= min((size_t)16, len);
108 ptxt += 12;
109
110 if (len > 0) {
111 gcm_aes128_decrypt(&ctx, len, ptxt, ctxt);
112 ctxt += len;
113 }
114 gcm_aes128_digest(&ctx, 16, block);
115
116 /* error case is with return code 0, see manual
117 * https://www.lysator.liu.se/~nisse/nettle/nettle.html#Miscellaneous-functions
118 */
119 if (memeql_sec(ctxt, block, 16) == 0)
120 return 0;
121 else
122 return ptxtlen;
123 }
124 }
125
126 /* Note: we need a curve where membership checking is hard for all
127 * group elements. See also https://ia.cr/2015/247 and followups
128 */
129 void dipe_init(FILE* configfp, dipe_param_t* param) {
130 char buffer[2<<16];
131 (*param) = (dipe_param_t)malloc(sizeof(dipe_param));
132 fread(buffer, 1, 2<<16, configfp);
133
134 pairing_init_set_buf((*param)->pairing, buffer, 2<<16);
135
136 element_init_G1((*param)->g1, (*param)->pairing);
137 element_init_G2((*param)->g2, (*param)->pairing);
138 element_init_GT((*param)->gt, (*param)->pairing);
139
140 element_random((*param)->g1);
141 element_random((*param)->g2);
142 pairing_apply((*param)->gt, (*param)->g1, (*param)->g2, (*param)->pairing);
143 }
144
145 pairing_t* dipe_get_pairing(dipe_param_t param) {
146 return &(param->pairing);
147 }
148
149 void dipe_master_keygen(dipe_param_t param, size_t dimension, dipe_master_publickey_t* pk, dipe_master_secretkey_t* sk) {
150 *pk = (dipe_master_publickey_t)malloc(sizeof(dipe_master_publickey));
151 *sk = (dipe_master_secretkey_t)malloc(sizeof(dipe_master_secretkey));
152
153 (*sk)->dimension = (*pk)->dimension = dimension;
154 element_init_Zr((*pk)->aid, param->pairing);
155 element_init_Zr((*sk)->aid, param->pairing);
156 element_random((*pk)->aid);
157 element_set((*sk)->aid, (*pk)->aid);
158
159 element_init_Zr((*sk)->a, param->pairing);
160 element_init_GT((*pk)->a, param->pairing);
161 element_random((*sk)->a);
162 element_pow_zn((*pk)->a, param->gt, (*sk)->a);
163
164 (*sk)->k = (element_t*)calloc(dimension, sizeof(element_t));
165 (*pk)->k = (element_t*)calloc(dimension, sizeof(element_t));
166 for (size_t i = 0; i < dimension; ++i) {
167 element_init_Zr((*sk)->k[i], param->pairing);
168 element_init_G1((*pk)->k[i], param->pairing);
169 element_random((*sk)->k[i]);
170 element_pow_zn((*pk)->k[i], param->g1, (*sk)->k[i]);
171 }
172 }
173
174 void dipe_keygen(dipe_param_t param, dipe_master_secretkey_t msk, const char* cid, element_t* y, dipe_secretkey_t* sk) {
175 *sk = (dipe_secretkey_t)malloc(sizeof(dipe_secretkey));
176 (*sk)->dimension = msk->dimension;
177 element_init_G2((*sk)->d, param->pairing);
178 element_init_Zr((*sk)->aid, param->pairing);
179 element_set((*sk)->aid, msk->aid);
180
181 size_t hash_input_length = dipe_h_length(y[0], msk->dimension);
182 unsigned char hash_input[hash_input_length];
183 element_t h;
184 element_init_G2(h, param->pairing);
185
186 dipe_generate_h(cid, y, msk->dimension, hash_input);
187 element_from_hash(h, hash_input, hash_input_length);
188
189 element_t innerp;
190 element_t tmp;
191
192 element_init_Zr(innerp, param->pairing);
193 element_init_Zr(tmp, param->pairing);
194 element_set0(innerp);
195
196 element_from_hash(h, hash_input, hash_input_length);
197
198 for (size_t i = 0; i < msk->dimension; ++i) {
199 element_mul(tmp, y[i], msk->k[i]);
200 element_add(innerp, innerp, tmp);
201 }
202
203 element_t a2;
204 element_init_G2(a2, param->pairing);
205 element_pow_zn(h, h, innerp);
206 element_pow_zn(a2, param->g2, msk->a);
207 element_mul((*sk)->d, a2, h);
208
209 element_clear(h);
210 element_clear(innerp);
211 element_clear(tmp);
212 element_clear(a2);
213 }
214
215 void dipe_encap(dipe_param_t param, size_t mpkcount, dipe_master_publickey_t* mpk, size_t threshold, element_t* x, element_t ptxt, dipe_ctxt_t* ctxt) {
216 *ctxt = (dipe_ctxt_t)malloc(sizeof(dipe_ctxt));
217 (*ctxt)->dimension = mpk[0]->dimension;
218 (*ctxt)->sharecount = mpkcount - threshold /* TODO */;
219
220 element_t r[(*ctxt)->sharecount];
221 element_t r0;
222 element_t faid[(*ctxt)->sharecount];
223 element_t aid[mpkcount];
224 element_t s;
225
226 element_init_Zr(s, param->pairing);
227 element_random(s);
228 element_init_Zr(r0, param->pairing);
229 element_random(r0);
230
231 element_init_G1((*ctxt)->s, param->pairing);
232 element_pow_zn((*ctxt)->s, param->g1, s);
233
234 (*ctxt)->cx = (element_t*)calloc((*ctxt)->dimension, sizeof(element_t));
235 (*ctxt)->shares = (struct dipe_ctxt_share*)calloc((*ctxt)->sharecount, sizeof(struct dipe_ctxt_share));
236 for (size_t i = 0; i < (*ctxt)->sharecount; ++i) {
237 element_init_Zr((*ctxt)->shares[i].aid, param->pairing);
238 element_init_Zr(faid[i], param->pairing);
239 element_random((*ctxt)->shares[i].aid);
240 element_set(faid[i], (*ctxt)->shares[i].aid);
241
242 element_init_Zr(r[i], param->pairing);
243 element_random(r[i]);
244 }
245
246 element_t* ashares[mpkcount];
247 for (size_t i = 0; i < mpkcount; ++i) {
248 ashares[i] = &(mpk[i]->a);
249 element_init_Zr(aid[i], param->pairing);
250 element_set(aid[i], mpk[i]->aid);
251 }
252 element_t* adummyshares[(*ctxt)->sharecount];
253 for (size_t i = 0; i < (*ctxt)->sharecount; ++i) {
254 adummyshares[i] = &((*ctxt)->shares[i].c);
255 }
256 dipe_ss_share(param, mpkcount, aid, (*ctxt)->sharecount, faid, 1, ashares, &((*ctxt)->c), adummyshares);
257
258 for (size_t i = 0; i < (*ctxt)->sharecount; ++i) {
259 element_pow_zn((*ctxt)->shares[i].c, (*ctxt)->shares[i].c, s);
260 }
261 element_pow_zn((*ctxt)->c, (*ctxt)->c, s);
262 element_mul((*ctxt)->c, (*ctxt)->c, ptxt);
263
264
265 element_t* kshares[mpkcount];
266 for (size_t i = 0; i < mpkcount; ++i) {
267 kshares[i] = mpk[i]->k;
268 }
269 element_t* kdummyshares[(*ctxt)->sharecount];
270 for (size_t i = 0; i < (*ctxt)->sharecount; ++i) {
271 kdummyshares[i] = (*ctxt)->shares[i].cx = (element_t*)calloc((*ctxt)->dimension, sizeof(element_t));
272 }
273
274 element_t tmp;
275 for (size_t i = 0; i < (*ctxt)->sharecount; ++i) {
276 element_init_G1((*ctxt)->cx[i], param->pairing);
277 }
278 element_init_G1(tmp, param->pairing);
279 dipe_ss_share(param, mpkcount, aid, (*ctxt)->sharecount, faid, (*ctxt)->dimension, kshares, (*ctxt)->cx, kdummyshares);
280
281 for (size_t i = 0; i < (*ctxt)->sharecount; ++i) {
282 for (size_t j = 0; j < (*ctxt)->dimension; ++j) {
283 element_pow_zn((*ctxt)->shares[i].cx[j], (*ctxt)->shares[i].cx[j], s);
284 element_pow_zn(tmp, param->g1, x[j]);
285 element_pow_zn(tmp, tmp, r[i]);
286 element_mul((*ctxt)->shares[i].cx[j], (*ctxt)->shares[i].cx[j], tmp);
287 }
288 }
289 for (size_t j = 0; j < (*ctxt)->dimension; ++j) {
290 element_pow_zn((*ctxt)->cx[j], (*ctxt)->cx[j], s);
291 element_pow_zn(tmp, param->g1, x[j]);
292 element_pow_zn(tmp, tmp, r0);
293 element_mul((*ctxt)->cx[j], (*ctxt)->cx[j], tmp);
294 }
295
296
297 for (size_t i = 0; i < (*ctxt)->sharecount; ++i) {
298 element_clear(r[i]);
299 element_clear(faid[i]);
300 }
301 for (size_t i = 0; i < mpkcount; ++i) {
302 element_clear(aid[i]);
303 }
304 element_clear(r0);
305 element_clear(s);
306 element_clear(tmp);
307 }
308
309
310 void dipe_decap(dipe_param_t param, size_t skcount, dipe_secretkey_t* sk, const char* cid, element_t* y, dipe_ctxt_t ctxt, element_t ptxt) {
311 size_t hash_input_length = dipe_h_length(y[0], sk[0]->dimension);
312 unsigned char hash_input[hash_input_length];
313 element_t h;
314 element_init_G2(h, param->pairing);
315
316 dipe_generate_h(cid, y, sk[0]->dimension, hash_input);
317 element_from_hash(h, hash_input, hash_input_length);
318
319 element_t tmp;
320 element_t innerp;
321 element_t hy;
322 element_init_GT(tmp, param->pairing);
323 element_init_GT(innerp, param->pairing);
324 element_init_G2(hy, param->pairing);
325
326 element_t aid[skcount + ctxt->sharecount];
327 element_t* beta[skcount + ctxt->sharecount];
328 for (size_t i = 0; i < skcount; ++i) {
329 beta[i] = (element_t*)calloc(1, sizeof(element_t));
330 element_init_GT(*(beta[i]), param->pairing);
331 element_init_Zr(aid[i], param->pairing);
332 element_set(aid[i], sk[i]->aid);
333 pairing_apply(*(beta[i]), ctxt->s, sk[i]->d, param->pairing);
334 }
335 for (size_t i = 0; i < ctxt->sharecount; ++i) {
336 beta[skcount+i] = (element_t*)calloc(1, sizeof(element_t));
337 element_init_GT(*(beta[skcount+i]), param->pairing);
338 element_init_Zr(aid[skcount+i], param->pairing);
339 element_set(aid[skcount+i], ctxt->shares[i].aid);
340
341 element_set1(innerp);
342 for (size_t j = 0; j < sk[0]->dimension; ++j) {
343 element_pow_zn(hy, h, y[j]);
344 element_printf("%B %B\n", ctxt->shares[i].cx[j], hy);
345 pairing_apply(tmp, ctxt->shares[i].cx[j], hy, param->pairing);
346 element_mul(innerp, innerp, tmp);
347 }
348 element_mul(*(beta[skcount+i]), ctxt->shares[i].c, innerp);
349 }
350
351 element_t recover[1];
352 dipe_ss_recover(param, skcount + ctxt->sharecount, aid, 1, beta, recover);
353 element_set(ptxt, recover[0]);
354 element_clear(recover[0]);
355
356 element_set1(innerp);
357 for (size_t i = 0; i < sk[0]->dimension; ++i) {
358 element_pow_zn(hy, h, y[i]);
359 pairing_apply(tmp, ctxt->cx[i], hy, param->pairing);
360 element_mul(innerp, innerp, tmp);
361 }
362
363 element_invert(ptxt, ptxt);
364 element_mul(ptxt, ptxt, ctxt->c);
365 element_mul(ptxt, ptxt, innerp); /* innerp */
366
367 for (size_t i = 0; i < skcount + ctxt->sharecount; ++i) {
368 element_clear(aid[i]);
369 element_clear(*(beta[i]));
370 free(beta[i]);
371 }
372
373 element_clear(h);
374 element_clear(tmp);
375 element_clear(innerp);
376 element_clear(hy);
377 }
378
379 void dipe_encrypt(dipe_param_t param, size_t mpkcount, dipe_master_publickey_t* mpk, size_t threshold, element_t* x, size_t ptxt_len, char* ptxt, size_t ctxt_len, char* ctxt) {
380 element_t key;
381 uint8_t aes[32];
382 dipe_ctxt_t cap;
383 size_t cap_len;
384
385 element_init_GT(key, param->pairing);
386 element_random(key);
387 dipe_generate_aeskey(key, aes);
388 dipe_encap(param, mpkcount, mpk, threshold, x, key, &cap);
389 cap_len = dipe_serialize_ctxt(param, cap, (uint8_t*)ctxt);
390 ctxt += cap_len; ctxt_len -= cap_len;
391
392 dipe_aes_encrypt(aes, aes+16, ptxt_len, (uint8_t*)ptxt, ctxt_len, (uint8_t*)ctxt);
393
394 dipe_free_ctxt(cap);
395 element_clear(key);
396 }
397
398 size_t dipe_decrypt(dipe_param_t param, size_t skcount, dipe_secretkey_t* sk, const char* cid, element_t* y, size_t ctxt_len, char* ctxt, char* ptxt) {
399 dipe_ctxt_t cap;
400 uint8_t aes[32];
401 element_t key;
402 size_t cap_len;
403
404 element_init_GT(key, param->pairing);
405 cap_len = dipe_deserialize_ctxt(param, sk[0]->dimension, 0, &cap, (uint8_t*)ctxt);
406 ctxt += cap_len;
407 ctxt_len -= cap_len;
408 dipe_decap(param, skcount, sk, cid, y, cap, key);
409 dipe_generate_aeskey(key, aes);
410
411 dipe_free_ctxt(cap);
412 element_clear(key);
413
414 return dipe_aes_decrypt(aes, aes+16, ctxt_len, (uint8_t*)ctxt, (uint8_t*)ptxt);
415 }
416
417 /* Note: we're generating random-looking bytes here. Therefore we
418 * can't encode the dimension of the predicate vector (supposed to be
419 * set as system parameter) or information about the secret sharing
420 * (needs to be retrieved by some sort of trial decryption).
421 */
422 size_t dipe_serialize_ctxt(__attribute__((unused)) dipe_param_t param, dipe_ctxt_t ctxt, uint8_t* buffer) {
423 size_t bytes_written = 0;
424 element_to_bytes_compressed(buffer, ctxt->s);
425 buffer += element_length_in_bytes_compressed(ctxt->s);
426 bytes_written += element_length_in_bytes_compressed(ctxt->s);
427
428 for (size_t i = 0; i < ctxt->dimension; ++i) {
429 element_to_bytes_compressed(buffer, ctxt->cx[i]);
430 buffer += element_length_in_bytes_compressed(ctxt->cx[i]);
431 bytes_written += element_length_in_bytes_compressed(ctxt->cx[i]);
432 }
433
434 element_to_bytes(buffer, ctxt->c);
435 buffer += element_length_in_bytes(ctxt->c);
436 bytes_written += element_length_in_bytes(ctxt->c);
437
438 for (size_t j = 0; j < ctxt->sharecount; ++j) {
439 element_to_bytes(buffer, ctxt->shares[j].aid);
440 buffer += element_length_in_bytes(ctxt->shares[j].aid);
441 bytes_written += element_length_in_bytes(ctxt->shares[j].aid);
442
443 for (size_t i = 0; i < ctxt->dimension; ++i) {
444 element_to_bytes_compressed(buffer, ctxt->shares[j].cx[i]);
445 buffer += element_length_in_bytes_compressed(ctxt->shares[j].cx[i]);
446 bytes_written += element_length_in_bytes_compressed(ctxt->shares[j].cx[i]);
447 }
448
449 element_to_bytes(buffer, ctxt->shares[j].c);
450 buffer += element_length_in_bytes(ctxt->shares[j].c);
451 bytes_written += element_length_in_bytes(ctxt->shares[j].c);
452 }
453
454 return bytes_written;
455 }
456
457 size_t dipe_deserialize_ctxt(dipe_param_t param, size_t dimension, size_t shares, dipe_ctxt_t* ctxt, uint8_t* buffer) {
458 size_t bytes_read = 0;
459 *ctxt = (dipe_ctxt_t)malloc(sizeof(dipe_ctxt));
460 (*ctxt)->dimension = dimension;
461 (*ctxt)->sharecount = shares;
462
463 element_init_G1((*ctxt)->s, param->pairing);
464 element_from_bytes_compressed((*ctxt)->s, buffer);
465 buffer += element_length_in_bytes_compressed((*ctxt)->s);
466 bytes_read += element_length_in_bytes_compressed((*ctxt)->s);
467
468 (*ctxt)->cx = (element_t*)calloc(dimension, sizeof(element_t));
469 for (size_t i = 0; i < dimension; ++i) {
470 element_init_G1((*ctxt)->cx[i], param->pairing);
471 element_from_bytes_compressed((*ctxt)->cx[i], buffer);
472 buffer += element_length_in_bytes_compressed((*ctxt)->cx[i]);
473 bytes_read += element_length_in_bytes_compressed((*ctxt)->cx[i]);
474 }
475
476 element_init_GT((*ctxt)->c, param->pairing);
477 element_from_bytes((*ctxt)->c, buffer);
478 buffer += element_length_in_bytes((*ctxt)->c);
479 bytes_read += element_length_in_bytes((*ctxt)->c);
480
481
482 (*ctxt)->shares = (struct dipe_ctxt_share*)calloc(shares, sizeof(struct dipe_ctxt_share));
483 for (size_t j = 0; j < shares; ++j) {
484 element_init_Zr((*ctxt)->shares[j].aid, param->pairing);
485 element_from_bytes((*ctxt)->shares[j].aid, buffer);
486 buffer += element_length_in_bytes((*ctxt)->shares[j].aid);
487 bytes_read += element_length_in_bytes((*ctxt)->shares[j].aid);
488
489 }
490
491 return bytes_read;
492 }
493
494 size_t dipe_ciphertext_overhead(dipe_param_t param, size_t dimension, size_t shares) {
495 size_t overhead = 16 + 4 /* IV + Tag + Size */;
496 element_t t;
497
498 /* s */
499 element_init_G1(t, param->pairing);
500 overhead += element_length_in_bytes_compressed(t);
501
502 /* cx */
503 overhead += (1+shares) * dimension * element_length_in_bytes_compressed(t);
504 element_clear(t);
505
506 /* c */
507 element_init_GT(t, param->pairing);
508 overhead += (1+shares) * element_length_in_bytes(t);
509 element_clear(t);
510
511 return overhead;
512 }
513
514 void dipe_free_param(dipe_param_t param) {
515 element_clear(param->g1);
516 element_clear(param->g2);
517 element_clear(param->gt);
518 pairing_clear(param->pairing);
519 free(param);
520 }
521
522 void dipe_free_master_secretkey(dipe_master_secretkey_t sk) {
523 for (size_t i = 0; i < sk->dimension; ++i) {
524 element_clear(sk->k[i]);
525 }
526 element_clear(sk->a);
527 free(sk->k);
528 element_clear(sk->aid);
529 free(sk);
530 }
531
532 void dipe_free_master_publickey(dipe_master_publickey_t pk) {
533 for (size_t i = 0; i < pk->dimension; ++i) {
534 element_clear(pk->k[i]);
535 }
536 element_clear(pk->a);
537 free(pk->k);
538 element_clear(pk->aid);
539 free(pk);
540 }
541
542 void dipe_free_secretkey(dipe_secretkey_t sk) {
543 element_clear(sk->d);
544 element_clear(sk->aid);
545 free(sk);
546 }
547
548 void dipe_free_ctxt(dipe_ctxt_t ctxt) {
549 for (size_t j = 0; j < ctxt->dimension; ++j) {
550 element_clear(ctxt->cx[j]);
551 }
552 element_clear(ctxt->c);
553 free(ctxt->cx);
554
555 for (size_t i = 0; i < ctxt->sharecount; ++i) {
556 for (size_t j = 0; j < ctxt->dimension; ++j) {
557 element_clear(ctxt->shares[i].cx[j]);
558 }
559 element_clear(ctxt->shares[i].c);
560 free(ctxt->shares[i].cx);
561 }
562 free(ctxt->shares);
563
564 element_clear(ctxt->s);
565 free(ctxt);
566 }