fix ed25519 add op

This commit is contained in:
exfinen
2023-06-22 09:00:38 +09:00
parent 1ad0bf9da2
commit a5b9673a1f
10 changed files with 133 additions and 92 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
/target
.vscode

View File

@@ -1,4 +1,5 @@
use crate::building_block::ec_point::EcPoint;
use crate::building_block::field::Field;
use num_bigint::BigUint;
use num_traits::identities::{Zero, One};
use std::ops::{BitAnd, ShrAssign};
@@ -22,13 +23,13 @@ pub trait EcAdditiveGroupOps {
}
}
fn get_point_at_infinity(&self) -> EcPoint { // using &self to make the trait object-safe
EcPoint::inf()
fn get_point_at_infinity(&self, f: &Field) -> EcPoint { // using &self to make the trait object-safe
EcPoint::inf(f)
}
fn scalar_mul(&self, pt: &EcPoint, multiplier: &BigUint) -> EcPoint {
let mut n = multiplier.clone();
let mut res = EcPoint::inf();
let mut res = EcPoint::inf(&pt.x.f);
let mut pt_pow_n = pt.clone();
let one = BigUint::one();

View File

@@ -17,33 +17,33 @@ pub struct EcCyclicAdditiveGroup {
impl EcCyclicAdditiveGroup {
pub fn new(
f: Field,
f: &Field,
g: EcPoint,
n: &impl ToBigUint,
ops: Box<dyn EcAdditiveGroupOps>,
) -> Self {
let n = n.to_biguint();
let f_n = Field::new(&n);
EcCyclicAdditiveGroup { f, f_n, g, n, ops }
EcCyclicAdditiveGroup { f: f.clone(), f_n, g, n, ops }
}
pub fn secp256k1() -> EcCyclicAdditiveGroup {
// base prime field
let base_field_order = BigUint::parse_bytes(b"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", 16).unwrap();
let f = Field::new(&base_field_order);
let f = &Field::new(&base_field_order);
// base point of the cyclic group
let gx = BigUint::parse_bytes(b"79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", 16).unwrap();
let gy = BigUint::parse_bytes(b"483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", 16).unwrap();
let g = EcPoint::new(
&FieldElem::new(&f, &gx),
&FieldElem::new(&f, &gy),
&FieldElem::new(f, &gx),
&FieldElem::new(f, &gy),
);
// order of the base point
let n = BigUint::parse_bytes(b"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 16).unwrap();
let ops = Box::new(JacobianAddOps::new());
let ops = Box::new(JacobianAddOps::new(f));
EcCyclicAdditiveGroup::new(f, g, &n, ops)
}

View File

@@ -29,11 +29,10 @@ impl<'a> From<EcPointWithOps<'a>> for EcPoint {
}
impl EcPoint {
pub fn inf() -> Self {
let f = Field::new(&1u8);
pub fn inf(f: &Field) -> Self {
EcPoint {
x: FieldElem::new(&f, &0u8),
y: FieldElem::new(&f, &0u8),
x: FieldElem::new(f, &0u8),
y: FieldElem::new(f, &0u8),
is_inf: true,
}
}

View File

@@ -131,8 +131,8 @@ mod tests {
// TODO create separate tests for not-on-curve and pub_key-not-order-n cases
fn sign_verify_bad_pub_key() {
let group = EcCyclicAdditiveGroup::secp256k1();
let curve = WeierstrassEq::secp256k1(group.f.clone());
let ops = Box::new(JacobianAddOps::new());
let curve = WeierstrassEq::secp256k1(&group.f);
let ops = Box::new(JacobianAddOps::new(&group.f));
let hasher = Box::new(Sha256());
let mut ecdsa = Ecdsa::new(group, curve, ops.clone(), hasher);
@@ -155,8 +155,9 @@ mod tests {
#[test]
fn sign_verify_inf_pub_key() {
let group = EcCyclicAdditiveGroup::secp256k1();
let curve = WeierstrassEq::secp256k1(group.f.clone());
let ops = Box::new(JacobianAddOps::new());
let f = &group.f.clone();
let curve = WeierstrassEq::secp256k1(f);
let ops = Box::new(JacobianAddOps::new(f));
let hasher = Box::new(Sha256());
let mut ecdsa = Ecdsa::new(group, curve, ops, hasher);
@@ -167,7 +168,7 @@ mod tests {
let sig = ecdsa.sign(&priv_key, &message).unwrap();
// use inf public key for verifying
let pub_key = EcPoint::inf();
let pub_key = EcPoint::inf(f);
let is_verified = ecdsa.verify(&sig, &pub_key, &message);
assert_eq!(is_verified, false);
}
@@ -175,8 +176,8 @@ mod tests {
#[test]
fn sign_verify_sig_r_out_of_range() {
let group = EcCyclicAdditiveGroup::secp256k1();
let curve = WeierstrassEq::secp256k1(group.f.clone());
let ops = Box::new(JacobianAddOps::new());
let curve = WeierstrassEq::secp256k1(&group.f);
let ops = Box::new(JacobianAddOps::new(&group.f));
let hasher = Box::new(Sha256());
let mut ecdsa = Ecdsa::new(group, curve, ops.clone(), hasher);
@@ -208,8 +209,8 @@ mod tests {
#[test]
fn sign_verify_sig_s_out_of_range() {
let group = EcCyclicAdditiveGroup::secp256k1();
let curve = WeierstrassEq::secp256k1(group.f.clone());
let ops = Box::new(JacobianAddOps::new());
let curve = WeierstrassEq::secp256k1(&group.f);
let ops = Box::new(JacobianAddOps::new(&group.f));
let hasher = Box::new(Sha256());
let mut ecdsa = Ecdsa::new(group, curve, ops.clone(), hasher);
@@ -241,8 +242,8 @@ mod tests {
#[test]
fn sign_verify_all_good() {
let group = EcCyclicAdditiveGroup::secp256k1();
let curve = WeierstrassEq::secp256k1(group.f.clone());
let ops = Box::new(JacobianAddOps::new());
let curve = WeierstrassEq::secp256k1(&group.f);
let ops = Box::new(JacobianAddOps::new(&group.f));
let hasher = Box::new(Sha256());
let mut ecdsa = Ecdsa::new(group, curve, ops, hasher);
@@ -261,8 +262,8 @@ mod tests {
#[test]
fn sign_verify_bad_priv_key() {
let group = EcCyclicAdditiveGroup::secp256k1();
let curve = WeierstrassEq::secp256k1(group.f.clone());
let ops = Box::new(JacobianAddOps::new());
let curve = WeierstrassEq::secp256k1(&group.f);
let ops = Box::new(JacobianAddOps::new(&group.f));
let hasher = Box::new(Sha256());
let mut ecdsa = Ecdsa::new(group, curve, ops.clone(), hasher);
@@ -283,8 +284,8 @@ mod tests {
#[test]
fn sign_verify_different_message() {
let group = EcCyclicAdditiveGroup::secp256k1();
let curve = WeierstrassEq::secp256k1(group.f.clone());
let ops = Box::new(JacobianAddOps::new());
let curve = WeierstrassEq::secp256k1(&group.f);
let ops = Box::new(JacobianAddOps::new(&group.f));
let hasher = Box::new(Sha256());
let mut ecdsa = Ecdsa::new(group, curve, ops.clone(), hasher);

View File

@@ -40,14 +40,21 @@ impl EcAdditiveGroupOps for Ed25519Sha512 {
// Edwards Addition Law
// (x1,y1) + (x2,y2) = ((x1y2 + x2y1) / (1 + d x1x2 y1y2), (y1y2 + x1x2) / (1 - d x1x2 y1y2))
fn add(&self, p1: &EcPoint, p2: &EcPoint) -> EcPoint {
let x1y2 = &p1.x * &p2.y;
let x2y1 = &p2.x * &p1.y;
let x1x2y1y2 = &x1y2 * &x2y1;
let y1y2 = &p1.y * &p2.y;
let x1x2 = &p1.x * &p2.x;
let x = (x1y2 + x2y1) / (self.f.elem(&1u8) + (&self.d * &x1x2y1y2));
let y = (y1y2 + x1x2) / (self.f.elem(&1u8) - (&self.d * x1x2y1y2));
EcPoint::new(&x, &y)
if p1.is_inf {
p2.clone()
}
else if p2.is_inf {
p1.clone()
} else {
let x1y2 = &p1.x * &p2.y;
let x2y1 = &p2.x * &p1.y;
let x1x2y1y2 = &x1y2 * &x2y1;
let y1y2 = &p1.y * &p2.y;
let x1x2 = &p1.x * &p2.x;
let x = (x1y2 + x2y1) / (self.f.elem(&1u8) + (&self.d * &x1x2y1y2));
let y = (y1y2 + x1x2) / (self.f.elem(&1u8) - (&self.d * x1x2y1y2));
EcPoint::new(&x, &y)
}
}
fn inv(&self, _p: &EcPoint) -> EcPoint {
@@ -235,6 +242,30 @@ impl Ed25519Sha512 {
mod tests {
use super::*;
#[test]
fn adding_inf_test() {
let ed25519 = Ed25519Sha512::new();
let inf = &EcPoint::inf(&ed25519.f);
let one = &ed25519.f.elem(&1u8);
let non_inf = &EcPoint::new(one, one);
{
let pt = ed25519.add(inf, inf);
assert!(pt.is_inf);
}
{
let pt = ed25519.add(non_inf, inf);
assert!(&pt == non_inf);
}
{
let pt = ed25519.add(inf, non_inf);
assert!(&pt == non_inf);
}
{
let pt = ed25519.add(non_inf, non_inf);
assert!(pt.is_inf == false);
}
}
fn run_rfc8032_test(prv_key: &str, exp_pub_key: &str, msg: &[u8], exp_sig: &str) {
let ed25519 = Ed25519Sha512::new();

View File

@@ -265,7 +265,7 @@ mod tests {
#[test]
fn ec_point1_eq() {
let group = EcCyclicAdditiveGroup::secp256k1();
let ops = JacobianAddOps::new();
let ops = JacobianAddOps::new(&group.f);
let p = EcPointWithOps((&ops, group.g));
assert!(p == p);
@@ -277,7 +277,7 @@ mod tests {
#[test]
fn ec_point1_times_field_elem() {
let group = EcCyclicAdditiveGroup::secp256k1();
let ops = JacobianAddOps::new();
let ops = JacobianAddOps::new(&group.f);
let p = group.g;
let p = EcPointWithOps((&ops, p));
@@ -292,7 +292,7 @@ mod tests {
#[test]
fn ec_point1_plus_ec_point1() {
let group = EcCyclicAdditiveGroup::secp256k1();
let ops = JacobianAddOps::new();
let ops = JacobianAddOps::new(&group.f);
let g = group.g;
let g = EcPointWithOps((&ops, g));
@@ -310,7 +310,7 @@ mod tests {
#[test]
fn ec_points_eq() {
let group = EcCyclicAdditiveGroup::secp256k1();
let ops = JacobianAddOps::new();
let ops = JacobianAddOps::new(&group.f);
let p1 = EcPointWithOps((&ops, group.g));
let p2 = &p1 * group.f.elem(&2u8);
@@ -327,7 +327,7 @@ mod tests {
#[test]
fn ec_points_index() {
let group = EcCyclicAdditiveGroup::secp256k1();
let ops = JacobianAddOps::new();
let ops = JacobianAddOps::new(&group.f);
let p1 = EcPointWithOps((&ops, group.g));
let p2 = &p1 * group.f.elem(&2u8);
@@ -343,7 +343,7 @@ mod tests {
#[test]
fn ec_points_from() {
let group = EcCyclicAdditiveGroup::secp256k1();
let ops = JacobianAddOps::new();
let ops = JacobianAddOps::new(&group.f);
let p1 = EcPointWithOps((&ops, group.g));
let p2 = &p1 * group.f.elem(&2u8);
@@ -383,7 +383,7 @@ mod tests {
#[test]
fn ec_points_to() {
let group = EcCyclicAdditiveGroup::secp256k1();
let ops = JacobianAddOps::new();
let ops = JacobianAddOps::new(&group.f);
let p1 = EcPointWithOps((&ops, group.g));
let p2 = &p1 * group.f.elem(&2u8);
@@ -426,7 +426,7 @@ mod tests {
#[test]
fn ec_points_sum() {
let group = EcCyclicAdditiveGroup::secp256k1();
let ops = JacobianAddOps::new();
let ops = JacobianAddOps::new(&group.f);
let p1 = EcPointWithOps((&ops, group.g));
let p2 = &p1 * group.f.elem(&2u8);
@@ -443,7 +443,7 @@ mod tests {
#[test]
fn ec_points_times_field_elem() {
let group = EcCyclicAdditiveGroup::secp256k1();
let ops = JacobianAddOps::new();
let ops = JacobianAddOps::new(&group.f);
let p1 = EcPointWithOps((&ops, group.g));
let p2 = &p1 * group.f.elem(&2u8);
@@ -458,7 +458,7 @@ mod tests {
#[test]
fn ec_points_plus_ec_points() {
let group = EcCyclicAdditiveGroup::secp256k1();
let ops = JacobianAddOps::new();
let ops = JacobianAddOps::new(&group.f);
let p1 = EcPointWithOps((&ops, group.g));
let p2 = &p1 * group.f.elem(&2u8);
@@ -476,11 +476,11 @@ mod tests {
#[test]
fn ec_points_minus_ec_points() {
let group = EcCyclicAdditiveGroup::secp256k1();
let ops = JacobianAddOps::new();
let ops = JacobianAddOps::new(&group.f);
let g = &EcPointWithOps((&ops, group.g));
let g2 = g * group.f.elem(&2u8);
let zero = &EcPointWithOps((&ops, ops.get_point_at_infinity()));
let zero = &EcPointWithOps((&ops, ops.get_point_at_infinity(&group.f)));
let g2s = EcPointsWithOps((&ops, vec![g2.clone(), g2.clone()]));
let zeros = EcPointsWithOps((&ops, vec![zero.clone(), zero.clone()]));
@@ -490,4 +490,4 @@ mod tests {
assert!(act == exp);
}
}
}

View File

@@ -1,17 +1,19 @@
use crate::building_block::{
ec_additive_group_ops::EcAdditiveGroupOps,
ec_point::EcPoint,
field::FieldElem,
field::{Field, FieldElem},
};
use num_bigint::BigUint;
use num_traits::identities::{One, Zero};
#[derive(Clone)]
pub struct AffineAddOps;
pub struct AffineAddOps {
f: Field,
}
impl AffineAddOps {
pub fn new() -> Self {
AffineAddOps {}
pub fn new(f: &Field) -> Self {
AffineAddOps { f: f.clone() }
}
}
@@ -19,17 +21,17 @@ impl EcAdditiveGroupOps for AffineAddOps {
// TODO check if all points are based on the same field
fn add(&self, p1: &EcPoint, p2: &EcPoint) -> EcPoint {
if p1.is_inf && p2.is_inf { // inf + inf is inf
EcPoint::inf()
EcPoint::inf(&self.f)
} else if p1.is_inf { // adding p2 to inf is p2
p2.clone()
} else if p2.is_inf { // adding p1 to inf is p1
p1.clone()
} else if p1.x == p2.x && p1.y != p2.y { // if line through p1 and p2 is vertical line
EcPoint::inf()
EcPoint::inf(&self.f)
} else if p1.x == p2.x && p1.y == p2.y { // if adding the same point
// special case: if y == 0, the tangent line is vertical
if p1.y.n == BigUint::zero() || p2.y.n == BigUint::zero() {
return EcPoint::inf();
return EcPoint::inf(&self.f);
}
// differentiate y^2 = x^3 + Ax + B w/ implicit differentiation
// d/dx(y^2) = d/dx(x^3 + Ax + B)
@@ -162,11 +164,13 @@ impl JacobianPoint {
}
#[derive(Clone)]
pub struct JacobianAddOps;
pub struct JacobianAddOps {
f: Field,
}
impl JacobianAddOps {
pub fn new() -> Self {
JacobianAddOps {}
pub fn new(f: &Field) -> Self {
JacobianAddOps { f: f.clone() }
}
}
@@ -174,17 +178,17 @@ impl EcAdditiveGroupOps for JacobianAddOps {
// TODO check if all points are based on the same field
fn add(&self, p1: &EcPoint, p2: &EcPoint) -> EcPoint {
if p1.is_inf && p2.is_inf { // inf + inf is inf
EcPoint::inf()
EcPoint::inf(&self.f)
} else if p1.is_inf { // adding p2 to inf is p2
p2.clone()
} else if p2.is_inf { // adding p1 to inf is p1
p1.clone()
} else if p1.x == p2.x && p1.y != p2.y { // if line through p1 and p2 is vertical line
EcPoint::inf()
EcPoint::inf(&self.f)
} else if p1.x == p2.x && p1.y == p2.y { // if adding the same point
// special case: if y == 0, the tangent line is vertical
if p1.y.n == BigUint::zero() || p2.y.n == BigUint::zero() {
return EcPoint::inf();
return EcPoint::inf(&self.f);
}
// formula described in: http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#doubling-dbl-2009-l
@@ -249,15 +253,18 @@ mod tests {
weierstrass_eq::WeierstrassEq,
};
fn get_ops_list<'a>() -> Vec<Box<dyn EcAdditiveGroupOps>> {
vec![Box::new(AffineAddOps::new()), Box::new(JacobianAddOps::new())]
fn get_ops_list<'a>(f: &Field) -> Vec<Box<dyn EcAdditiveGroupOps>> {
vec![
Box::new(AffineAddOps::new(f)),
Box::new(JacobianAddOps::new(f)),
]
}
#[test]
fn add_same_point() {
let group = EcCyclicAdditiveGroup::secp256k1();
let g = &group.g;
for ops in get_ops_list() {
for ops in get_ops_list(&group.f) {
let g2 = ops.add(g, g);
let exp_x = BigUint::parse_bytes(b"89565891926547004231252920425935692360644145829622209833684329913297188986597", 10).unwrap();
let exp_y = BigUint::parse_bytes(b"12158399299693830322967808612713398636155367887041628176798871954788371653930", 10).unwrap();
@@ -275,10 +282,10 @@ mod tests {
fn add_vertical_line() {
let group = EcCyclicAdditiveGroup::secp256k1();
let g = &group.g;
for ops in get_ops_list() {
for ops in get_ops_list(&group.f) {
let a = g.clone();
let b = EcPoint::new(&a.x, &-&a.y);
let exp = EcPoint::inf();
let exp = EcPoint::inf(&group.f);
let act = ops.add(&a, &b);
assert_eq!(act, exp);
}
@@ -288,8 +295,8 @@ mod tests {
fn add_inf_and_affine() {
let group = EcCyclicAdditiveGroup::secp256k1();
let g = &group.g;
for ops in get_ops_list() {
let inf = EcPoint::inf();
for ops in get_ops_list(&group.f) {
let inf = EcPoint::inf(&group.f);
let inf_plus_g = ops.add(g, &inf);
assert_eq!(g, &inf_plus_g);
}
@@ -299,8 +306,8 @@ mod tests {
fn add_affine_and_inf() {
let group = EcCyclicAdditiveGroup::secp256k1();
let g = &group.g;
for ops in get_ops_list() {
let inf = EcPoint::inf();
for ops in get_ops_list(&group.f) {
let inf = EcPoint::inf(&group.f);
let g_plus_inf = ops.add(&inf, g);
assert_eq!(g, &g_plus_inf);
}
@@ -308,8 +315,9 @@ mod tests {
#[test]
fn add_inf_and_inf() {
let ops = AffineAddOps::new();
let inf = EcPoint::inf();
let group = EcCyclicAdditiveGroup::secp256k1();
let ops = AffineAddOps::new(&group.f);
let inf = EcPoint::inf(&group.f);
let inf_plus_inf = ops.add(&inf, &inf);
assert_eq!(inf_plus_inf, inf);
}
@@ -372,9 +380,9 @@ mod tests {
#[test]
fn scalar_mul_smaller_nums() {
let group = EcCyclicAdditiveGroup::secp256k1();
let e = WeierstrassEq::secp256k1(group.f);
let e = WeierstrassEq::secp256k1(&group.f);
let g = &group.g;
for ops in get_ops_list() {
for ops in get_ops_list(&group.f) {
let gs = get_g_multiples(&e);
for n in 1usize..=10 {
@@ -422,9 +430,9 @@ mod tests {
use std::time::Instant;
let group = EcCyclicAdditiveGroup::secp256k1();
let e = WeierstrassEq::secp256k1(group.f);
let e = WeierstrassEq::secp256k1(&group.f);
let g = &group.g;
for ops in get_ops_list() {
for ops in get_ops_list(&group.f) {
for t in &test_cases {
let k = BigUint::parse_bytes(t.k, 16).unwrap();
let x = BigUint::parse_bytes(t.x, 16).unwrap();
@@ -461,9 +469,9 @@ mod tests {
y: b"8B71E83545FC2B5872589F99D948C03108D36797C4DE363EBD3FF6A9E1A95B10",
};
let f = EcCyclicAdditiveGroup::secp256k1().f;
let f = &EcCyclicAdditiveGroup::secp256k1().f;
let e = WeierstrassEq::secp256k1(f);
for ops in get_ops_list() {
for ops in get_ops_list(f) {
let gs = get_g_multiples(&e);
let test_cases = [

View File

@@ -17,23 +17,23 @@ pub struct WeierstrassEq {
impl WeierstrassEq {
pub fn new(
f: Field,
f: &Field,
a1: BigUint,
a2: BigUint,
a3: BigUint,
a4: BigUint,
a6: BigUint,
) -> Result<Self, String> {
let a1 = FieldElem::new(&f, &a1);
let a2 = FieldElem::new(&f, &a2);
let a3 = FieldElem::new(&f, &a3);
let a4 = FieldElem::new(&f, &a4);
let a6 = FieldElem::new(&f, &a6);
let a1 = FieldElem::new(f, &a1);
let a2 = FieldElem::new(f, &a2);
let a3 = FieldElem::new(f, &a3);
let a4 = FieldElem::new(f, &a4);
let a6 = FieldElem::new(f, &a6);
Ok(WeierstrassEq { f, a1, a2, a3, a4, a6 })
Ok(WeierstrassEq { f: f.clone(), a1, a2, a3, a4, a6 })
}
pub fn secp256k1(f: Field) -> WeierstrassEq {
pub fn secp256k1(f: &Field) -> WeierstrassEq {
let a1 = BigUint::from(0u8);
let a2 = BigUint::from(0u8);
let a3 = BigUint::from(0u8);

View File

@@ -193,7 +193,7 @@ mod tests {
#[test]
fn test_gg_ones_times_z() {
let group = EcCyclicAdditiveGroup::secp256k1();
let ops = JacobianAddOps::new();
let ops = JacobianAddOps::new(&group.f);
let bp: Bulletproofs<2> = Bulletproofs::new(group, &ops);
let n = 2;
@@ -213,7 +213,7 @@ mod tests {
#[test]
fn test_offset_by_negation() {
let group = EcCyclicAdditiveGroup::secp256k1();
let ops = JacobianAddOps::new();
let ops = JacobianAddOps::new(&group.f);
let bp: Bulletproofs<2> = Bulletproofs::new(group, &ops);
let f_n = &bp.group.f_n;
{
@@ -241,7 +241,7 @@ mod tests {
#[allow(non_snake_case)]
fn test_base_point_field_elem_mul() {
let group = EcCyclicAdditiveGroup::secp256k1();
let ops = JacobianAddOps::new();
let ops = JacobianAddOps::new(&group.f);
let bp: Bulletproofs<2> = Bulletproofs::new(group, &ops);
let f_n = &bp.group.f_n;
@@ -278,7 +278,7 @@ mod tests {
#[allow(non_snake_case)]
fn test_mul_field_elem_above_order() {
let group = EcCyclicAdditiveGroup::secp256k1();
let ops = JacobianAddOps::new();
let ops = JacobianAddOps::new(&group.f);
let bp: Bulletproofs<2> = Bulletproofs::new(group, &ops);
let f_n = &bp.group.f_n;
@@ -301,7 +301,7 @@ mod tests {
#[allow(non_snake_case)]
fn test_range_proof() {
let group = EcCyclicAdditiveGroup::secp256k1();
let ops = JacobianAddOps::new();
let ops = JacobianAddOps::new(&group.f);
let bp: Bulletproofs<2> = Bulletproofs::new(group, &ops);
let f_n = &bp.group.f_n;