Semaphore是一個(gè)用零知識證明(zk-SNARK)技術(shù)的開源項(xiàng)目。Semaphore實(shí)現(xiàn)的是基于零知識證明的身份和信號。https: github com barryWhiteHat
Semaphore是一個(gè)用零知識證明(zk-SNARK)技術(shù)的開源項(xiàng)目。Semaphore實(shí)現(xiàn)的是基于零知識證明的身份和信號。
https://github.com/barryWhiteHat/semaphore
1. 整體框架
Semaphore整個(gè)項(xiàng)目,由三部分組成:nodejs模塊(客戶端/服務(wù)器端以及前端頁面),snark模塊(zk-SNARK Groth16電路相關(guān)模塊),以及以太坊上的智能合約。主要邏輯都在semaphorejs目錄中,其源代碼目錄結(jié)構(gòu)如下:
contracts - 智能合約,使用truffle框架部署測試。
snark - snark模塊,使用snarkjs(iden3)開發(fā)zk-SNARK電路。
src - nodejs模塊,實(shí)現(xiàn)前后端。
三部分之間的邏輯關(guān)系如下:
2. Key & Identity
使用Semaphore的每個(gè)賬戶需要創(chuàng)建私鑰和公鑰。每個(gè)賬戶的公鑰和私鑰,以及對應(yīng)的Identity的具體邏輯可以查看semaphorejs/src/client/semaphore.js文件中g(shù)enerate_identity函數(shù):
const private_key = crypto.randomBytes(32).toString('hex');
const prvKey = Buffer.from(private_key, 'hex');
const pubKey = eddsa.prv2pub(prvKey);
const identity_nullifier = '0x' + crypto.randomBytes(31).toString('hex');
const identity_trapdoor = '0x' + crypto.randomBytes(31).toString('hex');
const identity_commitment = pedersenHash([bigInt(circomlib.babyJub.mulPointEscalar(pubKey, 8)[0]), bigInt(identity_nullifier), bigInt(identity_trapdoor)]);
私鑰是256位的隨機(jī)數(shù)。公鑰是私鑰的EdDSA的簽名。Identity主要由兩部分組成:31個(gè)字節(jié)的nullifier和31個(gè)字節(jié)的trapdoor。這兩部分都是隨機(jī)生成。這里的nullfier,不要和ZCash中的Nullifier混淆。這里的nullfier就是隨機(jī)數(shù)。每個(gè)Identity會對應(yīng)兩個(gè)對應(yīng)的信息:一個(gè)是commitment,一個(gè)是nullifier_hash。Commitment的計(jì)算方式如下圖:
Identity中的nullifier以及trapdoor并不記錄在以太坊的智能合約中,對應(yīng)的commitment會記錄在合約中。
3. Semaphore.sol
semaphorejs/contracts/Semaphore.sol是智能合約部分的邏輯實(shí)現(xiàn)。insertIdentity函數(shù)實(shí)現(xiàn)一個(gè)賬戶Identity的“注冊”。
function insertIdentity(uint256 identity_commitment) public style="box-sizing: border-box; padding-right: 0.1px;"> insert(id_tree_index, identity_commitment);
uint256 root = tree_roots[id_tree_index];
root_history[root] = true;
}
Identity對應(yīng)的commitment會添加到一個(gè)merkle樹上,同時(shí)新的merkle樹根會記錄在root_history的mapping中。
4. Nullifier Hash
Nullifier Hash是用來證明某個(gè)Identity對應(yīng)commitment存在一個(gè)merkle樹上,并生成的標(biāo)示。Nullfier Hash的計(jì)算過程可以查看電路的邏輯(semaphorejs/snark/semaphore-base.circom)。
template Semaphore(jubjub_field_size, n_levels, n_rounds) {
...
component external_nullifier_bits = Num2Bits(232);
external_nullifier_bits.in <== external_nullifier;
component nullifiers_hasher = Blake2s(512, 0);
for (var i = 0; i < 248; i++) {
nullifiers_hasher.in_bits[i] <== identity_nullifier_bits.out[i];
}
for (var i = 0; i < 232; i++) {
nullifiers_hasher.in_bits[248 + i] <== external_nullifier_bits.out[i];
}
for (var i = 0; i < n_levels; i++) {
nullifiers_hasher.in_bits[248 + 232 + i] <== identity_path_index[i];
}
for (var i = (248 + 232 + n_levels); i < 512; i++) {
nullifiers_hasher.in_bits[i] <== 0;
}
component nullifiers_hash_num = Bits2Num(253);
for (var i = 0; i < 253; i++) {
nullifiers_hash_num.in[i] <== nullifiers_hasher.out[i];
}
nullifiers_hash <== nullifiers_hash_num.out;
...
}
Nullifier Hash的計(jì)算邏輯如下圖:
其實(shí)nullfier和path index已經(jīng)足夠表示。額外加入了external nullfier的原因是,同一個(gè)Identity,在external nullifier不同的情況下,生成不同的nullifier hash。也就是說,一個(gè)賬戶可以多次“消費(fèi)”。這樣設(shè)計(jì)的原因是為了Signal的業(yè)務(wù)需求。
5. Signal
通過智能合約創(chuàng)建了Identity,就可以發(fā)信號(Signal)了。一個(gè)賬戶發(fā)送信號,必須首先提供Identity在merkle樹上的證明(能計(jì)算出commitment)。智能合約中的broadcastSignal是發(fā)送信號的接口:
function broadcastSignal(
bytes memory signal,
uint[2] memory a,
uint[2][2] memory b,
uint[2] memory c,
uint[4] memory input // (root, nullifiers_hash, signal_hash, external_nullifier)
) public
style="box-sizing: border-box; padding-right: 0.1px;"> isValidSignalAndProof(signal, a, b, c, input)
{
uint nullifiers_hash = input[1];
signals[current_signal_index++] = signal;
nullifier_hash_history[nullifiers_hash] = true;
emit SignalBroadcast(signal, nullifiers_hash, input[3]);
}
signal就是需要發(fā)送的信號,a/b/c是零知識證明的proof信息,input是零知識證明對應(yīng)電路的輸入,包括merkle樹根,nullifier hash,signal hash以及external nullifier。
只有在proof信息驗(yàn)證過后,對應(yīng)signal才會記錄。每次發(fā)送signal時(shí)對應(yīng)的nullifier hash會被記錄下來。也就是說,在external nullifier不變的情況下,所有Identity只能發(fā)送一次Signal。
總結(jié):
Semaphore項(xiàng)目由js開發(fā),結(jié)合零知識證明(zk-SNARK),在以太坊的智能合約的基礎(chǔ)上實(shí)現(xiàn)Identity。每個(gè)Identity可以發(fā)送信號。在external nullifier不變的情況下,每個(gè)Identity只能發(fā)送一次Signal。(Star Li)