+#include "DIPE.h"
+#include <string.h>
+
+struct dipe_param {
+ pairing_t pairing;
+ element_t g1;
+ element_t g2;
+ element_t gt;
+};
+
+struct dipe_master_publickey {
+ size_t dimension;
+ element_t a;
+ element_t* k;
+};
+
+struct dipe_master_secretkey {
+ size_t dimension;
+ element_t a;
+ element_t* k;
+};
+
+struct dipe_secretkey {
+ size_t dimension;
+ element_t d;
+};
+
+struct dipe_ctxt {
+ size_t dimension;
+ element_t s;
+ element_t* cx;
+ element_t c;
+};
+
+
+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(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_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((*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->gt, (*sk)->k[i]);
+ }
+}
+
+void dipe_keygen(dipe_param_t param, dipe_master_secretkey_t msk, 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);
+
+ 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_set1(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_encrypt(dipe_param_t param, dipe_master_publickey_t mpk, element_t* x, element_t ptxt, dipe_ctxt_t* ctxt) {
+ *ctxt = (dipe_ctxt_t)malloc(sizeof(dipe_ctxt));
+ (*ctxt)->dimension = mpk->dimension;
+
+ element_t r;
+ element_t s;
+ element_init_Zr(r, param->pairing);
+ element_init_Zr(s, param->pairing);
+
+ element_random(r);
+ element_random(s);
+
+ element_init_G1((*ctxt)->s, param->pairing);
+ element_pow_zn((*ctxt)->s, param->g1, s);
+
+ element_t k1;
+ element_t x1;
+ element_init_G1(k1, param->pairing);
+ element_init_G1(x1, param->pairing);
+
+ (*ctxt)->cx = (element_t*)calloc(mpk->dimension, sizeof(element_t));
+ for (size_t i = 0; i < mpk->dimension; ++i){
+ element_pow_zn(x1, param->g1, x[i]);
+ element_pow_zn(x1, x1, r);
+
+ element_pow_zn(k1, mpk->k[i], s);
+
+ element_init_G1((*ctxt)->cx[i], param->pairing);
+ element_mul((*ctxt)->cx[i], k1, x1);
+ }
+
+ element_t at;
+ element_init_GT(at, param->pairing);
+ element_pow_zn(at, mpk->a, s);
+ element_init_GT((*ctxt)->c, param->pairing);
+ element_mul((*ctxt)->c, at, ptxt);
+
+ element_clear(r);
+ element_clear(s);
+ element_clear(k1);
+ element_clear(x1);
+ element_clear(at);
+}
+
+
+void dipe_decrypt(dipe_param_t param, dipe_secretkey_t sk, char* cid, element_t* y, dipe_ctxt_t ctxt, element_t ptxt) {
+ size_t hash_input_length = dipe_h_length(y[0], sk->dimension);
+ unsigned char hash_input[hash_input_length];
+ element_t h;
+ element_init_G2(h, param->pairing);
+
+ dipe_generate_h(cid, y, sk->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_set1(innerp);
+ for (size_t i = 0; i < sk->dimension; ++i) {
+ element_pow_zn(hy, h, y[i]);
+ pairing_apply(tmp, ctxt->cx[i], hy, param->pairing);
+ element_mul(innerp, innerp, tmp);
+ }
+
+ pairing_apply(ptxt, ctxt->s, sk->d, param->pairing);
+ element_invert(ptxt, ptxt);
+ element_mul(ptxt, ptxt, ctxt->c);
+ element_mul(ptxt, ptxt, innerp);
+
+ element_clear(h);
+ element_clear(tmp);
+ element_clear(innerp);
+ element_clear(hy);
+}
+
+
+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);
+ 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);
+ free(pk);
+}
+
+void dipe_free_secretkey(dipe_secretkey_t sk) {
+ element_clear(sk->d);
+ free(sk);
+}
+
+void dipe_free_ctxt(dipe_ctxt_t ctxt) {
+ for (size_t i = 0; i < ctxt->dimension; ++i) {
+ element_clear(ctxt->cx[i]);
+ }
+ element_clear(ctxt->c);
+ element_clear(ctxt->s);
+ free(ctxt->cx);
+ free(ctxt);
+}