https://github.com/henrycg/earand
Raw File
Tip revision: 362625f3847ddd2e2d5a90cf5f93b4b3ea76e059 authored by Henry Corrigan-Gibbs on 21 May 2018, 19:54:59 UTC
Merge branch 'master' of github.com:henrycg/earand
Tip revision: 362625f
pedersen_proof.c
#include <openssl/sha.h>
#include <string.h>

#include "pedersen_proof.h"
#include "util.h"

static const char str_c[] = "c";
static const char str_s1[] = "s1";
static const char str_s2[] = "s2";

struct pedersen_statement {
    const EC_GROUP* group;
    EC_POINT* g; 
    EC_POINT* h; 
    EC_POINT* commit_x;
    EC_POINT* g_to_the_x;
};

struct pedersen_evidence {
  /* Challenge */
  BIGNUM* c;

  /* Response */
  BIGNUM* s1;
  BIGNUM* s2;
};

static BIGNUM* Commit(const_PedersenStatement st, const EC_POINT* T1, 
    const EC_POINT* T2, const BIGNUM* q, BN_CTX* ctx);
static void AddPointToHash(SHA_CTX* sha, const EC_GROUP* ec, 
    const EC_POINT* p, BN_CTX* ctx);

PedersenStatement PedersenStatement_New(const EC_GROUP* group, 
    const EC_POINT* g, 
    const EC_POINT* h, 
    const EC_POINT* commit_x,
    const EC_POINT* g_to_the_x)
{
  PedersenStatement st = safe_malloc(sizeof(*st));

  st->group = group;
  CHECK_CALL(st->g = EC_POINT_dup(g, group));
  CHECK_CALL(st->h = EC_POINT_dup(h, group));
  CHECK_CALL(st->commit_x = EC_POINT_dup(commit_x, group));
  CHECK_CALL(st->g_to_the_x = EC_POINT_dup(g_to_the_x, group));

  return st;
}

void PedersenStatement_Free(PedersenStatement st)
{
  EC_POINT_clear_free(st->g);
  EC_POINT_clear_free(st->h);
  EC_POINT_clear_free(st->commit_x);
  EC_POINT_clear_free(st->g_to_the_x);
  free(st);
}

PedersenEvidence PedersenEvidence_New(PedersenStatement st, 
    const BIGNUM *witness_x, const BIGNUM *witness_r)
{
  PedersenEvidence ev = safe_malloc(sizeof(*ev));
  CHECK_CALL(ev);

  BN_CTX* ctx = BN_CTX_new();
  CHECK_CALL(ctx);

  BIGNUM* q = BN_new();
  BIGNUM* t1 = BN_new();
  BIGNUM* t2 = BN_new();
  CHECK_CALL(q);
  CHECK_CALL(t1);
  CHECK_CALL(t2);
  CHECK_CALL(EC_GROUP_get_order(st->group, q, ctx));

  EC_POINT* commit_1 = EC_POINT_new(st->group);
  EC_POINT* commit_2 = EC_POINT_new(st->group);

  // t1 = random in [1,Q]
  // t2 = random in [1,Q]
  CHECK_CALL(BN_rand_range(t1, q));
  CHECK_CALL(BN_rand_range(t2, q));

  // T2 = g^t1
  CHECK_CALL(EC_POINT_mul(st->group, commit_2, NULL, st->g, t1, ctx));

  // T1 = g^t1 h^t2 == T2 * (h^t2)
  CHECK_CALL(EC_POINT_mul(st->group, commit_1, NULL, st->h, t2, ctx));
  CHECK_CALL(EC_POINT_add(st->group, commit_1, commit_1, commit_2, ctx));

  EC_DEBUG("T1", st->group, commit_1, ctx);
  EC_DEBUG("T2", st->group, commit_2, ctx);

  // == Challenge == 
  // c = Hash(g, h, commit_x, g_to_the_x, T1, T2)
  ev->c = Commit(st, commit_1, commit_2, q, ctx);
  CHECK_CALL(ev->c);

  // == Response ==
  // s1 = c*x + t1  (mod Q)
  ev->s1 = BN_dup(ev->c);
  CHECK_CALL(ev->s1);
  CHECK_CALL(BN_mod_mul(ev->s1, ev->s1, witness_x, q, ctx));
  CHECK_CALL(BN_mod_add(ev->s1, ev->s1, t1, q, ctx));

  // s2 = c*r + t2  (mod Q)
  ev->s2 = BN_dup(ev->c);
  CHECK_CALL(ev->s2);
  CHECK_CALL(BN_mod_mul(ev->s2, ev->s2, witness_r, q, ctx));
  CHECK_CALL(BN_mod_add(ev->s2, ev->s2, t2, q, ctx));

  // proof is (c, s1, s2)

  BN_free(q);
  BN_clear_free(t1);
  BN_clear_free(t2);
  BN_CTX_free(ctx);

  EC_POINT_free(commit_1);
  EC_POINT_free(commit_2);

  return ev;
}

void PedersenEvidence_Free(PedersenEvidence ev)
{
  BN_clear_free(ev->c);
  BN_clear_free(ev->s1);
  BN_clear_free(ev->s2);
  free(ev);
}

BIGNUM* Commit(const_PedersenStatement st, const EC_POINT* T1, const EC_POINT* T2,
    const BIGNUM* q, BN_CTX* ctx) 
{
  unsigned char digest[SHA_DIGEST_LENGTH];

  SHA_CTX sha;
  CHECK_CALL(SHA1_Init(&sha));

  AddPointToHash(&sha, st->group, st->g, ctx);
  AddPointToHash(&sha, st->group, st->h, ctx);
  AddPointToHash(&sha, st->group, st->commit_x, ctx);
  AddPointToHash(&sha, st->group, st->g_to_the_x, ctx);
  AddPointToHash(&sha, st->group, T1, ctx);
  AddPointToHash(&sha, st->group, T2, ctx);

  CHECK_CALL(SHA1_Final(digest, &sha));

  BIGNUM* result = BN_bin2bn(digest, SHA_DIGEST_LENGTH, NULL);
  CHECK_CALL(result);

  CHECK_CALL(BN_mod(result, result, q, ctx));

  return result;
}

void AddPointToHash(SHA_CTX* sha, const EC_GROUP* group, 
    const EC_POINT* p, BN_CTX* ctx)
{
  char* hex = EC_POINT_point2hex(group, p, POINT_CONVERSION_UNCOMPRESSED, ctx);
  CHECK_CALL(SHA1_Update(sha, (void*)hex, strlen(hex)));
  OPENSSL_free(hex);
}

bool PedersenEvidence_Verify(const_PedersenEvidence ev, const_PedersenStatement st)
{
  BN_CTX* ctx = BN_CTX_new();
  EC_POINT* commit_1 = EC_POINT_new(st->group);
  EC_POINT* commit_2 = EC_POINT_new(st->group); 
  EC_POINT* g_to_the_s1 = EC_POINT_new(st->group);
  EC_POINT* commit_x_inv = EC_POINT_new(st->group); 

  // T2 = (g^s1) / (g_to_the_x^c)

  CHECK_CALL(st->g);
  CHECK_CALL(ev->s1);

  // g_to_the_s1 = g^s1
  CHECK_CALL(EC_POINT_mul(st->group, g_to_the_s1, NULL, st->g, ev->s1, ctx));

  // commit_2 = (g_to_the_x)^c
  CHECK_CALL(EC_POINT_mul(st->group, commit_2, NULL, st->g_to_the_x, ev->c, ctx));
  CHECK_CALL(EC_POINT_invert(st->group, commit_2, ctx));

  // T2 = (g^s1) / (g_to_the_x^c)
  CHECK_CALL(EC_POINT_add(st->group, commit_2, g_to_the_s1, commit_2, ctx));

  // T1 = (g^s1 h^s2) / (commit_x^c)
  // commit_1 = g^s1 h^s2
  CHECK_CALL(EC_POINT_mul(st->group, commit_1, NULL, st->h, ev->s2, ctx));
  CHECK_CALL(EC_POINT_add(st->group, commit_1, commit_1, g_to_the_s1, ctx));

  // commit_x_inv = (commit_x^-c)
  CHECK_CALL(EC_POINT_mul(st->group, commit_x_inv, NULL, st->commit_x, ev->c, ctx));
  CHECK_CALL(EC_POINT_invert(st->group, commit_x_inv, ctx));

  // T1 = (g^s1 h^s2) / (commit_x^c)
  CHECK_CALL(EC_POINT_add(st->group, commit_1, commit_1, commit_x_inv, ctx));

  //EC_DEBUG("commit_x", st->group, st->commit_x, ctx);
  EC_DEBUG("T1", st->group, commit_1, ctx);
  EC_DEBUG("T2", st->group, commit_2, ctx);

  BIGNUM* q = BN_new();
  CHECK_CALL(EC_GROUP_get_order(st->group, q, ctx));
  BIGNUM* c_actual = Commit(st, commit_1, commit_2, q, ctx);

  //BN_DEBUG("c_actual", c_actual);
  //BN_DEBUG("       c", ev->c);

  bool retval = !BN_cmp(c_actual, ev->c);

  BN_free(q);
  BN_free(c_actual);
  EC_POINT_free(commit_1);
  EC_POINT_free(commit_2);
  EC_POINT_free(g_to_the_s1);
  EC_POINT_free(commit_x_inv);
  BN_CTX_free(ctx);
  
  return retval;
}

bool PedersenEvidence_Serialize(const_PedersenEvidence ev, FILE* fp)
{
  if(!WriteOneBignum(str_c, sizeof(str_c), fp, ev->c)) return false;
  if(!WriteOneBignum(str_s1, sizeof(str_s1), fp, ev->s1)) return false;
  if(!WriteOneBignum(str_s2, sizeof(str_s2), fp, ev->s2)) return false;

  return true;
}

PedersenEvidence PedersenEvidence_Unserialize(FILE* fp)
{
  PedersenEvidence ev = safe_malloc(sizeof(*ev));
  ev->c = BN_new();
  ev->s1 = BN_new();
  ev->s2 = BN_new();

  CHECK_CALL(ev->c);
  CHECK_CALL(ev->s1);
  CHECK_CALL(ev->s2);

  if(!(ReadOneBignum(&(ev->c), fp, str_c) &&
    ReadOneBignum(&(ev->s1), fp, str_s1) &&
    ReadOneBignum(&(ev->s2), fp, str_s2))) {

    BN_clear_free(ev->c);
    BN_clear_free(ev->s1);
    BN_clear_free(ev->s2);
    free(ev);

    return NULL;
  } 

  return ev;
}

back to top