Skip to content

Commit

Permalink
Add most of the prove function
Browse files Browse the repository at this point in the history
  • Loading branch information
kayabaNerve committed May 3, 2024
1 parent e169471 commit 8ab716c
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 27 deletions.
2 changes: 1 addition & 1 deletion crypto/fcmps/src/gadgets/interactive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ impl<C: Ciphersuite> Circuit<C> {
claim: ClaimedPointWithDlog<C::F>,
) -> OnCurve {
let ClaimedPointWithDlog { mut generator, divisor, dlog, point } = claim;
assert_eq!(dlog.len(), <C::F as PrimeField>::CAPACITY.try_into().unwrap());
assert_eq!(dlog.len(), <C::F as PrimeField>::NUM_BITS.try_into().unwrap());

// Ensure this is being safely called
let arg_iter = core::iter::once(&divisor.y).chain(divisor.yx.iter());
Expand Down
162 changes: 136 additions & 26 deletions crypto/fcmps/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@ use rand_core::{RngCore, CryptoRng};
use transcript::Transcript;

use ciphersuite::{
group::ff::{Field, PrimeField, PrimeFieldBits},
group::{
ff::{Field, PrimeField, PrimeFieldBits},
Group,
},
Ciphersuite,
};

use ec_divisors::Poly;
use ec_divisors::{Poly, DivisorCurve, new_divisor};
use generalized_bulletproofs::arithmetic_circuit_proof::ArithmeticCircuitProof;

#[allow(unused)] // TODO
Expand All @@ -31,14 +34,39 @@ pub struct Blinds<F: PrimeFieldBits> {

/// A blind, prepared for usage within the circuit.
#[derive(Clone, PartialEq, Eq, Debug)]
struct PreparedBlind<F: PrimeField> {
struct PreparedBlind<F: PrimeFieldBits> {
bits: Vec<bool>,
divisor: Poly<F>,
}

impl<F: PrimeFieldBits> PreparedBlind<F> {
fn new<C1: Ciphersuite>(blinding_generator: C1::G, blind: C1::F) -> Self
where
C1::G: DivisorCurve<FieldElement = F>,
{
let bits = blind.to_le_bits().into_iter().collect::<Vec<_>>();
assert_eq!(u32::try_from(bits.len()).unwrap(), C1::F::NUM_BITS);

let divisor = {
let mut gen_pow_2 = blinding_generator;
let mut points = vec![];
for bit in &bits {
if *bit {
points.push(gen_pow_2);
}
gen_pow_2 = gen_pow_2.double();
}
points.push(blinding_generator * -blind);
new_divisor::<C1::G>(&points).unwrap()
};

Self { bits, divisor }
}
}

/// The blinds used for an output, prepared for usage within the circuit.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct PreparedBlinds<F: PrimeField> {
pub struct PreparedBlinds<F: PrimeFieldBits> {
o_blind: PreparedBlind<F>,
i_blind: PreparedBlind<F>,
i_blind_blind: PreparedBlind<F>,
Expand All @@ -47,23 +75,10 @@ pub struct PreparedBlinds<F: PrimeField> {

impl<F: PrimeFieldBits> Blinds<F> {
pub fn new<R: RngCore + CryptoRng>(rng: &mut R) -> Self {
let new_blind = |rng: &mut R| -> F {
'outer: loop {
let res = F::random(&mut *rng);
// If this uses more bits than capacity, re-sample
for bit in res.to_le_bits().iter().skip(F::CAPACITY.try_into().unwrap()) {
if *bit {
continue 'outer;
}
}
return res;
}
};

let o_blind = new_blind(&mut *rng);
let i_blind = new_blind(&mut *rng);
let i_blind_blind = new_blind(&mut *rng);
let c_blind = new_blind(&mut *rng);
let o_blind = F::random(&mut *rng);
let i_blind = F::random(&mut *rng);
let i_blind_blind = F::random(&mut *rng);
let c_blind = F::random(&mut *rng);

// o_blind, i_blind, c_blind are used in-circuit as negative
let o_blind = -o_blind;
Expand Down Expand Up @@ -116,6 +131,17 @@ pub struct FcmpParams<C1: Ciphersuite, C2: Ciphersuite> {
initial: CurveSpec<C2::F>,
/// The secondary curve, defined over the initial curve's scalar field.
secondary: CurveSpec<C1::F>,
/// The blinding generator for the vector commitments on the initial curve.
initial_blinding_generator: C1::G,
/// The blinding generator for the vector commitments on the secondary curve.
secondary_blinding_generator: C2::G,
}

#[derive(Clone, PartialEq, Eq, Debug)]
pub struct Branches<C1: Ciphersuite, C2: Ciphersuite> {
leaves: Vec<Output<C1::F>>,
curve_2_layers: Vec<Vec<C2::F>>,
curve_1_layers: Vec<Vec<C1::F>>,
}

/// The full-chain membership proof.
Expand All @@ -125,19 +151,103 @@ pub struct Fcmp<C1: Ciphersuite, C2: Ciphersuite> {
proof_2: ArithmeticCircuitProof<C2>,
proof_2_vcs: Vec<C2::G>,
}
impl<C1: Ciphersuite, C2: Ciphersuite> Fcmp<C1, C2> {
impl<C1: Ciphersuite, C2: Ciphersuite> Fcmp<C1, C2>
where
C1::G: DivisorCurve<FieldElement = C2::F>,
C2::G: DivisorCurve<FieldElement = C1::F>,
{
pub fn prove<R: RngCore + CryptoRng, T: Transcript>(
rng: &mut R,
transcript: &mut T,
params: &FcmpParams<C1, C2>,
tree_root: TreeRoot<C1, C2>,
depth: u32,
tree: Tree<C1, C2>,
output: Output<C1::F>,
blinds: PreparedBlinds<C1::F>,
output_blinds: PreparedBlinds<C1::F>,
mut branches: Branches<C1, C2>,
) -> Self {
// Assert the depth is greater than or equal to two, and we'll actually use both proofs
assert!(tree.depth >= 2);
// If depth = 1, there's one layer after the leaves
// That makes the tree root a C1 point
assert_eq!(depth % 2, u32::from(u8::from(matches!(tree_root, TreeRoot::C1(_)))));
assert_eq!(tree.depth % 2, u32::from(u8::from(matches!(tree.root, TreeRoot::C1(_)))));

// Re-format the leaves into the expected branch format
let mut branches_1 = vec![vec![]];
for leaf in branches.leaves {
branches_1[0].extend(&[leaf.O.0, leaf.I.0, leaf.I.1, leaf.C.0]);
}

// Append the rest of the branches
let branches_2 = branches.curve_2_layers;
branches_1.append(&mut branches.curve_1_layers);

// Accumulate a blind into a witness vector
fn accum_blind<C: Ciphersuite>(witness: &mut Vec<C::F>, prepared_blind: PreparedBlind<C::F>) {
// Bits
assert_eq!(prepared_blind.bits.len(), usize::try_from(C::F::NUM_BITS).unwrap());
for bit in &prepared_blind.bits {
witness.push(if *bit { C::F::ONE } else { C::F::ZERO });
}

// Divisor y
witness.push(*prepared_blind.divisor.y_coefficients.first().unwrap_or(&C::F::ZERO));

// Divisor yx
// We have `(p / 2) - 2` yx coeffs, where p is the amount of points
let p = prepared_blind.bits.len() + 1;
let empty_vec = vec![];
let yx = prepared_blind.divisor.yx_coefficients.first().unwrap_or(&empty_vec);
for i in 0 .. (p / 2).saturating_sub(2) {
witness.push(*yx.get(i).unwrap_or(&C::F::ZERO));
}

// Divisor x
// We have `p / 2` x coeffs
assert_eq!(prepared_blind.divisor.x_coefficients[0], C::F::ONE);
// Transcript from 1 given we expect a normalization of the first coefficient
for i in 1 .. (p / 2) {
witness.push(*prepared_blind.divisor.x_coefficients.get(i).unwrap_or(&C::F::ZERO));
}

// Divisor 0
witness.push(prepared_blind.divisor.zero_coefficient);
}

// Decide blinds for each branch
let mut branches_1_blinds = vec![];
let mut branches_1_blinds_prepared = vec![];
for _ in 0 .. branches_1.len() {
let blind = C1::F::random(&mut *rng);
branches_1_blinds.push(blind);
branches_1_blinds_prepared
.push(PreparedBlind::<_>::new::<C1>(params.initial_blinding_generator, blind));
}

let mut branches_2_blinds = vec![];
let mut branches_2_blinds_prepared = vec![];
for _ in 0 .. branches_2.len() {
let blind = C2::F::random(&mut *rng);
branches_2_blinds.push(blind);
branches_2_blinds_prepared
.push(PreparedBlind::<_>::new::<C2>(params.secondary_blinding_generator, blind));
}

// interactive_witness_1 gets the leaves' openings/divisors, along with the standard witness
// for the relevant branches
let mut interactive_witness_1 = vec![];
accum_blind::<C1>(&mut interactive_witness_1, output_blinds.o_blind);
accum_blind::<C1>(&mut interactive_witness_1, output_blinds.i_blind);
accum_blind::<C1>(&mut interactive_witness_1, output_blinds.i_blind_blind);
accum_blind::<C1>(&mut interactive_witness_1, output_blinds.c_blind);
for blind in branches_2_blinds_prepared {
accum_blind::<C1>(&mut interactive_witness_1, blind);
}

// interactive_witness_2 gets the witness for the relevant branches
let mut interactive_witness_2 = vec![];
for blind in branches_1_blinds_prepared {
accum_blind::<C2>(&mut interactive_witness_2, blind);
}

todo!("TODO")
}
Expand Down

0 comments on commit 8ab716c

Please sign in to comment.