feat: clean up range proof constructor
This commit is contained in:
parent
826c3bee4a
commit
e1d3883893
|
@ -40,45 +40,38 @@ pub struct RangeProof {
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
impl RangeProof {
|
impl RangeProof {
|
||||||
|
/// Create an aggregated range proof.
|
||||||
|
///
|
||||||
|
/// The proof is created with respect to a vector of Pedersen commitments C_1, ..., C_m. The
|
||||||
|
/// method itself does not take in these commitments, but the values associated with the commitments:
|
||||||
|
/// - vector of committed amounts v_1, ..., v_m represented as u64
|
||||||
|
/// - bit-lengths of the committed amounts
|
||||||
|
/// - Pedersen openings for each commitments
|
||||||
|
///
|
||||||
|
/// The sum of the bit-lengths of the commitments amounts must be a power-of-two
|
||||||
#[allow(clippy::many_single_char_names)]
|
#[allow(clippy::many_single_char_names)]
|
||||||
#[cfg(not(target_arch = "bpf"))]
|
#[cfg(not(target_arch = "bpf"))]
|
||||||
pub fn create(
|
pub fn new(
|
||||||
amounts: Vec<u64>,
|
amounts: Vec<u64>,
|
||||||
bit_lengths: Vec<usize>,
|
bit_lengths: Vec<usize>,
|
||||||
opens: Vec<&PedersenOpening>,
|
openings: Vec<&PedersenOpening>,
|
||||||
transcript: &mut Transcript,
|
transcript: &mut Transcript,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let t_1_blinding = PedersenOpening::random(&mut OsRng);
|
// amounts, bit-lengths, openings must be same length vectors
|
||||||
let t_2_blinding = PedersenOpening::random(&mut OsRng);
|
let m = amounts.len();
|
||||||
|
assert_eq!(bit_lengths.len(), m);
|
||||||
|
assert_eq!(openings.len(), m);
|
||||||
|
|
||||||
Self::create_with(
|
// total vector dimension to compute the ultimate inner product proof for
|
||||||
amounts,
|
let nm: usize = bit_lengths.iter().sum();
|
||||||
bit_lengths,
|
assert!(nm.is_power_of_two());
|
||||||
opens,
|
|
||||||
&t_1_blinding,
|
|
||||||
&t_2_blinding,
|
|
||||||
transcript,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::many_single_char_names)]
|
// TODO: precompute generators
|
||||||
#[cfg(not(target_arch = "bpf"))]
|
|
||||||
pub fn create_with(
|
|
||||||
amounts: Vec<u64>,
|
|
||||||
bit_lengths: Vec<usize>,
|
|
||||||
opens: Vec<&PedersenOpening>,
|
|
||||||
t_1_blinding: &PedersenOpening,
|
|
||||||
t_2_blinding: &PedersenOpening,
|
|
||||||
transcript: &mut Transcript,
|
|
||||||
) -> Self {
|
|
||||||
let nm = bit_lengths.iter().sum();
|
|
||||||
|
|
||||||
// Computing the generators online for now. It should ultimately be precomputed.
|
|
||||||
let bp_gens = BulletproofGens::new(nm);
|
let bp_gens = BulletproofGens::new(nm);
|
||||||
let G = PedersenBase::default().G;
|
let G = PedersenBase::default().G;
|
||||||
let H = PedersenBase::default().H;
|
let H = PedersenBase::default().H;
|
||||||
|
|
||||||
// bit-decompose values and commit to the bits
|
// bit-decompose values and generate their Pedersen vector commitment
|
||||||
let a_blinding = Scalar::random(&mut OsRng);
|
let a_blinding = Scalar::random(&mut OsRng);
|
||||||
let mut A = a_blinding * H;
|
let mut A = a_blinding * H;
|
||||||
|
|
||||||
|
@ -92,31 +85,40 @@ impl RangeProof {
|
||||||
A += point;
|
A += point;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let A = A.compress();
|
||||||
|
|
||||||
// generate blinding factors and commit as vectors
|
// generate blinding factors and generate their Pedersen vector commitment
|
||||||
let s_blinding = Scalar::random(&mut OsRng);
|
|
||||||
|
|
||||||
let s_L: Vec<Scalar> = (0..nm).map(|_| Scalar::random(&mut OsRng)).collect();
|
let s_L: Vec<Scalar> = (0..nm).map(|_| Scalar::random(&mut OsRng)).collect();
|
||||||
let s_R: Vec<Scalar> = (0..nm).map(|_| Scalar::random(&mut OsRng)).collect();
|
let s_R: Vec<Scalar> = (0..nm).map(|_| Scalar::random(&mut OsRng)).collect();
|
||||||
|
|
||||||
|
// generate blinding factor for Pedersen commitment; `s_blinding` should not to be confused
|
||||||
|
// with blinding factors for the actual inner product vector
|
||||||
|
let s_blinding = Scalar::random(&mut OsRng);
|
||||||
|
|
||||||
let S = RistrettoPoint::multiscalar_mul(
|
let S = RistrettoPoint::multiscalar_mul(
|
||||||
iter::once(&s_blinding).chain(s_L.iter()).chain(s_R.iter()),
|
iter::once(&s_blinding).chain(s_L.iter()).chain(s_R.iter()),
|
||||||
iter::once(&H).chain(bp_gens.G(nm)).chain(bp_gens.H(nm)),
|
iter::once(&H).chain(bp_gens.G(nm)).chain(bp_gens.H(nm)),
|
||||||
);
|
).compress();
|
||||||
|
|
||||||
transcript.append_point(b"A", &A.compress());
|
// add the Pedersen vector commitments to the transcript (send the commitments to the verifier)
|
||||||
transcript.append_point(b"S", &S.compress());
|
transcript.append_point(b"A", &A);
|
||||||
|
transcript.append_point(b"S", &S);
|
||||||
|
|
||||||
// commit to T1 and T2
|
// derive challenge scalars from the transcript (receive challenge from the verifier): `y`
|
||||||
|
// and `z` used for merge multiple inner product relations into one single inner product
|
||||||
let y = transcript.challenge_scalar(b"y");
|
let y = transcript.challenge_scalar(b"y");
|
||||||
let z = transcript.challenge_scalar(b"z");
|
let z = transcript.challenge_scalar(b"z");
|
||||||
|
|
||||||
|
// define blinded vectors:
|
||||||
|
// - l(x) = (a_L - z*1) + s_L*x
|
||||||
|
// - r(x) = (y^n * (a_R + z*1) + [z^2*2^n | z^3*2^n | ... | z^m*2^n]) + y^n * s_R*x
|
||||||
let mut l_poly = util::VecPoly1::zero(nm);
|
let mut l_poly = util::VecPoly1::zero(nm);
|
||||||
let mut r_poly = util::VecPoly1::zero(nm);
|
let mut r_poly = util::VecPoly1::zero(nm);
|
||||||
|
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
let mut exp_z = z * z;
|
let mut exp_z = z * z;
|
||||||
let mut exp_y = Scalar::one();
|
let mut exp_y = Scalar::one();
|
||||||
|
|
||||||
for (amount_i, n_i) in amounts.iter().zip(bit_lengths.iter()) {
|
for (amount_i, n_i) in amounts.iter().zip(bit_lengths.iter()) {
|
||||||
let mut exp_2 = Scalar::one();
|
let mut exp_2 = Scalar::one();
|
||||||
|
|
||||||
|
@ -136,50 +138,54 @@ impl RangeProof {
|
||||||
exp_z *= z;
|
exp_z *= z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// define t(x) = <l(x), r(x)> = t_0 + t_1*x + t_2*x
|
||||||
let t_poly = l_poly.inner_product(&r_poly);
|
let t_poly = l_poly.inner_product(&r_poly);
|
||||||
|
|
||||||
let T_1 = Pedersen::with(t_poly.1, t_1_blinding)
|
// generate Pedersen commitment for the coefficients t_1 and t_2
|
||||||
.get_point()
|
let (T_1, t_1_blinding) = Pedersen::new(t_poly.1);
|
||||||
.compress();
|
let (T_2, t_2_blinding) = Pedersen::new(t_poly.2);
|
||||||
let T_2 = Pedersen::with(t_poly.2, t_2_blinding)
|
|
||||||
.get_point()
|
let T_1 = T_1.get_point().compress();
|
||||||
.compress();
|
let T_2 = T_2.get_point().compress();
|
||||||
|
|
||||||
transcript.append_point(b"T_1", &T_1);
|
transcript.append_point(b"T_1", &T_1);
|
||||||
transcript.append_point(b"T_2", &T_2);
|
transcript.append_point(b"T_2", &T_2);
|
||||||
|
|
||||||
|
// evaluate t(x) on challenge x and homomorphically compute the openings for
|
||||||
|
// z^2 * V_1 + z^3 * V_2 + ... + z^{m+1} * V_m + delta(y, z)*G + x*T_1 + x^2*T_2
|
||||||
let x = transcript.challenge_scalar(b"x");
|
let x = transcript.challenge_scalar(b"x");
|
||||||
|
|
||||||
let mut agg_open = Scalar::zero();
|
let mut agg_opening = Scalar::zero();
|
||||||
let mut exp_z = z * z;
|
let mut exp_z = z;
|
||||||
for open in opens {
|
for opening in openings {
|
||||||
agg_open += exp_z * open.get_scalar();
|
|
||||||
exp_z *= z;
|
exp_z *= z;
|
||||||
|
agg_opening += exp_z * opening.get_scalar();
|
||||||
}
|
}
|
||||||
|
|
||||||
let t_blinding_poly = util::Poly2(
|
let t_blinding_poly = util::Poly2(
|
||||||
agg_open,
|
agg_opening,
|
||||||
t_1_blinding.get_scalar(),
|
t_1_blinding.get_scalar(),
|
||||||
t_2_blinding.get_scalar(),
|
t_2_blinding.get_scalar(),
|
||||||
);
|
);
|
||||||
|
|
||||||
// compute t_x
|
|
||||||
let t_x = t_poly.eval(x);
|
let t_x = t_poly.eval(x);
|
||||||
let t_x_blinding = t_blinding_poly.eval(x);
|
let t_x_blinding = t_blinding_poly.eval(x);
|
||||||
|
|
||||||
|
transcript.append_scalar(b"t_x", &t_x);
|
||||||
|
transcript.append_scalar(b"t_x_blinding", &t_x_blinding);
|
||||||
|
|
||||||
|
// homomorphically compuate the openings for A + x*S
|
||||||
let e_blinding = a_blinding + s_blinding * x;
|
let e_blinding = a_blinding + s_blinding * x;
|
||||||
let l_vec = l_poly.eval(x);
|
let l_vec = l_poly.eval(x);
|
||||||
let r_vec = r_poly.eval(x);
|
let r_vec = r_poly.eval(x);
|
||||||
|
|
||||||
transcript.append_scalar(b"t_x", &t_x);
|
|
||||||
transcript.append_scalar(b"t_x_blinding", &t_x_blinding);
|
|
||||||
transcript.append_scalar(b"e_blinding", &e_blinding);
|
transcript.append_scalar(b"e_blinding", &e_blinding);
|
||||||
|
|
||||||
|
// compute the inner product argument on the commitment:
|
||||||
|
// P = <l(x), G> + <r(x), H'> + <l(x), r(x)>*Q
|
||||||
let w = transcript.challenge_scalar(b"w");
|
let w = transcript.challenge_scalar(b"w");
|
||||||
let Q = w * G;
|
let Q = w * G;
|
||||||
|
|
||||||
transcript.challenge_scalar(b"c");
|
|
||||||
|
|
||||||
let G_factors: Vec<Scalar> = iter::repeat(Scalar::one()).take(nm).collect();
|
let G_factors: Vec<Scalar> = iter::repeat(Scalar::one()).take(nm).collect();
|
||||||
let H_factors: Vec<Scalar> = util::exp_iter(y.invert()).take(nm).collect();
|
let H_factors: Vec<Scalar> = util::exp_iter(y.invert()).take(nm).collect();
|
||||||
|
|
||||||
|
@ -194,9 +200,12 @@ impl RangeProof {
|
||||||
transcript,
|
transcript,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// generate challenge `c` for consistency with the verifier's transcript
|
||||||
|
transcript.challenge_scalar(b"c");
|
||||||
|
|
||||||
RangeProof {
|
RangeProof {
|
||||||
A: A.compress(),
|
A,
|
||||||
S: S.compress(),
|
S,
|
||||||
T_1,
|
T_1,
|
||||||
T_2,
|
T_2,
|
||||||
t_x,
|
t_x,
|
||||||
|
|
Loading…
Reference in New Issue