//subtract Keys (subtracts curve points)
 //AB = A - B where A, B are curve points
 void subKeys(key & AB, const key &A, const key &B) {
     ge_p3 B2, A2;
     CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&B2, B.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
     CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&A2, A.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
     ge_cached tmp2;
     ge_p3_to_cached(&tmp2, &B2);
     ge_p1p1 tmp3;
     ge_sub(&tmp3, &A2, &tmp2);
     ge_p1p1_to_p3(&A2, &tmp3);
     ge_p3_tobytes(AB.bytes, &A2);
 }
 //addKeys3
 //aAbB = a*A + b*B where a, b are scalars, A, B are curve points
 //B must be input after applying "precomp"
 void addKeys3(key &aAbB, const key &a, const key &A, const key &b, const ge_dsmp B) {
     ge_p2 rv;
     ge_p3 A2;
     CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&A2, A.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
     ge_double_scalarmult_precomp_vartime(&rv, a.bytes, &A2, b.bytes, B);
     ge_tobytes(aAbB.bytes, &rv);
 }
 //addKeys2
 //aGbB = aG + bB where a, b are scalars, G is the basepoint and B is a point
 void addKeys2(key &aGbB, const key &a, const key &b, const key & B) {
     ge_p2 rv;
     ge_p3 B2;
     CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&B2, B.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
     ge_double_scalarmult_base_vartime(&rv, b.bytes, &B2, a.bytes);
     ge_tobytes(aGbB.bytes, &rv);
 }
 //does a * P where a is a scalar and P is an arbitrary point
 void scalarmultKey(key & aP, const key &P, const key &a) {
     ge_p3 A;
     ge_p2 R;
     CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&A, P.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
     ge_scalarmult(&R, a.bytes, &A);
     ge_tobytes(aP.bytes, &R);
 }
 //Computes aH where H= toPoint(cn_fast_hash(G)), G the basepoint
 key scalarmultH(const key & a) {
     ge_p3 A;
     ge_p2 R;
     CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&A, H.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
     ge_scalarmult(&R, a.bytes, &A);
     key aP;
     ge_tobytes(aP.bytes, &R);
     return aP;
 }
static void corrupt_bob_step2(secure_comparator_t *bob, const void *input, size_t input_length, void *output, size_t *output_length)
{
	/* Let's assume bob is malicious and uses zeroes instead of random numbers */

	ge_p3 g2a;
	ge_p3 g3a;

	ge_p3 g2b;
	ge_p3 g3b;

	ge_frombytes_vartime(&g2a, (const unsigned char *)input);
	ge_frombytes_vartime(&g3a, ((const unsigned char *)input) + (3 * ED25519_GE_LENGTH));

	if (THEMIS_SCOMPARE_SEND_OUTPUT_TO_PEER != secure_comparator_proceed_compare(bob, input, input_length, output, output_length))
	{
		testsuite_fail_if(true, "secure_comparator_proceed_compare failed");
		return;
	}

	memset(bob->rand2, 0, sizeof(bob->rand2));
	memset(bob->rand3, 0, sizeof(bob->rand3));

	ge_scalarmult_base(&g2b, bob->rand2);
	ge_scalarmult_base(&g3b, bob->rand3);

	ge_scalarmult_blinded(&(bob->g2), bob->rand2, &g2a);
	ge_scalarmult_blinded(&(bob->g3), bob->rand3, &g3a);

	memset(bob->rand, 0, sizeof(bob->rand));

	ge_scalarmult_blinded(&(bob->P), bob->rand, &(bob->g3));
	ge_double_scalarmult_vartime((ge_p2 *)&(bob->Q), bob->secret, &(bob->g2), bob->rand);
	ge_p2_to_p3(&(bob->Q), (const ge_p2 *)&(bob->Q));

	ge_p3_tobytes((unsigned char *)output, &g2b);
	ed_sign(3, bob->rand2, ((unsigned char *)output) + ED25519_GE_LENGTH);

	ge_p3_tobytes(((unsigned char *)output) + (3 * ED25519_GE_LENGTH), &g3b);
	ed_sign(4, bob->rand3, ((unsigned char *)output) + (4 * ED25519_GE_LENGTH));

	ge_p3_tobytes(((unsigned char *)output) + (6 * ED25519_GE_LENGTH), &(bob->P));
	ge_p3_tobytes(((unsigned char *)output) + (7 * ED25519_GE_LENGTH), &(bob->Q));
	ed_dbl_base_sign(5, bob->rand, bob->secret, &(bob->g2), &(bob->g3), ((unsigned char *)output) + (8 * ED25519_GE_LENGTH));
}
  bool crypto_ops::check_ring_signature(const hash &prefix_hash, const key_image &image,
    const public_key *const *pubs, size_t pubs_count,
    const signature *sig) {
    size_t i;
    ge_p3 image_unp;
    ge_dsmp image_pre;
    ec_scalar sum, h;
    rs_comm *const buf = reinterpret_cast<rs_comm *>(alloca(rs_comm_size(pubs_count)));
#if !defined(NDEBUG)
    for (i = 0; i < pubs_count; i++) {
      assert(check_key(*pubs[i]));
    }
#endif
    if (ge_frombytes_vartime(&image_unp, &image) != 0) {
      return false;
    }
    ge_dsm_precomp(image_pre, &image_unp);
    sc_0(&sum);
    buf->h = prefix_hash;
    for (i = 0; i < pubs_count; i++) {
      ge_p2 tmp2;
      ge_p3 tmp3;
      if (sc_check(&sig[i].c) != 0 || sc_check(&sig[i].r) != 0) {
        return false;
      }
      if (ge_frombytes_vartime(&tmp3, &*pubs[i]) != 0) {
        abort();
      }
      ge_double_scalarmult_base_vartime(&tmp2, &sig[i].c, &tmp3, &sig[i].r);
      ge_tobytes(&buf->ab[i].a, &tmp2);
      hash_to_ec(*pubs[i], tmp3);
      ge_double_scalarmult_precomp_vartime(&tmp2, &sig[i].r, &tmp3, &sig[i].c, image_pre);
      ge_tobytes(&buf->ab[i].b, &tmp2);
      sc_add(&sum, &sum, &sig[i].c);
    }
    hash_to_scalar(buf, rs_comm_size(pubs_count), h);
    sc_sub(&h, &h, &sum);
    return sc_isnonzero(&h) == 0;
  }
 key hashToPointSimple(const key & hh) {
     key pointk;
     ge_p1p1 point2;
     ge_p2 point;
     ge_p3 res;
     key h = cn_fast_hash(hh); 
     CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&res, h.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
     ge_p3_to_p2(&point, &res);
     ge_mul8(&point2, &point);
     ge_p1p1_to_p3(&res, &point2);
     ge_p3_tobytes(pointk.bytes, &res);
     return pointk;
 }    
 bool crypto_ops::generate_key_derivation(const public_key &key1, const secret_key &key2, key_derivation &derivation) {
   ge_p3 point;
   ge_p2 point2;
   ge_p1p1 point3;
   assert(sc_check(&key2) == 0);
   if (ge_frombytes_vartime(&point, &key1) != 0) {
     return false;
   }
   ge_scalarmult(&point2, &key2, &point);
   ge_mul8(&point3, &point2);
   ge_p1p1_to_p2(&point2, &point3);
   ge_tobytes(&derivation, &point2);
   return true;
 }
 bool crypto_ops::derive_public_key(const key_derivation &derivation, size_t output_index,
   const public_key &base, public_key &derived_key) {
   ec_scalar scalar;
   ge_p3 point1;
   ge_p3 point2;
   ge_cached point3;
   ge_p1p1 point4;
   ge_p2 point5;
   if (ge_frombytes_vartime(&point1, &base) != 0) {
     return false;
   }
   derivation_to_scalar(derivation, output_index, scalar);
   ge_scalarmult_base(&point2, &scalar);
   ge_p3_to_cached(&point3, &point2);
   ge_add(&point4, &point1, &point3);
   ge_p1p1_to_p2(&point5, &point4);
   ge_tobytes(&derived_key, &point5);
   return true;
 }
 bool crypto_ops::check_signature(const hash &prefix_hash, const public_key &pub, const signature &sig) {
   ge_p2 tmp2;
   ge_p3 tmp3;
   ec_scalar c;
   s_comm buf;
   assert(check_key(pub));
   buf.h = prefix_hash;
   buf.key = pub;
   if (ge_frombytes_vartime(&tmp3, &pub) != 0) {
     abort();
   }
   if (sc_check(&sig.c) != 0 || sc_check(&sig.r) != 0) {
     return false;
   }
   ge_double_scalarmult_base_vartime(&tmp2, &sig.c, &tmp3, &sig.r);
   ge_tobytes(&buf.comm, &tmp2);
   hash_to_scalar(&buf, sizeof(s_comm), c);
   sc_sub(&c, &c, &sig.c);
   return sc_isnonzero(&c) == 0;
 }
 bool crypto_ops::check_key(const public_key &key) {
   ge_p3 point;
   return ge_frombytes_vartime(&point, &key) == 0;
 }
  void crypto_ops::generate_ring_signature(const hash &prefix_hash, const key_image &image,
    const public_key *const *pubs, size_t pubs_count,
    const secret_key &sec, size_t sec_index,
    signature *sig) {
    lock_guard<mutex> lock(random_lock);
    size_t i;
    ge_p3 image_unp;
    ge_dsmp image_pre;
    ec_scalar sum, k, h;
    rs_comm *const buf = reinterpret_cast<rs_comm *>(alloca(rs_comm_size(pubs_count)));
    assert(sec_index < pubs_count);
#if !defined(NDEBUG)
    {
      ge_p3 t;
      public_key t2;
      key_image t3;
      assert(sc_check(&sec) == 0);
      ge_scalarmult_base(&t, &sec);
      ge_p3_tobytes(&t2, &t);
      assert(*pubs[sec_index] == t2);
      generate_key_image(*pubs[sec_index], sec, t3);
      assert(image == t3);
      for (i = 0; i < pubs_count; i++) {
        assert(check_key(*pubs[i]));
      }
    }
#endif
    if (ge_frombytes_vartime(&image_unp, &image) != 0) {
      abort();
    }
    ge_dsm_precomp(image_pre, &image_unp);
    sc_0(&sum);
    buf->h = prefix_hash;
    for (i = 0; i < pubs_count; i++) {
      ge_p2 tmp2;
      ge_p3 tmp3;
      if (i == sec_index) {
        random_scalar(k);
        ge_scalarmult_base(&tmp3, &k);
        ge_p3_tobytes(&buf->ab[i].a, &tmp3);
        hash_to_ec(*pubs[i], tmp3);
        ge_scalarmult(&tmp2, &k, &tmp3);
        ge_tobytes(&buf->ab[i].b, &tmp2);
      } else {
        random_scalar(sig[i].c);
        random_scalar(sig[i].r);
        if (ge_frombytes_vartime(&tmp3, &*pubs[i]) != 0) {
          abort();
        }
        ge_double_scalarmult_base_vartime(&tmp2, &sig[i].c, &tmp3, &sig[i].r);
        ge_tobytes(&buf->ab[i].a, &tmp2);
        hash_to_ec(*pubs[i], tmp3);
        ge_double_scalarmult_precomp_vartime(&tmp2, &sig[i].r, &tmp3, &sig[i].c, image_pre);
        ge_tobytes(&buf->ab[i].b, &tmp2);
        sc_add(&sum, &sum, &sig[i].c);
      }
    }
    hash_to_scalar(buf, rs_comm_size(pubs_count), h);
    sc_sub(&sig[sec_index].c, &h, &sum);
    sc_mulsub(&sig[sec_index].r, &sig[sec_index].c, &sec, &k);
  }
 //Does some precomputation to make addKeys3 more efficient
 // input B a curve point and output a ge_dsmp which has precomputation applied
 void precomp(ge_dsmp rv, const key & B) {
     ge_p3 B2;
     CHECK_AND_ASSERT_THROW_MES(ge_frombytes_vartime(&B2, B.bytes) == 0, "ge_frombytes_vartime failed at "+boost::lexical_cast<std::string>(__LINE__));
     ge_dsm_precomp(rv, &B2);
 }