参考2019年2月发表的论文《Zexe: Enabling Decentralized Private Computation》,具体实现见代码库。
1. zexe中的algebra代数运算zexe\algebra\src\curves中,对bls12_377、bls12_381、edwards_bls12、edwards_sw6、jubjub、mnt6、sw6等共7条曲线做了实现,同时对bls12_377、bls12_381和sw6做了bench测试。
1.1FixedBaseMSM运算zexe/algebra/src/msm/fixed_base.rs中有: 1)get_mul_window_size根据多项式的阶 d d d(即num_scalars)来决定窗口的大小。
pub fn get_mul_window_size(num_scalars: usize) -> usize {
if num_scalars < 32 {
3
} else {
(f64::from(num_scalars as u32)).ln().ceil() as usize
}
}
2)get_window_table返回的为一个二维数组,列数为:2^{window},行数为outerc=(scalar_size + window - 1) / window,其中的scalar_size为曲线的MODULUS_BITS。其中最后一列,除了前last_in_window个外,之后的均为零值。 [ 0 g 2 g 3 g 4 g . . . ( 2 w i n d o w − 1 ) g 0 ( 2 w i n d o w ) g 2 ∗ ( 2 w i n d o w ) g 3 ∗ ( 2 w i n d o w ) g 4 ∗ ( 2 w i n d o w ) g . . . ( 2 2 ∗ w i n d o w − 1 ) g . . . . . . . . . . . . . . . . . . . . . 0 ( 2 ( o u t e r c − 1 ) ∗ w i n d o w ) g 2 ∗ ( 2 ( o u t e r c − 1 ) ∗ w i n d o w ) g . . . ( l a s t _ i n _ w i n d o w − 1 ) ∗ ( 2 ( o u t e r c − 1 ) ∗ w i n d o w ) g 0 0 ] \begin{bmatrix} 0& g & 2g & 3g & 4g & ... & (2^{window}-1)g\\ 0& (2^{window})g & 2*(2^{window})g & 3*(2^{window})g & 4*(2^{window})g & ... & (2^{2*window}-1)g \\ ... & ... & ... & ... & ... & ... & ...\\ 0 & (2^{(outerc-1)*window})g & 2*(2^{(outerc-1)*window})g & ... & (last\_in\_window-1)*(2^{(outerc-1)*window})g & 0 & 0 \end{bmatrix} ⎣⎢⎢⎡00...0g(2window)g...(2(outerc−1)∗window)g2g2∗(2window)g...2∗(2(outerc−1)∗window)g3g3∗(2window)g......4g4∗(2window)g...(last_in_window−1)∗(2(outerc−1)∗window)g.........0(2window−1)g(22∗window−1)g...0⎦⎥⎥⎤
pub fn get_window_table(
scalar_size: usize,
window: usize,
g: T,
) -> Vec{
let in_window = 1 << window;
let outerc = (scalar_size + window - 1) / window;
let last_in_window = 1 << (scalar_size - (outerc - 1) * window);
let mut multiples_of_g = vec![vec![T::zero(); in_window]; outerc];
let mut g_outer = g;
for outer in 0..outerc {
let mut g_inner = T::zero();
let cur_in_window = if outer == outerc - 1 {
last_in_window
} else {
in_window
};
for inner in 0..cur_in_window {
multiples_of_g[outer][inner] = g_inner;
g_inner += &g_outer;
}
for _ in 0..window {
g_outer.double_in_place();
}
}
multiples_of_g
}
3)multi_scalar_mul函数中采用了v.par_iter()(调用rayon库)并行计算,其中table为上面2)返回的二维数组multiples_of_g,v为一维数组(如 [ 1 , β , β 2 , β 3 , . . . , β d ] [1,\beta,\beta^2,\beta^3,...,\beta^d ] [1,β,β2,β3,...,βd]),对应返回的结果为 [ g , β g , β 2 g , β 3 g , . . . , β d g ] [g,\beta g,\beta^2 g,\beta^3 g,...,\beta^d g] [g,βg,β2g,β3g,...,βdg]。 windowed_mul以查表的方式从multiples_of_g中计算相应的scalar*g的值。
pub fn multi_scalar_mul(
scalar_size: usize,
window: usize,
table: &[Vec],
v: &[T::ScalarField],
) -> Vec{
let outerc = (scalar_size + window - 1) / window;
assert!(outerc <= table.len());
v.par_iter().map(|e| Self::windowed_mul::(outerc, window, table, e)).collect::()
}
pub fn windowed_mul(
outerc: usize,
window: usize,
multiples_of_g: &[Vec],
scalar: &T::ScalarField,
) -> T {
let mut scalar_val = scalar.into_repr().to_bits();
scalar_val.reverse(); //将scalar转换为以big-endian形式表示,如为10,对应为1010
let mut res = multiples_of_g[0][0];
for outer in 0..outerc {
let mut inner = 0usize;
for i in 0..window {
if outer * window + i < (::Params::MODULUS_BITS as usize)
&& scalar_val[outer * window + i]
{
inner |= 1 << i;
}
}
res += &multiples_of_g[outer][inner];
}
res
}
2. zexe的bench-utils
配置上--features print-trace,调用其提供的start_timer!和end_timer!等宏,可打印各个环节实际执行时间,非常实用。
zexe的crypto-primitives提供了三种commitment(blake2s、pedersen和injective_map)及相应的bench。 1)commitment
- blake2s为hash函数;
- pedersen为pedersen commitment;
- injective_map为在pedersen commitment的基础上,同时保证最终的commit点在curve上且在相应的prime order subgroup。
2)crh
- injective_map:
- pedersen:
3)merkle_tree
4)nizk
- gm17:
- groth16:
5)prf
- blake2s:
参考资料: [1] 2019年论文《Zexe: Enabling Decentralized Private Computation》
