diff --git a/crypto/ciphersuite/src/helioselene.rs b/crypto/ciphersuite/src/helioselene.rs index 27690020..d5375305 100644 --- a/crypto/ciphersuite/src/helioselene.rs +++ b/crypto/ciphersuite/src/helioselene.rs @@ -33,7 +33,6 @@ impl Ciphersuite for Helios { } } - #[derive(Clone, Copy, PartialEq, Eq, Debug, Zeroize)] pub struct Selene; impl Ciphersuite for Selene { diff --git a/crypto/divisors/src/lib.rs b/crypto/divisors/src/lib.rs index 55a5229f..115aebf4 100644 --- a/crypto/divisors/src/lib.rs +++ b/crypto/divisors/src/lib.rs @@ -157,7 +157,10 @@ pub fn new_divisor(points: &[C]) -> Option { /// A struct representing a circuit. #[derive(Clone, PartialEq, Eq, Debug)] pub(crate) struct Circuit { - muls: usize, + pub(crate) muls: usize, commitments: usize, // A series of linear combinations which must evaluate to 0. constraints: Vec>, diff --git a/crypto/fcmps/src/gadgets/interactive.rs b/crypto/fcmps/src/gadgets/interactive.rs index e9f5e517..9c8a17c7 100644 --- a/crypto/fcmps/src/gadgets/interactive.rs +++ b/crypto/fcmps/src/gadgets/interactive.rs @@ -216,7 +216,6 @@ impl Circuit { curve: &CurveSpec, claim: ClaimedPointWithDlog, ) -> OnCurve { - dbg!("in discrete_log"); let ClaimedPointWithDlog { generator, divisor, dlog, point } = claim; // Ensure this is being safely called diff --git a/crypto/fcmps/src/lib.rs b/crypto/fcmps/src/lib.rs index 68a60c0e..f2fdd274 100644 --- a/crypto/fcmps/src/lib.rs +++ b/crypto/fcmps/src/lib.rs @@ -41,10 +41,38 @@ impl VectorCommitmentTape { (0 .. 256).map(|j| Variable::C(i, j)).collect() } - fn append_branch(&mut self, branch_len: usize, branch: Option>) -> Vec { + fn append_branch( + &mut self, + generators: &Generators, + branch_len: usize, + branch: Option>, + ) -> (Vec, Option) + where + C::G: DivisorCurve, + { + 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::>(), + ); + let mut offset = F::ZERO; + while Option::<<::G as DivisorCurve>::FieldElement>::from( + (<::G as DivisorCurve>::FieldElement::ONE + + ::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); @@ -54,7 +82,7 @@ impl VectorCommitmentTape { 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 @@ -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::( + ¶ms.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::(¶ms.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::(¶ms.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::(params.curve_1_generators.h(), blind)); + .push(PreparedBlind::<_>::new::(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::(params.curve_2_generators.h(), blind)); + .push(PreparedBlind::<_>::new::(params.curve_2_generators.h(), -(blind - offset))); } // Accumulate the opening for the leaves @@ -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, @@ -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, @@ -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") } } diff --git a/crypto/fcmps/src/tests.rs b/crypto/fcmps/src/tests.rs index da128b20..922ab5b5 100644 --- a/crypto/fcmps/src/tests.rs +++ b/crypto/fcmps/src/tests.rs @@ -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(generator: C, mut point: C) -> C { + while Option::::from((C::FieldElement::ONE + C::to_xy(point).1).sqrt()).is_none() + { + point += generator; + } + point +} + +#[allow(non_snake_case)] +fn random_permissible_point() -> C::G +where + C::G: DivisorCurve, +{ + make_permissible(C::G::generator(), C::G::random(&mut OsRng)) +} + +#[allow(non_snake_case)] +fn random_output() -> Output { + let O = random_permissible_point::(); + let I = ::G::random(&mut OsRng); + let C = random_permissible_point::(); + Output { O, I, C } +} + #[allow(non_snake_case)] #[test] fn test() { @@ -16,36 +41,99 @@ fn test() { let curve_1_generators = generalized_bulletproofs::tests::generators::(512); let curve_2_generators = generalized_bulletproofs::tests::generators::(512); - let params = - FcmpParams::<_, Ed25519, _, _> { curve_1_generators, curve_2_generators, G, T, U, V }; - - let mut O = ::G::random(&mut OsRng); - while Option::<::F>::from( - (::F::ONE + ::G::to_xy(O).1).sqrt(), - ) - .is_none() - { - O += ::G::generator(); - } - let I = ::G::random(&mut OsRng); - let mut C = ::G::random(&mut OsRng); - while Option::<::F>::from( - (::F::ONE + ::G::to_xy(O).1).sqrt(), - ) - .is_none() - { - C += ::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| { + [ + ::G::to_xy(output.O).0, + ::G::to_xy(output.I).0, + ::G::to_xy(output.I).1, + ::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::()); + } + 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| ::G::to_xy(point).0) + .collect::>(); + + 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::()); + } + 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| ::G::to_xy(point).0) + .collect::>(); + + 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"), ¶ms, TreeRoot::::C1(::G::random(&mut OsRng)), output,