2个不稳定版本
0.5.1 | 2020年4月21日 |
---|---|
0.5.0 |
|
0.4.0 | 2020年3月25日 |
#2377 in 加密学
200KB
4.5K SLoC
amcl_rust_wrapper
- 包装了AMCL的一些部分,提供了一种优雅的抽象方法来处理椭圆曲线上的有限域元素和群元素。
- 重载了+,-,*,+=,-=等运算符以用于域元素以及群元素。重载的运算符对应于常数时间方法。但对于标量乘法,存在可变时间算法,但只能通过调用方法来使用。
- 提供创建域元素或群(椭圆曲线点)元素向量的抽象,然后可以进行缩放、加法、减法、取内积或Hadamard积。
- 支持创建域元素的单项式并对其进行算术运算。
- 使用rayon并行化了一些向量和多项式上的操作。
- 使用serde提供序列化支持。
- 在丢弃时清除域和群元素。使用zeroize。
- 此外,还实现了一些额外的算法,例如使用wNAF的变时间标量乘法、常数时间和变时间多标量乘法、批(同时)求逆和Barrett约简。
构建
必须通过启用以下曲线之一作为功能来构建包装器。
要为BLS-381曲线构建,使用
cargo build --no-default-features --features bls381
类似地,要为secp256k1构建,使用
cargo build --no-default-features --features secp256k1
要为secp256k1运行测试,使用
cargo test --no-default-features --features secp256k1
要将它用作依赖项crate,使用曲线名称作为功能。例如,对于BLS12-381曲线,使用
[dependencies.amcl_wrapper]
version = "0.3.4"
default-features = false
features = ["bls381"]
请注意,一次只能使用一个曲线,因此代码只能与一个功能一起工作。
基准测试
有各种操作的测试,它们打印执行这些操作所需的时间。它们以timing
*[]为前缀:要运行它们,使用
cargo test --release --no-default-features --features <curve name> -- --nocapture timing
示例
- 创建一些随机的域元素或群元素,并进行一些基本的加法/减法/乘法操作
let a = FieldElement::random();
let b = FieldElement::random();
let neg_b = -b;
assert_ne!(b, neg_b);
let neg_neg_b = -neg_b;
assert_eq!(b, neg_neg_b);
assert_eq!(b+neg_b, FieldElement::zero());
let c = a + b;
let d = a - b;
let e = a * b;
let mut sum = FieldElement::zero();
sum += c;
sum += d;
// Compute inverse of element
let n = a.invert();
// Faster but constant time computation of inverse of several elements. `inverses` will be a vector of inverses of elements and `pr` will be the product of all inverses.
let (inverses, pr) = FieldElement::batch_invert(vec![a, b, c, d].as_slice());
// Compute a width 5 NAF.
let a_wnaf = a.to_wnaf(5);
// G1 is the elliptic curve sub-group over the prime field
let x = G1::random();
let y = G1::random();
let neg_y = -y;
assert_ne!(y, neg_y);
let neg_neg_y = -neg_y;
assert_eq!(y, neg_neg_y);
assert_eq!(y+neg_y, G1::identity());
let z = x + y;
let z1 = x - y;
let mut sum_1 = G1::identity();
sum_1 += z;
sum_1 += z1;
// G2 is the elliptic curve sub-group over the prime extension field
let x = G2::random();
let y = G2::random();
let neg_y = -y;
assert_ne!(y, neg_y);
let neg_neg_y = -neg_y;
assert_eq!(y, neg_neg_y);
assert_eq!(y+neg_y, G2::identity());
let z = x + y;
let z1 = x - y;
let mut sum_1 = G2::identity();
sum_1 += z;
sum_1 += z1;
// To check that G1 or G2 have correct order, i.e. the curve order
let x = G1::random();
assert!(x.has_correct_order());
let y = G2::random();
assert!(y.has_correct_order());
上述操作的变异版本(如加法/减法/否定/求逆)也存在,但必须作为方法调用,如b.negate()
- 标量乘法
let a = FieldElement::random();
let g = G1::generator(); // the group's generator
// constant time scalar multiplication
let m = g * a;
// variable time scalar multiplication using wNAF
let n = g.scalar_mul_variable_time(&a);
- 通过内部散列消息将任意大小的消息映射到域元素或群元素。
let msg = "Some message";
let a = FieldElement::from_msg_hash(msg.as_bytes());
let b = G1::from_msg_hash(msg.as_bytes());
- 创建字段元素的向量并执行一些操作
// creates a vector of size 10 with all elements as 0
let mut a = CurveOrderElementVector::new(10);
// Add 2 more elements to the above vector
a.push(FieldElement::random());
a.push(FieldElement::random());
a[0]; // 0th element of above vector
a[1]; // 1st element of above vector
a.len(); // length of vector
a.sum(); // sum of elements of vector
// Return a Vandermonde vector of a given field element, i.e. given element `k` and size `n`, return vector as `vec![1, k, k^2, k^3, ... k^n-1]`
let k = FieldElement::random();
let van_vec = CurveOrderElementVector::new_vandermonde_vector(&k, 5);
// creates a vector of size 10 with randomly generated field elements
let rands: Vec<_> = (0..10).map(|_| FieldElement::random()).collect();
// an alternative way of creating vector of size 10 of random field elements
let rands_1 = CurveOrderElementVector::random(10);
// Compute new vector as sum of 2 vectors. Requires vectors to be of equal length.
let sum_vec = rands.plus(&rands_1);
// Compute new vector as difference of 2 vectors. Requires vectors to be of equal length.
let diff_vec = rands.minus(&rands_1);
// Return the scaled vector of the given vector by a field element `n`, i.e. multiply each element of the vector by that field element
let n = FieldElement::random();
let scaled_vec = rands.scaled_by(&n);
// Scale the vector itself
let mut rands_2 = rands_1.clone();
rands_2.scale(&n);
// Compute inner product of 2 vectors. Requires vectors to be of equal length.
let ip = rands.inner_product(&rands_1);
// Compute Hadamard product of 2 vectors. Requires vectors to be of equal length.
let hp = rands.hadamard_product(&rands_1);
- 创建群元素的向量并执行一些操作
// creates a vector of size 10 with all elements as 0
let mut a = G1Vector::new(10);
// Add 2 more elements to the above vector
a.push(G1::random());
a.push(G1::random());
// creating vector of size 10 of random group elements
let rands: Vec<_> = (0..10).map(|_| G1::random()).collect();
let rands_1 = G1Vector::random(10);
// Compute new vector as sum of 2 vectors. Requires vectors to be of equal length.
let sum_vec = rands.plus(&rands_1);
// Compute new vector as difference of 2 vectors. Requires vectors to be of equal length.
let diff_vec = rands.minus(&rands_1);
// Compute inner product of a vector of group elements with a vector of field elements.
// eg. given a vector of group elements and field elements, G and F respectively, compute G[0]*F[0] + G[1]*F[1] + G[2]*F[2] + .. G[n-1]*F[n-1]
// requires vectors to be of same length
let g = G1Vector::random(10);
let f = CurveOrderElementVector::random(10);
// Uses constant time multi-scalar multiplication `multi_scalar_mul_const_time` underneath.
let ip = g.inner_product_const_time(&f);
// Uses variable time multi-scalar multiplication `multi_scalar_mul_var_time` underneath.
let ip1 = g.inner_product_var_time(&f);
// If lookup tables are already constructed, `multi_scalar_mul_const_time_with_precomputation_done` and `multi_scalar_mul_var_time_with_precomputation_done` can be used for constant and variable time multi-scalar multiplication
- 配对支持。支持目标群
GT
的Ate配对
let g1 = G1::random();
let g2 = G2::random();
// compute reduced ate pairing for 2 elements, i.e. e(g1, g2)
let gt = GT::ate_pairing(&g1, &g2);
// multiply target group elements
let h1 = G1::random();
let h2 = G2::random();
let ht = GT::ate_pairing(&h1, &h2);
let m = GT::mul(>, &ht);
// compute reduced ate pairing for 4 elements, i.e. e(g1, g2) * e (h1, h2)
let p = GT::ate_2_pairing(&g1, &g2, &h1, &h2);
// compute reduced ate multi-pairing. Takes a vector of tuples of group elements G1 and G2 as Vec<(&G1, &G2)>
let e = GT::ate_multi_pairing(tuple_vec);
// Raise target group element to field element (GT^f)
let r = FieldElement::random();
let p = gt.pow(&r);
- 序列化
// Convert to and from hex.
let hex_repr = a.to_hex();
let a_recon = FieldElement::from_hex(hex_repr).unwrap(); // Constant time conversion
// Convert to and from hex.
let hex_repr = x.to_hex();
let x_recon = G1::from_hex(hex_repr).unwrap(); // Constant time conversion
// Convert to and from hex.
let hex_repr = y.to_hex();
let y_recon = G2::from_hex(hex_repr).unwrap(); // Constant time conversion
- 一元多项式
// Create a univariate zero polynomial of degree `d`, i.e. the polynomial will be 0 + 0*x + 0*x^2 + 0*x^3 + ... + 0*x^d
let poly = UnivarPolynomial::new(d);
assert!(poly.is_zero());
// Create a polynomial from field elements as coefficients, the following polynomial will be c_0 + c_1*x + c_2*x^2 + c_3*x^3 + ... + c_d*x^d
let coeffs: Vec<FieldElement> = vec![c_0, c_1, ... coefficients for smaller to higher degrees ..., c_d];
let poly1 = UnivarPolynomial(CurveOrderElementVector::from(coeffs));
// Create a polynomial of degree `d` with random coefficients
let poly2 = UnivarPolynomial::random(d);
// Create a polynomial from its roots
let poly3 = UnivarPolynomial::new_with_roots(roots);
// Create a polynomial by passing the coefficients to a macro
let poly4 = univar_polynomial!(
FieldElement::one(),
FieldElement::zero(),
FieldElement::from(87u64),
-FieldElement::one(),
FieldElement::from(300u64)
);
// A polynomial can be evaluated at a field element `v`
let res: FieldElement = poly1.eval(v);
// Polynomials can be added, subtracted, multiplied or divided to give new polynomials
let sum = UnivarPolynomial::sum(&poly1, &poly2);
// Or use operator overloading
let sum = &poly1 + &poly2;
let diff = UnivarPolynomial::difference(&poly1, &poly2);
// Or use operator overloading
let diff = &poly1 - &poly2;
let product = UnivarPolynomial::multiply(&poly1, &poly2);
// Or use operator overloading
let product = &poly1 * &poly2;
// Dividing polynomials: poly1 / poly2
let (quotient, rem) = UnivarPolynomial::long_division(&poly1, &poly2);
依赖项
~6MB
~113K SLoC