Skip to content

Commit

Permalink
Remove permissibility per discussions
Browse files Browse the repository at this point in the history
  • Loading branch information
kayabaNerve committed May 5, 2024
1 parent 07729b3 commit 345b62e
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 117 deletions.
3 changes: 0 additions & 3 deletions crypto/fcmps/src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,6 @@ impl<C: Ciphersuite> Circuit<C> {
let c_blind = self.discrete_log(transcript, curve, c_blind);
self.incomplete_add_pub(C_tilde, c_blind, C);

self.permissible(C::F::ONE, C::F::ONE, O.y);
self.permissible(C::F::ONE, C::F::ONE, C.y);
self.tuple_member_of_list(transcript, vec![O.x, I.x, I.y, C.x], branch);
}

Expand All @@ -184,7 +182,6 @@ impl<C: Ciphersuite> Circuit<C> {
let blind = self.discrete_log(transcript, curve, blind);
let hash = self.on_curve(curve, hash);
self.incomplete_add_pub(blinded_hash, blind, hash);
self.permissible(C::F::ONE, C::F::ONE, hash.y);
self.member_of_list(hash.x.into(), branch.into_iter().map(Into::into).collect::<Vec<_>>());
}

Expand Down
16 changes: 0 additions & 16 deletions crypto/fcmps/src/gadgets/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,20 +160,4 @@ impl<C: Ciphersuite> Circuit<C> {

OnCurve { x: x2, y: y2 }
}

/// Constrain a `y` coordinate as being permissible.
///
/// Panics if the prover and the `y` coordinate isn't permissible.
pub(crate) fn permissible(&mut self, a: C::F, b: C::F, y: Variable) {
// a y - -b = ay + b
let p = LinComb::empty().term(a, y).constant(b);
let p_eval = self.eval(&p);
let p_eval_sqrt = p_eval.map(|p_eval| p_eval.sqrt().unwrap());

let (l, r, o) = self.mul(None, None, p_eval_sqrt.map(|sqrt| (sqrt, sqrt)));
// Ensure this is actually a sqrt
self.equality(l.into(), &r.into());
// Ensure the sq is the y coordinate derivative
self.equality(p, &o.into());
}
}
89 changes: 32 additions & 57 deletions crypto/fcmps/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,38 +45,18 @@ impl<F: Zeroize + PrimeFieldBits> VectorCommitmentTape<F> {
(0 .. 256).map(|j| Variable::C(i, j)).collect()
}

fn append_branch<T: Transcript, C: Ciphersuite>(
fn append_branch<C: Ciphersuite>(
&mut self,
generators: &Generators<T, C>,
branch_len: usize,
branch: Option<Vec<F>>,
) -> (Vec<Variable>, Option<F>)
) -> Vec<Variable>
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 @@ -86,7 +66,7 @@ impl<F: Zeroize + PrimeFieldBits> VectorCommitmentTape<F> {

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

/// Append a discrete logarithm of up to 255 bits, allowing usage of the extra slot for an
Expand Down Expand Up @@ -349,6 +329,11 @@ pub struct FcmpParams<T: 'static + Transcript, C1: Ciphersuite, C2: Ciphersuite>
/// Generators for the second curve.
curve_2_generators: Generators<T, C2>,

/// Initialization point for the hash function over the first curve.
curve_1_hash_init: C1::G,
/// Initialization point for the hash function over the first curve.
curve_2_hash_init: C2::G,

G_table: Vec<(C1::F, C1::F)>,
T_table: Vec<(C1::F, C1::F)>,
U_table: Vec<(C1::F, C1::F)>,
Expand All @@ -362,9 +347,12 @@ where
C1::G: DivisorCurve<FieldElement = C2::F>,
C2::G: DivisorCurve<FieldElement = C1::F>,
{
#[allow(clippy::too_many_arguments)]
pub fn new<OC: Ciphersuite>(
curve_1_generators: Generators<T, C1>,
curve_2_generators: Generators<T, C2>,
curve_1_hash_init: C1::G,
curve_2_hash_init: C2::G,
G: OC::G,
T: OC::G,
U: OC::G,
Expand Down Expand Up @@ -392,6 +380,8 @@ where
Self {
curve_1_generators,
curve_2_generators,
curve_1_hash_init,
curve_2_hash_init,
G_table,
T_table,
U_table,
Expand Down Expand Up @@ -484,51 +474,40 @@ 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![];
{
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());
let branch = c1_tape.append_branch::<C1>(flattened_leaves.len(), Some(flattened_leaves));
c1_branches.push(branch);
}
for branch in branches.curve_1_layers {
let (branch, offset) =
c1_tape.append_branch::<T, C1>(&params.curve_1_generators, branch.len(), Some(branch));
c1_branch_offsets.push(offset.unwrap());
let branch = c1_tape.append_branch::<C1>(branch.len(), Some(branch));
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 {
let (branch, offset) =
c2_tape.append_branch::<T, C2>(&params.curve_2_generators, branch.len(), Some(branch));
c2_branch_offsets.push(offset.unwrap());
let branch = c2_tape.append_branch::<C2>(branch.len(), Some(branch));
c2_branches.push(branch);
}

// Decide blinds for each branch
let mut branches_1_blinds = vec![];
let mut branches_1_blinds_prepared = vec![];
for offset in &c1_branch_offsets {
for _ in 0 .. c1_branches.len() {
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 - offset)));
.push(PreparedBlind::<_>::new::<C1>(params.curve_1_generators.h(), -blind));
}

let mut branches_2_blinds = vec![];
let mut branches_2_blinds_prepared = vec![];
for offset in &c2_branch_offsets {
for _ in 0 .. c2_branches.len() {
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 - offset)));
.push(PreparedBlind::<_>::new::<C2>(params.curve_2_generators.h(), -blind));
}

// Accumulate the opening for the leaves
Expand Down Expand Up @@ -710,14 +689,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.clone().into_iter().zip(pvc_blinds_2.clone()).zip(c2_branch_offsets);
let commitment_iter = commitments_2.clone().into_iter().zip(pvc_blinds_2.clone());
let branch_iter = c1_branches.into_iter().skip(1).zip(commitment_blind_claims_1);
for (((prior_commitment, prior_blind), offset), (branch, prior_blind_opening)) in
for ((mut prior_commitment, prior_blind), (branch, prior_blind_opening)) in
commitment_iter.into_iter().zip(branch_iter)
{
let unblinded_hash =
prior_commitment - (params.curve_2_generators.h() * (prior_blind - offset));
prior_commitment += params.curve_2_hash_init;
let unblinded_hash = prior_commitment - (params.curve_2_generators.h() * prior_blind);
let (hash_x, hash_y, _) = c1_circuit.mul(None, None, Some(C2::G::to_xy(unblinded_hash)));
c1_circuit.additional_layer(
transcript,
Expand All @@ -732,14 +710,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.clone().into_iter().zip(pvc_blinds_1.clone()).zip(c1_branch_offsets);
let commitment_iter = commitments_1.clone().into_iter().zip(pvc_blinds_1.clone());
let branch_iter = c2_branches.into_iter().zip(commitment_blind_claims_2);
for (((prior_commitment, prior_blind), offset), (branch, prior_blind_opening)) in
for ((mut prior_commitment, prior_blind), (branch, prior_blind_opening)) in
commitment_iter.into_iter().zip(branch_iter)
{
let unblinded_hash =
prior_commitment - (params.curve_1_generators.h() * (prior_blind - offset));
prior_commitment += params.curve_1_hash_init;
let unblinded_hash = prior_commitment - (params.curve_1_generators.h() * prior_blind);
let (hash_x, hash_y, _) = c2_circuit.mul(None, None, Some(C1::G::to_xy(unblinded_hash)));
c2_circuit.additional_layer(
transcript,
Expand Down Expand Up @@ -808,12 +785,10 @@ where

for (i, layer_len) in layer_lens.iter().enumerate() {
if (i % 2) == 0 {
let (branch, _offset) =
c1_tape.append_branch::<T, C1>(&params.curve_1_generators, *layer_len, None);
let branch = c1_tape.append_branch::<C1>(*layer_len, None);
c1_branches.push(branch);
} else {
let (branch, _offset) =
c2_tape.append_branch::<T, C2>(&params.curve_2_generators, *layer_len, None);
let branch = c2_tape.append_branch::<C2>(*layer_len, None);
c2_branches.push(branch);
}
}
Expand Down Expand Up @@ -957,7 +932,7 @@ where
c1_circuit.additional_layer(
transcript,
&CurveSpec { a: <C2::G as DivisorCurve>::a(), b: <C2::G as DivisorCurve>::b() },
C2::G::to_xy(prior_commitment),
C2::G::to_xy(params.curve_2_hash_init + prior_commitment),
prior_blind_opening,
(hash_x, hash_y),
branch,
Expand All @@ -975,7 +950,7 @@ where
c2_circuit.additional_layer(
transcript,
&CurveSpec { a: <C1::G as DivisorCurve>::a(), b: <C1::G as DivisorCurve>::b() },
C1::G::to_xy(prior_commitment),
C1::G::to_xy(params.curve_1_hash_init + prior_commitment),
prior_blind_opening,
(hash_x, hash_y),
branch,
Expand Down
83 changes: 42 additions & 41 deletions crypto/fcmps/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,45 @@ 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
}

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

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

#[inline(never)]
fn verify_fn(
proof: Fcmp<Selene, Helios>,
params: &FcmpParams<RecommendedTranscript, Selene, Helios>,
root: TreeRoot<Selene, Helios>,
layer_lens: Vec<usize>,
input: Input<<Selene as Ciphersuite>::F>,
) {
let instant = std::time::Instant::now();

let mut verifier_1 = params.curve_1_generators.batch_verifier();
let mut verifier_2 = params.curve_2_generators.batch_verifier();

for _ in 0 .. 100 {
proof.clone().verify::<_, _, Ed25519>(
&mut OsRng,
&mut RecommendedTranscript::new(b"FCMP Test"),
&mut verifier_1,
&mut verifier_2,
params,
root,
layer_lens.clone(),
input,
);
}

assert!(params.curve_1_generators.verify(verifier_1));
assert!(params.curve_2_generators.verify(verifier_2));

dbg!((std::time::Instant::now() - instant).as_millis());
}

#[test]
fn test() {
let G = <Ed25519 as Ciphersuite>::G::random(&mut OsRng);
Expand All @@ -41,6 +58,8 @@ fn test() {
let params = FcmpParams::<_, _, _>::new::<Ed25519>(
curve_1_generators.clone(),
curve_2_generators.clone(),
<Selene as Ciphersuite>::G::random(&mut OsRng),
<Helios as Ciphersuite>::G::random(&mut OsRng),
G,
T,
U,
Expand Down Expand Up @@ -75,7 +94,7 @@ fn test() {
{
multiexp.push((scalar, *point));
}
make_permissible(curve_1_generators.h(), multiexp_vartime(&multiexp))
params.curve_1_hash_init + multiexp_vartime(&multiexp)
});
let mut helios_hash;

Expand All @@ -84,7 +103,7 @@ fn test() {
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>());
curve_2_layer.push(<Selene as Ciphersuite>::G::random(&mut OsRng));
}
let layer_len = curve_2_layer.len();
curve_2_layer[usize::try_from(OsRng.next_u64()).unwrap() % layer_len] =
Expand All @@ -99,14 +118,14 @@ fn test() {
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))
params.curve_2_hash_init + 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>());
curve_1_layer.push(<Helios as Ciphersuite>::G::random(&mut OsRng));
}
let layer_len = curve_1_layer.len();
curve_1_layer[usize::try_from(OsRng.next_u64()).unwrap() % layer_len] =
Expand All @@ -121,7 +140,7 @@ fn test() {
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))
params.curve_1_hash_init + multiexp_vartime(&multiexp)
});

curve_1_layers.push(curve_1_layer);
Expand All @@ -147,23 +166,5 @@ fn test() {
branches,
);

let mut verifier_1 = params.curve_1_generators.batch_verifier();
let mut verifier_2 = params.curve_2_generators.batch_verifier();

let instant = std::time::Instant::now();
for _ in 0 .. 10 {
proof.clone().verify::<_, _, Ed25519>(
&mut OsRng,
&mut RecommendedTranscript::new(b"FCMP Test"),
&mut verifier_1,
&mut verifier_2,
&params,
root,
layer_lens.clone(),
input,
);
}
assert!(params.curve_1_generators.verify(verifier_1));
assert!(params.curve_2_generators.verify(verifier_2));
dbg!((std::time::Instant::now() - instant).as_millis());
verify_fn(proof, &params, root, layer_lens, input);
}

0 comments on commit 345b62e

Please sign in to comment.