Skip to content

Commit

Permalink
Test proving for additional layers
Browse files Browse the repository at this point in the history
Also adds support for how branch hashes must be permissible.
  • Loading branch information
kayabaNerve committed May 4, 2024
1 parent 25bbb63 commit 089e80e
Show file tree
Hide file tree
Showing 7 changed files with 182 additions and 48 deletions.
1 change: 0 additions & 1 deletion crypto/ciphersuite/src/helioselene.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ impl Ciphersuite for Helios {
}
}


#[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)]
pub struct Selene;
impl Ciphersuite for Selene {
Expand Down
9 changes: 6 additions & 3 deletions crypto/divisors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,10 @@ pub fn new_divisor<C: DivisorCurve>(points: &[C]) -> Option<Poly<C::FieldElement

#[cfg(any(test, feature = "ed25519"))]
mod ed25519 {
use group::{ff::{Field, PrimeField}, GroupEncoding};
use group::{
ff::{Field, PrimeField},
GroupEncoding,
};
use dalek_ff_group::{FieldElement, EdwardsPoint};

impl crate::DivisorCurve for EdwardsPoint {
Expand Down Expand Up @@ -191,8 +194,8 @@ mod ed25519 {

// Recover the x coordinate
let edwards_y_sq = edwards_y * edwards_y;
let D =
-Self::FieldElement::from(121665u64) * Self::FieldElement::from(121666u64).invert().unwrap();
let D = -Self::FieldElement::from(121665u64) *
Self::FieldElement::from(121666u64).invert().unwrap();
let mut edwards_x = ((edwards_y_sq - Self::FieldElement::ONE) *
((D * edwards_y_sq) + Self::FieldElement::ONE).invert().unwrap())
.sqrt()
Expand Down
5 changes: 1 addition & 4 deletions crypto/divisors/src/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
use rand_core::OsRng;

use group::{
ff::{Field, PrimeField},
Group, GroupEncoding, Curve,
};
use group::{ff::Field, Group, Curve};
use dalek_ff_group::EdwardsPoint;
use pasta_curves::{
arithmetic::{Coordinates, CurveAffine},
Expand Down
2 changes: 1 addition & 1 deletion crypto/fcmps/src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ struct ProverData<F: Field> {
/// A struct representing a circuit.
#[derive(Clone, PartialEq, Eq, Debug)]
pub(crate) struct Circuit<C: Ciphersuite> {
muls: usize,
pub(crate) muls: usize,
commitments: usize,
// A series of linear combinations which must evaluate to 0.
constraints: Vec<LinComb<C::F>>,
Expand Down
1 change: 0 additions & 1 deletion crypto/fcmps/src/gadgets/interactive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,6 @@ impl<C: Ciphersuite> Circuit<C> {
curve: &CurveSpec<C::F>,
claim: ClaimedPointWithDlog<C::F>,
) -> OnCurve {
dbg!("in discrete_log");
let ClaimedPointWithDlog { generator, divisor, dlog, point } = claim;

// Ensure this is being safely called
Expand Down
78 changes: 63 additions & 15 deletions crypto/fcmps/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,38 @@ impl<F: Zeroize + PrimeFieldBits> VectorCommitmentTape<F> {
(0 .. 256).map(|j| Variable::C(i, j)).collect()
}

fn append_branch(&mut self, branch_len: usize, branch: Option<Vec<F>>) -> Vec<Variable> {
fn append_branch<T: Transcript, C: Ciphersuite>(
&mut self,
generators: &Generators<T, C>,
branch_len: usize,
branch: Option<Vec<F>>,
) -> (Vec<Variable>, Option<F>)
where
C::G: DivisorCurve<Scalar = F>,
{
let mut branch_offset = None;
let branch = branch.map(|mut branch| {
assert_eq!(branch_len, branch.len());
assert!(branch.len() <= 256);

branch_offset = Some({
let mut hash = multiexp(
&branch.iter().zip(generators.g_bold_slice()).map(|(s, p)| (*s, *p)).collect::<Vec<_>>(),
);
let mut offset = F::ZERO;
while Option::<<<C as Ciphersuite>::G as DivisorCurve>::FieldElement>::from(
(<<C as Ciphersuite>::G as DivisorCurve>::FieldElement::ONE +
<C as Ciphersuite>::G::to_xy(hash).1)
.sqrt(),
)
.is_none()
{
hash += generators.h();
offset += F::ONE;
}
offset
});

// Pad the branch
while branch.len() < 256 {
branch.push(F::ZERO);
Expand All @@ -54,7 +82,7 @@ impl<F: Zeroize + PrimeFieldBits> VectorCommitmentTape<F> {

let mut branch = self.append(branch);
branch.truncate(branch_len);
branch
(branch, branch_offset)
}

/// Append a discrete logarithm of up to 255 bits, allowing usage of the extra slot for an
Expand Down Expand Up @@ -417,35 +445,51 @@ where

// Append the leaves and the rest of the branches to the tape
let mut c1_tape = VectorCommitmentTape(vec![]);
let mut c1_branch_offsets = vec![];
let mut c1_branches = vec![];
c1_branches.push(c1_tape.append_branch(flattened_leaves.len(), Some(flattened_leaves)));
{
let (branch, offset) = c1_tape.append_branch::<T, C1>(
&params.curve_1_generators,
flattened_leaves.len(),
Some(flattened_leaves),
);
c1_branch_offsets.push(offset.unwrap());
c1_branches.push(branch);
}
for branch in branches.curve_1_layers {
c1_branches.push(c1_tape.append_branch(branch.len(), Some(branch)));
let (branch, offset) =
c1_tape.append_branch::<T, C1>(&params.curve_1_generators, branch.len(), Some(branch));
c1_branch_offsets.push(offset.unwrap());
c1_branches.push(branch);
}

let mut c2_tape = VectorCommitmentTape(vec![]);
let mut c2_branch_offsets = vec![];
let mut c2_branches = vec![];
for branch in branches.curve_2_layers {
c2_branches.push(c2_tape.append_branch(branch.len(), Some(branch)));
let (branch, offset) =
c2_tape.append_branch::<T, C2>(&params.curve_2_generators, branch.len(), Some(branch));
c2_branch_offsets.push(offset.unwrap());
c2_branches.push(branch);
}

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

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

// Accumulate the opening for the leaves
Expand Down Expand Up @@ -633,12 +677,13 @@ where
// - 1, as the leaves are the first branch
assert_eq!(c1_branches.len() - 1, commitment_blind_claims_1.len());
assert!(commitments_2.len() > c1_branches.len());
let commitment_iter = commitments_2.into_iter().zip(pvc_blinds_2);
let commitment_iter = commitments_2.into_iter().zip(pvc_blinds_2).zip(c2_branch_offsets);
let branch_iter = c1_branches.into_iter().skip(1).zip(commitment_blind_claims_1);
for ((prior_commitment, prior_blind), (branch, prior_blind_opening)) in
for (((prior_commitment, prior_blind), offset), (branch, prior_blind_opening)) in
commitment_iter.into_iter().zip(branch_iter)
{
let unblinded_hash = prior_commitment - (params.curve_2_generators.h() * prior_blind);
let unblinded_hash =
prior_commitment - (params.curve_2_generators.h() * (prior_blind - offset));
let (hash_x, hash_y, _) = c1_circuit.mul(None, None, Some(C2::G::to_xy(unblinded_hash)));
c1_circuit.additional_layer(
transcript,
Expand All @@ -653,12 +698,13 @@ where
assert_eq!(commitments_1.len(), pvc_blinds_1.len());
assert_eq!(c2_branches.len(), commitment_blind_claims_2.len());
assert!(commitments_1.len() > c2_branches.len());
let commitment_iter = commitments_1.into_iter().zip(pvc_blinds_1);
let commitment_iter = commitments_1.into_iter().zip(pvc_blinds_1).zip(c1_branch_offsets);
let branch_iter = c2_branches.into_iter().zip(commitment_blind_claims_2);
for ((prior_commitment, prior_blind), (branch, prior_blind_opening)) in
for (((prior_commitment, prior_blind), offset), (branch, prior_blind_opening)) in
commitment_iter.into_iter().zip(branch_iter)
{
let unblinded_hash = prior_commitment - (params.curve_1_generators.h() * prior_blind);
let unblinded_hash =
prior_commitment - (params.curve_1_generators.h() * (prior_blind - offset));
let (hash_x, hash_y, _) = c2_circuit.mul(None, None, Some(C1::G::to_xy(unblinded_hash)));
c2_circuit.additional_layer(
transcript,
Expand All @@ -671,6 +717,8 @@ where
}

// Escape to the raw weights to form a GBP with
dbg!(c1_circuit.muls);
dbg!(c2_circuit.muls);
todo!("TODO")
}
}
134 changes: 111 additions & 23 deletions crypto/fcmps/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,35 @@ use rand_core::OsRng;

use transcript::RecommendedTranscript;

use multiexp::multiexp_vartime;
use ciphersuite::{group::Group, Ciphersuite, Ed25519, Selene, Helios};

use crate::*;

fn make_permissible<C: DivisorCurve>(generator: C, mut point: C) -> C {
while Option::<C::FieldElement>::from((C::FieldElement::ONE + C::to_xy(point).1).sqrt()).is_none()
{
point += generator;
}
point
}

#[allow(non_snake_case)]
fn random_permissible_point<C: Ciphersuite>() -> C::G
where
C::G: DivisorCurve,
{
make_permissible(C::G::generator(), C::G::random(&mut OsRng))
}

#[allow(non_snake_case)]
fn random_output() -> Output<Ed25519> {
let O = random_permissible_point::<Ed25519>();
let I = <Ed25519 as Ciphersuite>::G::random(&mut OsRng);
let C = random_permissible_point::<Ed25519>();
Output { O, I, C }
}

#[allow(non_snake_case)]
#[test]
fn test() {
Expand All @@ -16,36 +41,99 @@ fn test() {

let curve_1_generators = generalized_bulletproofs::tests::generators::<Selene>(512);
let curve_2_generators = generalized_bulletproofs::tests::generators::<Helios>(512);
let params =
FcmpParams::<_, Ed25519, _, _> { curve_1_generators, curve_2_generators, G, T, U, V };

let mut O = <Ed25519 as Ciphersuite>::G::random(&mut OsRng);
while Option::<<Selene as Ciphersuite>::F>::from(
(<Selene as Ciphersuite>::F::ONE + <Ed25519 as Ciphersuite>::G::to_xy(O).1).sqrt(),
)
.is_none()
{
O += <Ed25519 as Ciphersuite>::G::generator();
}
let I = <Ed25519 as Ciphersuite>::G::random(&mut OsRng);
let mut C = <Ed25519 as Ciphersuite>::G::random(&mut OsRng);
while Option::<<Selene as Ciphersuite>::F>::from(
(<Selene as Ciphersuite>::F::ONE + <Ed25519 as Ciphersuite>::G::to_xy(O).1).sqrt(),
)
.is_none()
{
C += <Ed25519 as Ciphersuite>::G::generator();
}
let output = Output { O, I, C };
let params = FcmpParams::<_, Ed25519, _, _> {
curve_1_generators: curve_1_generators.clone(),
curve_2_generators: curve_2_generators.clone(),
G,
T,
U,
V,
};

let output = random_output();
let blinds = OutputBlinds::new(&mut OsRng);
let blinds = blinds.prepare(G, T, U, V, output);

let branches = Branches { leaves: vec![output], curve_2_layers: vec![], curve_1_layers: vec![] };
let mut leaves = vec![];
for _ in 0 .. usize::try_from(OsRng.next_u64() % 4).unwrap() + 1 {
leaves.push(random_output());
}
let leaves_len = leaves.len();
leaves[usize::try_from(OsRng.next_u64()).unwrap() % leaves_len] = output;

let mut selene_hash = Some({
let mut multiexp = vec![];
for (scalar, point) in leaves
.iter()
.flat_map(|output| {
[
<Ed25519 as Ciphersuite>::G::to_xy(output.O).0,
<Ed25519 as Ciphersuite>::G::to_xy(output.I).0,
<Ed25519 as Ciphersuite>::G::to_xy(output.I).1,
<Ed25519 as Ciphersuite>::G::to_xy(output.C).0,
]
})
.zip(curve_1_generators.g_bold_slice())
{
multiexp.push((scalar, *point));
}
make_permissible(curve_1_generators.h(), multiexp_vartime(&multiexp))
});
let mut helios_hash;

let mut curve_2_layers = vec![];
let mut curve_1_layers = vec![];
for _ in 0 .. 2 {
let mut curve_2_layer = vec![];
for _ in 0 .. usize::try_from(OsRng.next_u64() % 4).unwrap() + 1 {
curve_2_layer.push(random_permissible_point::<Selene>());
}
let layer_len = curve_2_layer.len();
curve_2_layer[usize::try_from(OsRng.next_u64()).unwrap() % layer_len] =
selene_hash.take().unwrap();
let curve_2_layer = curve_2_layer
.into_iter()
.map(|point| <Selene as Ciphersuite>::G::to_xy(point).0)
.collect::<Vec<_>>();

helios_hash = Some({
let mut multiexp = vec![];
for (scalar, point) in curve_2_layer.iter().zip(curve_2_generators.g_bold_slice()) {
multiexp.push((*scalar, *point));
}
make_permissible(curve_2_generators.h(), multiexp_vartime(&multiexp))
});

curve_2_layers.push(curve_2_layer);

let mut curve_1_layer = vec![];
for _ in 0 .. usize::try_from(OsRng.next_u64() % 4).unwrap() + 1 {
curve_1_layer.push(random_permissible_point::<Helios>());
}
let layer_len = curve_1_layer.len();
curve_1_layer[usize::try_from(OsRng.next_u64()).unwrap() % layer_len] =
helios_hash.take().unwrap();
let curve_1_layer = curve_1_layer
.into_iter()
.map(|point| <Helios as Ciphersuite>::G::to_xy(point).0)
.collect::<Vec<_>>();

selene_hash = Some({
let mut multiexp = vec![];
for (scalar, point) in curve_1_layer.iter().zip(curve_1_generators.g_bold_slice()) {
multiexp.push((*scalar, *point));
}
make_permissible(curve_1_generators.h(), multiexp_vartime(&multiexp))
});

curve_1_layers.push(curve_1_layer);
}

let branches = Branches { leaves, curve_2_layers, curve_1_layers };

Fcmp::prove(
&mut OsRng,
&mut RecommendedTranscript::new(b""),
&mut RecommendedTranscript::new(b"FCMP Test"),
&params,
TreeRoot::<Selene, Helios>::C1(<Selene as Ciphersuite>::G::random(&mut OsRng)),
output,
Expand Down

0 comments on commit 089e80e

Please sign in to comment.