BLS签名-使用PBC库

BLS签名-使用PBC库

本篇博客将介绍如何使用PBC库实现Boneh-Lynn-Shacham (BLS)签名方案,该程序的源代码文件是example/bls.c

我们有三个阶为素数r的群G1、G2、GT,和一个双线性映射,它能把一个来自G1的元素和一个来自G2的元素映射到GT对应的元素上。我们把这些与一个系统参数g一起发布,g是G2中随机选择的一个元素

Alice选择一个要签署的消息,她通过如下的方法生成公钥和私钥,她的私钥是1到r之间的随机数,她对应的公钥是gx

为了签名一个消息,Alice将这条消息的hash值映射到G1的元素h上,然后输出这个签名hx

为了验证签名σ,Bob验证这个等式e(h,gx)=e(σ,g)

现在我们使用PBC库将这些转化为c代码

  • 首先我们包含pbc/pbc.h文件

    
    #include <pbc.h>
    
  • 然后我们初始化一个双线性配对

    pairing_t pairing;
    char param[1024];
    size_t count = fread(param, 1, 1024, stdin);
    if (!count) pbc_die("input error");
    pairing_init_set_buf(pairing, param, count);
  • 接着,我们通过改变我们程序的标准输入重定向来接收双线性配对的参数,param子目录下的任意一个文件都可以,比如说:

    bls < param/a.param
  • 我们需要几个element变量去保存系统参数。我们声明并初始化他们

    element_t g, h;
    element_t public_key, secret_key;
    element_t sig;
    element_t temp1, temp2;
    
    element_init_G2(g, pairing);
    element_init_G2(public_key, pairing);
    element_init_G1(h, pairing);
    element_init_G1(sig, pairing);
    element_init_GT(temp1, pairing);
    element_init_GT(temp2, pairing);
    element_init_Zr(secret_key, pairing);
  • 生成系统参数

    element_random(g);
  • 生成密钥

    element_random(secret_key);
  • 生成对应的公钥

    element_pow_zn(public_key, g, secret_key);
  • 然后给一个消息去签名。首先我们使用一些标准的hash算法去计算它的hash值。许多的库可以这样做,而且这个操作不涉及双线性配对,因此PBC不提供这一步的函数。公布这个消息的hash值是“ABCDEF”(一个48位的hash值),我们将这些比特映射到G1的一个元素h上

    element_from_hash(h, "ABCDEF", 6);
  • 生成签名

    element_pow_zn(sig, h, secret_key);
  • 为了验证这个签名,我们将签名、系统参数g和双线性配对生成的值与h、公钥和双线性配对生成的值进行比较。如果这两个输出匹配,说明这个签名是有效的

    pairing_apply(temp1, sig, g, pairing);
    pairing_apply(temp2, h, public_key, pairing);
    if (!element_cmp(temp1, temp2)) {
      printf("signature verifies\n");
    } else {
      printf("signature does not verify\n");
    }
  • 为了有用,在某些阶段必须将签名转化为字节才能存储或传输

    int n = pairing_length_in_bytes_compressed_G1(pairing);
    // Alternatively:
    // int n = element_length_in_bytes_compressed(sig);
    unsigned char *data = malloc(n);
    element_to_bytes_compressed(data, sig);
  • 在另一方面,这个签名必须能够解压

    element_from_bytes_compressed(sig, data);
  • 省略 _compressed 在上面的代码中同样也能工作,但是缓冲区的大小大概会变为两倍

  • 通过使用仅仅适用于签名的x-coordinate,我们能够节省更多的空间

    int n = pairing_length_in_bytes_x_only_G1(pairing);
    // Alternative:
    //   int n = element_length_in_bytes_x_only(sig);
    unsigned char *data = malloc(n);
    element_to_bytes_compressed(data, sig);
  • 但是由于有两个不同的点有相同的x坐标,在验证的时候会比较复杂。一种解决办法是选取一个点并试图去验证,如果失败了,我们在去尝试另外一个。可以看出这两个点互为逆元,避免了第二次计算双线性映射(实际上这是一个更好的处理问题的办法)

    int n = pairing_length_in_bytes_x_only_G1(pairing);
    //int n = element_length_in_bytes_x_only(sig);
    unsigned char *data = malloc(n);
    
    element_to_bytes_x_only(data, sig);
    
    element_from_bytes_x_only(sig, data)
    
    pairing_apply(temp1, sig, g, pairing);
    pairing_apply(temp2, h, public_key, pairing);
    
    if (!element_cmp(temp1, temp2)) {
      printf("signature verifies on first guess\n");
    } else {
      element_invert(temp1, temp1);
      if (!element_cmp(temp1, temp2)) {
          printf("signature verifies on second guess\n");
      } else {
          printf("signature does not verify\n");
      }
    }
阅读更多
换一批

没有更多推荐了,返回首页