]> git.siccegge.de Git - software/DIPE.git/blobdiff - src/DIPE.cxx
benchmarks\~
[software/DIPE.git] / src / DIPE.cxx
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..c593ae0937136f261e2f8b585e7ae6a749f28de6 100644 (file)
@@ -0,0 +1,580 @@
+#include "DIPE.h"
+#include "DIPE_Internal.h"
+
+#include <string.h>
+#include <nettle/hkdf.h>
+#include <nettle/hmac.h>
+#include <sys/random.h>
+#include <nettle/gcm.h>
+#include <nettle/memops.h>
+#include <arpa/inet.h>
+#include <algorithm>
+#include <errno.h>
+
+using std::min;
+using std::max;
+
+
+
+namespace {
+       size_t dipe_h_length(element_t elem, size_t dimension) {
+               return 16 /*cid*/ + dimension * element_length_in_bytes(elem);
+       }
+
+       void dipe_generate_h(const char* cid, element_t* y, size_t dimension, unsigned char* result) {
+               memcpy(result, cid, 16);
+               unsigned char* next_element = result+16;
+               for (size_t i = 0; i < dimension; ++i) {
+                       element_to_bytes(next_element, y[i]);
+                       next_element += element_length_in_bytes(y[0]);
+               }
+       }
+
+       void dipe_generate_aeskey(element_t encapkey, uint8_t* aeskey) {
+               struct hmac_sha256_ctx ctx;
+               uint8_t salt[SHA256_DIGEST_SIZE];
+               memset(salt, 0, SHA256_DIGEST_SIZE);
+               size_t elen = element_length_in_bytes(encapkey);
+               uint8_t coded[elen];
+               element_to_bytes(coded, encapkey);
+
+               hmac_sha256_set_key(&ctx, SHA256_DIGEST_SIZE, salt);
+               hkdf_extract(&ctx,
+                                        (nettle_hash_update_func *)hmac_sha256_update,
+                                        (nettle_hash_digest_func *)hmac_sha256_digest,
+                                        SHA256_DIGEST_SIZE,
+                                        elen, coded,
+                                        aeskey);
+       }
+
+       /* Data format is iv | enc(4 byte len | ptxt | 0 padding) | tag
+        */
+       int dipe_aes_encrypt(uint8_t* key, uint8_t* iv, size_t ptxt_len, uint8_t* ptxt, size_t ctxt_len, uint8_t* ctxt) {
+               struct gcm_aes128_ctx ctx;
+               uint8_t block[16];
+               uint32_t coded_ptxtlen;
+
+               ctxt_len -= 16; /* Tag */
+               if (ctxt_len < ptxt_len + 4) return 0;
+
+               memset(block, 0, 16);
+               gcm_aes128_set_key(&ctx, key);
+               gcm_aes128_set_iv(&ctx, 12, iv);
+
+               /* First Block */
+               coded_ptxtlen = htonl(ptxt_len);
+               memcpy(block, &coded_ptxtlen, 4);
+               memcpy(block+4, ptxt, min((size_t)12, ptxt_len));
+               ptxt_len -= min((size_t)12, ptxt_len);
+               ptxt += 12;
+
+               while (ctxt_len >= 16) {
+                       gcm_aes128_encrypt(&ctx, 16, ctxt, block);
+                       memset(block, 0, 16);
+                       ctxt_len -= 16;
+                       ctxt += 16;
+
+                       if (ptxt_len > 0) {
+                               memcpy(block, ptxt, min((size_t)16, ptxt_len));
+                               ptxt += 16;
+                               ptxt_len -= min((size_t)16, ptxt_len);
+                       }
+               }
+
+               if (ctxt_len > 0) {
+                       gcm_aes128_encrypt(&ctx, ctxt_len, ctxt, block);
+                       ctxt += ctxt_len;
+               }
+
+               gcm_aes128_digest(&ctx, 16, ctxt);
+               return 0;
+       }
+
+       int dipe_aes_decrypt(uint8_t* key, uint8_t* iv, size_t len, uint8_t* ctxt, uint8_t* ptxt) {
+               struct gcm_aes128_ctx ctx;
+               uint8_t block[16];
+
+               gcm_aes128_set_key(&ctx, key);
+               gcm_aes128_set_iv(&ctx, 12, iv);
+               len -= 16; /* GCM tag */
+
+
+               gcm_aes128_decrypt(&ctx, min((size_t)16, len), block, ctxt);
+               uint32_t ptxtlen = 0;
+               memcpy(&ptxtlen, block, 4);
+               memcpy(ptxt, block+4, min((size_t)12, len-4));
+               ptxtlen = ntohl(ptxtlen);
+               ctxt += min((size_t)16, len); len -= min((size_t)16, len);
+               ptxt += 12;
+
+               if (len > 0) {
+                       gcm_aes128_decrypt(&ctx, len, ptxt, ctxt);
+                       ctxt += len;
+               }
+               gcm_aes128_digest(&ctx, 16, block);
+
+               /* error case is with return code 0, see manual
+                * https://www.lysator.liu.se/~nisse/nettle/nettle.html#Miscellaneous-functions
+                */
+               if (memeql_sec(ctxt, block, 16) == 0)
+                       return 0;
+               else
+                       return ptxtlen;
+       }
+}
+
+/* Note: we need a curve where membership checking is hard for all
+ * group elements. See also https://ia.cr/2015/247 and followups
+ */
+void dipe_init(FILE* configfp, dipe_param_t* param) {
+       char buffer[2<<16];
+       (*param) = (dipe_param_t)malloc(sizeof(dipe_param));
+       fread(buffer, 1, 2<<16, configfp);
+
+       pairing_init_set_buf((*param)->pairing, buffer, 2<<16);
+
+       element_init_G1((*param)->g1, (*param)->pairing);
+       element_init_G2((*param)->g2, (*param)->pairing);
+       element_init_GT((*param)->gt, (*param)->pairing);
+
+       element_random((*param)->g1);
+       element_random((*param)->g2);
+       pairing_apply((*param)->gt, (*param)->g1, (*param)->g2, (*param)->pairing);
+}
+
+pairing_t* dipe_get_pairing(dipe_param_t param) {
+       return &(param->pairing);
+}
+
+void dipe_master_keygen(dipe_param_t param, size_t dimension, dipe_master_publickey_t* pk, dipe_master_secretkey_t* sk) {
+       *pk = (dipe_master_publickey_t)malloc(sizeof(dipe_master_publickey));
+       *sk = (dipe_master_secretkey_t)malloc(sizeof(dipe_master_secretkey));
+
+       (*sk)->dimension = (*pk)->dimension = dimension;
+       element_init_Zr((*pk)->aid, param->pairing);
+       element_init_Zr((*sk)->aid, param->pairing);
+       element_random((*pk)->aid);
+       element_set((*sk)->aid, (*pk)->aid);
+
+       element_init_Zr((*sk)->a, param->pairing);
+       element_init_GT((*pk)->a, param->pairing);
+       element_random((*sk)->a);
+       element_pow_zn((*pk)->a, param->gt, (*sk)->a);
+
+       (*sk)->k = (element_t*)calloc(dimension, sizeof(element_t));
+       (*pk)->k = (element_t*)calloc(dimension, sizeof(element_t));
+       for (size_t i = 0; i < dimension; ++i) {
+               element_init_Zr((*sk)->k[i], param->pairing);
+               element_init_G1((*pk)->k[i], param->pairing);
+               element_random((*sk)->k[i]);
+               element_pow_zn((*pk)->k[i], param->g1, (*sk)->k[i]);
+       }
+}
+
+void dipe_keygen(dipe_param_t param, dipe_master_secretkey_t msk, const char* cid, element_t* y, dipe_secretkey_t* sk) {
+       *sk = (dipe_secretkey_t)malloc(sizeof(dipe_secretkey));
+       (*sk)->dimension = msk->dimension;
+       element_init_G2((*sk)->d, param->pairing);
+       element_init_Zr((*sk)->aid, param->pairing);
+       element_set((*sk)->aid, msk->aid);
+
+       size_t hash_input_length = dipe_h_length(y[0], msk->dimension);
+       unsigned char hash_input[hash_input_length];
+       element_t h;
+       element_init_G2(h, param->pairing);
+
+       dipe_generate_h(cid, y, msk->dimension, hash_input);
+       element_from_hash(h, hash_input, hash_input_length);
+
+       element_t innerp;
+       element_t tmp;
+
+       element_init_Zr(innerp, param->pairing);
+       element_init_Zr(tmp, param->pairing);
+       element_set0(innerp);
+
+       element_from_hash(h, hash_input, hash_input_length);
+
+       for (size_t i = 0; i < msk->dimension; ++i) {
+               element_mul(tmp, y[i], msk->k[i]);
+               element_add(innerp, innerp, tmp);
+       }
+
+       element_t a2;
+       element_init_G2(a2, param->pairing);
+       element_pow_zn(h, h, innerp);
+       element_pow_zn(a2, param->g2, msk->a);
+       element_mul((*sk)->d, a2, h);
+
+       element_clear(h);
+       element_clear(innerp);
+       element_clear(tmp);
+       element_clear(a2);
+}
+
+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) {
+       *ctxt = (dipe_ctxt_t)malloc(sizeof(dipe_ctxt));
+       (*ctxt)->dimension = mpk[0]->dimension;
+       (*ctxt)->sharecount = mpkcount - threshold /*  TODO */;
+
+       element_t r[(*ctxt)->sharecount];
+       element_t r0;
+       element_t faid[(*ctxt)->sharecount];
+       element_t aid[mpkcount];
+       element_t s;
+
+       element_init_Zr(s, param->pairing);
+       element_random(s);
+       element_init_Zr(r0, param->pairing);
+       element_random(r0);
+
+       element_init_G1((*ctxt)->s, param->pairing);
+       element_pow_zn((*ctxt)->s, param->g1, s);
+
+       (*ctxt)->cx = (element_t*)calloc((*ctxt)->dimension, sizeof(element_t));
+       (*ctxt)->shares = (struct dipe_ctxt_share*)calloc((*ctxt)->sharecount, sizeof(struct dipe_ctxt_share));
+       for (size_t i = 0; i < (*ctxt)->sharecount; ++i) {
+               element_init_Zr((*ctxt)->shares[i].aid, param->pairing);
+               element_init_Zr(faid[i], param->pairing);
+               element_random((*ctxt)->shares[i].aid);
+               element_set(faid[i], (*ctxt)->shares[i].aid);
+
+               element_init_Zr(r[i], param->pairing);
+               element_random(r[i]);
+       }
+
+       element_t* ashares[mpkcount];
+       for (size_t i = 0; i < mpkcount; ++i) {
+               ashares[i] = &(mpk[i]->a);
+               element_init_Zr(aid[i], param->pairing);
+               element_set(aid[i], mpk[i]->aid);
+       }
+       element_t* adummyshares[(*ctxt)->sharecount];
+       for (size_t i  = 0; i < (*ctxt)->sharecount; ++i) {
+               adummyshares[i] = &((*ctxt)->shares[i].c);
+       }
+       dipe_ss_share(param, mpkcount, aid, (*ctxt)->sharecount, faid, 1, ashares, &((*ctxt)->c), adummyshares);
+
+       for (size_t i  = 0; i < (*ctxt)->sharecount; ++i) {
+               element_pow_zn((*ctxt)->shares[i].c, (*ctxt)->shares[i].c, s);
+       }
+       element_pow_zn((*ctxt)->c, (*ctxt)->c, s);
+       element_mul((*ctxt)->c, (*ctxt)->c, ptxt);
+
+
+       element_t* kshares[mpkcount];
+       for (size_t i = 0; i < mpkcount; ++i) {
+               kshares[i] = mpk[i]->k;
+       }
+       element_t* kdummyshares[(*ctxt)->sharecount];
+       for (size_t i  = 0; i < (*ctxt)->sharecount; ++i) {
+               kdummyshares[i] = (*ctxt)->shares[i].cx = (element_t*)calloc((*ctxt)->dimension, sizeof(element_t));
+       }
+
+       element_t tmp;
+       element_init_G1(tmp, param->pairing);
+       dipe_ss_share(param, mpkcount, aid, (*ctxt)->sharecount, faid, (*ctxt)->dimension, kshares, (*ctxt)->cx, kdummyshares);
+
+       for (size_t i = 0; i < (*ctxt)->sharecount; ++i) {
+               for (size_t j = 0; j < (*ctxt)->dimension; ++j) {
+                       element_pow_zn((*ctxt)->shares[i].cx[j], (*ctxt)->shares[i].cx[j], s);
+                       element_pow_zn(tmp, param->g1, x[j]);
+                       element_pow_zn(tmp, tmp, r[i]);
+                       element_mul((*ctxt)->shares[i].cx[j], (*ctxt)->shares[i].cx[j], tmp);
+               }
+       }
+       for (size_t j = 0; j < (*ctxt)->dimension; ++j) {
+               element_pow_zn((*ctxt)->cx[j], (*ctxt)->cx[j], s);
+               element_pow_zn(tmp, param->g1, x[j]);
+               element_pow_zn(tmp, tmp, r0);
+               element_mul((*ctxt)->cx[j], (*ctxt)->cx[j], tmp);
+       }
+
+
+       for (size_t i = 0; i < (*ctxt)->sharecount; ++i) {
+               element_clear(r[i]);
+               element_clear(faid[i]);
+       }
+       for (size_t i = 0; i < mpkcount; ++i) {
+               element_clear(aid[i]);
+       }
+       element_clear(r0);
+       element_clear(s);
+       element_clear(tmp);
+}
+
+
+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) {
+       size_t hash_input_length = dipe_h_length(y[0], sk[0]->dimension);
+       unsigned char hash_input[hash_input_length];
+       element_t h;
+       element_init_G2(h, param->pairing);
+
+       dipe_generate_h(cid, y, sk[0]->dimension, hash_input);
+       element_from_hash(h, hash_input, hash_input_length);
+
+       element_t tmp;
+       element_t innerp;
+       element_t hy;
+       element_init_GT(tmp, param->pairing);
+       element_init_GT(innerp, param->pairing);
+       element_init_G2(hy, param->pairing);
+
+       element_t aid[skcount + ctxt->sharecount];
+       element_t* beta[skcount + ctxt->sharecount];
+       for (size_t i = 0; i < skcount; ++i) {
+               beta[i] = (element_t*)calloc(1, sizeof(element_t));
+               element_init_GT(*(beta[i]), param->pairing);
+               element_init_Zr(aid[i], param->pairing);
+               element_set(aid[i], sk[i]->aid);
+               pairing_apply(*(beta[i]), ctxt->s, sk[i]->d, param->pairing);
+       }
+       for (size_t i = 0; i < ctxt->sharecount; ++i) {
+               beta[skcount+i] = (element_t*)calloc(1, sizeof(element_t));
+               element_init_GT(*(beta[skcount+i]), param->pairing);
+               element_init_Zr(aid[skcount+i], param->pairing);
+               element_set(aid[skcount+i], ctxt->shares[i].aid);
+
+               element_set1(innerp);
+               for (size_t j = 0; j < sk[0]->dimension; ++j) {
+                       element_pow_zn(hy, h, y[j]);
+                       pairing_apply(tmp, ctxt->shares[i].cx[j], hy, param->pairing);
+                       element_mul(innerp, innerp, tmp);
+               }
+               element_mul(*(beta[skcount+i]), ctxt->shares[i].c, innerp);
+       }
+
+       element_t recover[1];
+       dipe_ss_recover(param, skcount + ctxt->sharecount, aid, 1, beta, recover);
+       element_set(ptxt, recover[0]);
+       element_clear(recover[0]);
+
+       element_set1(innerp);
+       for (size_t i = 0; i < sk[0]->dimension; ++i) {
+               element_pow_zn(hy, h, y[i]);
+               pairing_apply(tmp, ctxt->cx[i], hy, param->pairing);
+               element_mul(innerp, innerp, tmp);
+       }
+
+       element_invert(ptxt, ptxt);
+       element_mul(ptxt, ptxt, ctxt->c);
+       element_mul(ptxt, ptxt, innerp); /* innerp */
+
+       for (size_t i = 0; i < skcount + ctxt->sharecount; ++i) {
+               element_clear(aid[i]);
+               element_clear(*(beta[i]));
+               free(beta[i]);
+       }
+
+       element_clear(h);
+       element_clear(tmp);
+       element_clear(innerp);
+       element_clear(hy);
+}
+
+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) {
+       element_t key;
+       uint8_t aes[32];
+       dipe_ctxt_t cap;
+       size_t cap_len;
+
+       element_init_GT(key, param->pairing);
+       element_random(key);
+       dipe_generate_aeskey(key, aes);
+       dipe_encap(param, mpkcount, mpk, threshold, x, key, &cap);
+       cap_len = dipe_serialize_ctxt(param, cap, (uint8_t*)ctxt);
+       ctxt += cap_len; ctxt_len -= cap_len;
+
+       dipe_aes_encrypt(aes, aes+16, ptxt_len, (uint8_t*)ptxt, ctxt_len, (uint8_t*)ctxt);
+
+       dipe_free_ctxt(cap);
+       element_clear(key);
+}
+
+size_t dipe_decrypt(dipe_param_t param, size_t skcount, dipe_secretkey_t* sk, size_t sharecount, const char* cid, element_t* y, size_t ctxt_len, char* ctxt, char* ptxt) {
+       dipe_ctxt_t cap;
+       uint8_t aes[32];
+       element_t key;
+       size_t cap_len;
+
+       element_init_GT(key, param->pairing);
+       cap_len = dipe_deserialize_ctxt(param, sk[0]->dimension, sharecount, &cap, (uint8_t*)ctxt);
+       ctxt += cap_len;
+       ctxt_len -= cap_len;
+       dipe_decap(param, skcount, sk, cid, y, cap, key);
+       dipe_generate_aeskey(key, aes);
+
+       dipe_free_ctxt(cap);
+       element_clear(key);
+
+       return dipe_aes_decrypt(aes, aes+16, ctxt_len, (uint8_t*)ctxt, (uint8_t*)ptxt);
+}
+
+/* Note: we're generating random-looking bytes here. Therefore we
+ * can't encode the dimension of the predicate vector (supposed to be
+ * set as system parameter) or information about the secret sharing
+ * (needs to be retrieved by some sort of trial decryption).
+ */
+size_t dipe_serialize_ctxt(__attribute__((unused)) dipe_param_t param, dipe_ctxt_t ctxt, uint8_t* buffer) {
+       size_t bytes_written = 0;
+       element_to_bytes_compressed(buffer, ctxt->s);
+       buffer += element_length_in_bytes_compressed(ctxt->s);
+       bytes_written += element_length_in_bytes_compressed(ctxt->s);
+
+       for (size_t i = 0; i < ctxt->dimension; ++i) {
+               element_to_bytes_compressed(buffer, ctxt->cx[i]);
+               buffer += element_length_in_bytes_compressed(ctxt->cx[i]);
+               bytes_written += element_length_in_bytes_compressed(ctxt->cx[i]);
+       }
+
+       element_to_bytes(buffer, ctxt->c);
+       buffer += element_length_in_bytes(ctxt->c);
+       bytes_written += element_length_in_bytes(ctxt->c);
+
+       for (size_t j = 0; j < ctxt->sharecount; ++j) {
+               element_to_bytes(buffer, ctxt->shares[j].aid);
+               buffer += element_length_in_bytes(ctxt->shares[j].aid);
+               bytes_written += element_length_in_bytes(ctxt->shares[j].aid);
+
+               for (size_t i = 0; i < ctxt->dimension; ++i) {
+                       element_to_bytes_compressed(buffer, ctxt->shares[j].cx[i]);
+                       buffer += element_length_in_bytes_compressed(ctxt->shares[j].cx[i]);
+                       bytes_written += element_length_in_bytes_compressed(ctxt->shares[j].cx[i]);
+               }
+
+               element_to_bytes(buffer, ctxt->shares[j].c);
+               buffer += element_length_in_bytes(ctxt->shares[j].c);
+               bytes_written += element_length_in_bytes(ctxt->shares[j].c);
+       }
+
+       return bytes_written;
+}
+
+size_t dipe_deserialize_ctxt(dipe_param_t param, size_t dimension, size_t shares, dipe_ctxt_t* ctxt, uint8_t* buffer) {
+       size_t bytes_read = 0;
+       *ctxt = (dipe_ctxt_t)malloc(sizeof(dipe_ctxt));
+       (*ctxt)->dimension = dimension;
+       (*ctxt)->sharecount = shares;
+
+       element_init_G1((*ctxt)->s, param->pairing);
+       element_from_bytes_compressed((*ctxt)->s, buffer);
+       buffer += element_length_in_bytes_compressed((*ctxt)->s);
+       bytes_read += element_length_in_bytes_compressed((*ctxt)->s);
+
+       (*ctxt)->cx = (element_t*)calloc(dimension, sizeof(element_t));
+       for (size_t i = 0; i < dimension; ++i) {
+               element_init_G1((*ctxt)->cx[i], param->pairing);
+               element_from_bytes_compressed((*ctxt)->cx[i], buffer);
+               buffer += element_length_in_bytes_compressed((*ctxt)->cx[i]);
+               bytes_read += element_length_in_bytes_compressed((*ctxt)->cx[i]);
+       }
+
+       element_init_GT((*ctxt)->c, param->pairing);
+       element_from_bytes((*ctxt)->c, buffer);
+       buffer += element_length_in_bytes((*ctxt)->c);
+       bytes_read += element_length_in_bytes((*ctxt)->c);
+
+
+       (*ctxt)->shares = (struct dipe_ctxt_share*)calloc(shares, sizeof(struct dipe_ctxt_share));
+       for (size_t j = 0; j < shares; ++j) {
+               element_init_Zr((*ctxt)->shares[j].aid, param->pairing);
+               element_from_bytes((*ctxt)->shares[j].aid, buffer);
+               buffer += element_length_in_bytes((*ctxt)->shares[j].aid);
+               bytes_read += element_length_in_bytes((*ctxt)->shares[j].aid);
+
+               (*ctxt)->shares[j].cx = (element_t*)calloc(dimension, sizeof(element_t));
+               for (size_t i = 0; i < dimension; ++i) {
+                       element_init_G1((*ctxt)->shares[j].cx[i], param->pairing);
+                       element_from_bytes_compressed((*ctxt)->shares[j].cx[i], buffer);
+                       buffer += element_length_in_bytes_compressed((*ctxt)->shares[j].cx[i]);
+                       bytes_read += element_length_in_bytes_compressed((*ctxt)->shares[j].cx[i]);
+               }
+
+               element_init_GT((*ctxt)->shares[j].c, param->pairing);
+               element_from_bytes((*ctxt)->shares[j].c, buffer);
+               buffer += element_length_in_bytes((*ctxt)->shares[j].c);
+               bytes_read += element_length_in_bytes((*ctxt)->shares[j].c);
+       }
+
+       return bytes_read;
+}
+
+size_t dipe_ciphertext_overhead(dipe_param_t param, size_t dimension, size_t shares) {
+       size_t overhead = 16 + 4 /* IV + Tag + Size */;
+       element_t t;
+
+       /* s */
+       element_init_G1(t, param->pairing);
+       overhead += element_length_in_bytes_compressed(t);
+
+       /* cx */
+       overhead += (1+shares) * dimension * element_length_in_bytes_compressed(t);
+       element_clear(t);
+
+       /* c */
+       element_init_GT(t, param->pairing);
+       overhead += (1+shares) * element_length_in_bytes(t);
+       element_clear(t);
+
+       /* aid */
+       element_init_Zr(t, param->pairing);
+       overhead += shares * element_length_in_bytes(t);
+       element_clear(t);
+
+       return overhead;
+}
+
+void dipe_free_param(dipe_param_t param) {
+       element_clear(param->g1);
+       element_clear(param->g2);
+       element_clear(param->gt);
+       pairing_clear(param->pairing);
+       free(param);
+}
+
+void dipe_free_master_secretkey(dipe_master_secretkey_t sk) {
+       for (size_t i = 0; i < sk->dimension; ++i) {
+               element_clear(sk->k[i]);
+       }
+       element_clear(sk->a);
+       free(sk->k);
+       element_clear(sk->aid);
+       free(sk);
+}
+
+void dipe_free_master_publickey(dipe_master_publickey_t pk) {
+       for (size_t i = 0; i < pk->dimension; ++i) {
+               element_clear(pk->k[i]);
+       }
+       element_clear(pk->a);
+       free(pk->k);
+       element_clear(pk->aid);
+       free(pk);
+}
+
+void dipe_free_secretkey(dipe_secretkey_t sk) {
+       element_clear(sk->d);
+       element_clear(sk->aid);
+       free(sk);
+}
+
+void dipe_free_ctxt(dipe_ctxt_t ctxt) {
+       for (size_t j = 0; j < ctxt->dimension; ++j) {
+               element_clear(ctxt->cx[j]);
+       }
+       element_clear(ctxt->c);
+       free(ctxt->cx);
+
+       for (size_t i = 0; i < ctxt->sharecount; ++i) {
+               for (size_t j = 0; j < ctxt->dimension; ++j) {
+                       element_clear(ctxt->shares[i].cx[j]);
+               }
+               element_clear(ctxt->shares[i].c);
+               element_clear(ctxt->shares[i].aid);
+               free(ctxt->shares[i].cx);
+       }
+       free(ctxt->shares);
+
+       element_clear(ctxt->s);
+       free(ctxt);
+}