BLS簽名-使用PBC庫
本篇博客將介紹如何使用PBC庫實現Boneh-Lynn-Shacham (BLS)簽名方案,該程序的源代碼文件是
example/bls.c
我們有三個階爲素數r的羣G1、G2、GT,和一個雙線性映射,它能把一個來自G1的元素和一個來自G2的元素映射到GT對應的元素上。我們把這些與一個系統參數g一起發佈,g是G2中隨機選擇的一個元素
Alice選擇一個要簽署的消息,她通過如下的方法生成公鑰和私鑰,她的私鑰是1到r之間的隨機數,她對應的公鑰是
爲了簽名一個消息,Alice將這條消息的hash值映射到G1的元素h上,然後輸出這個簽名
爲了驗證簽名σ,Bob驗證這個等式
現在我們使用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"); } }