Skip to content

Commit e87faa8

Browse files
Add ECC test
1 parent b545e78 commit e87faa8

File tree

1 file changed

+145
-0
lines changed

1 file changed

+145
-0
lines changed

src/circuit/gadget/ecc.rs

+145
Original file line numberDiff line numberDiff line change
@@ -311,3 +311,148 @@ impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug> FixedPointShor
311311
})
312312
}
313313
}
314+
315+
#[cfg(test)]
316+
mod tests {
317+
use crate::constants;
318+
use group::{Curve, Group};
319+
use halo2::{
320+
arithmetic::{CurveAffine, FieldExt},
321+
circuit::{layouter::SingleChipLayouter, Layouter},
322+
dev::MockProver,
323+
pasta::pallas,
324+
plonk::{Assignment, Circuit, ConstraintSystem, Error},
325+
};
326+
327+
use super::chip::{EccChip, EccConfig, OrchardFixedBases};
328+
329+
struct MyCircuit<C: CurveAffine> {
330+
_marker: std::marker::PhantomData<C>,
331+
}
332+
333+
#[allow(non_snake_case)]
334+
impl<C: CurveAffine> Circuit<C::Base> for MyCircuit<C> {
335+
type Config = EccConfig;
336+
337+
fn configure(meta: &mut ConstraintSystem<C::Base>) -> Self::Config {
338+
let bits = meta.advice_column();
339+
let P = (meta.advice_column(), meta.advice_column());
340+
let lambda = (meta.advice_column(), meta.advice_column());
341+
let extras = [
342+
meta.advice_column(),
343+
meta.advice_column(),
344+
meta.advice_column(),
345+
meta.advice_column(),
346+
meta.advice_column(),
347+
];
348+
349+
EccChip::<C>::configure(meta, bits, P, lambda, extras)
350+
}
351+
352+
fn synthesize(
353+
&self,
354+
cs: &mut impl Assignment<C::Base>,
355+
config: Self::Config,
356+
) -> Result<(), Error> {
357+
let mut layouter = SingleChipLayouter::new(cs)?;
358+
let loaded = EccChip::<C>::load(config.clone(), &mut layouter)?;
359+
let chip = EccChip::construct(config, loaded);
360+
361+
// Generate a random point P
362+
let p_val = C::CurveExt::random(rand::rngs::OsRng).to_affine(); // P
363+
let p = super::Point::new(chip.clone(), layouter.namespace(|| "point"), Some(p_val))?;
364+
365+
// Generate a random point Q
366+
let q_val = C::CurveExt::random(rand::rngs::OsRng).to_affine(); // P
367+
let q = super::Point::new(chip.clone(), layouter.namespace(|| "point"), Some(q_val))?;
368+
369+
// Check complete addition point P + Q
370+
{
371+
let real_added = p_val + q_val;
372+
let added_complete = p.add(layouter.namespace(|| "P + Q"), &q)?;
373+
if let (Some(x), Some(y)) =
374+
(added_complete.inner.x.value, added_complete.inner.y.value)
375+
{
376+
if C::from_xy(x, y).is_some().into() {
377+
assert_eq!(real_added.to_affine(), C::from_xy(x, y).unwrap());
378+
}
379+
}
380+
}
381+
382+
// Check fixed-base scalar multiplication
383+
{
384+
let scalar_fixed = C::Scalar::rand();
385+
let nullifier_k = constants::nullifier_k::generator();
386+
let base = nullifier_k.0.value();
387+
let real_mul_fixed = base * scalar_fixed;
388+
389+
let scalar_fixed = super::ScalarFixed::new(
390+
chip.clone(),
391+
layouter.namespace(|| "ScalarFixed"),
392+
Some(scalar_fixed),
393+
)?;
394+
let nullifier_k = super::FixedPoint::get(
395+
chip.clone(),
396+
OrchardFixedBases::NullifierK(nullifier_k),
397+
)?;
398+
let mul_fixed = nullifier_k.mul(layouter.namespace(|| "mul"), &scalar_fixed)?;
399+
if let (Some(x), Some(y)) = (mul_fixed.inner.x.value, mul_fixed.inner.y.value) {
400+
assert_eq!(real_mul_fixed.to_affine(), C::from_xy(x, y).unwrap());
401+
}
402+
}
403+
404+
// Check short signed fixed-base scalar multiplication
405+
{
406+
let scalar_fixed_short = C::Scalar::from_u64(rand::random::<u64>());
407+
let value_commit_v = constants::value_commit_v::generator();
408+
let real_mul_fixed_short = value_commit_v.0.value() * scalar_fixed_short;
409+
410+
let scalar_fixed_short = super::ScalarFixedShort::new(
411+
chip.clone(),
412+
layouter.namespace(|| "ScalarFixedShort"),
413+
Some(scalar_fixed_short),
414+
)?;
415+
let value_commit_v = super::FixedPointShort::get(
416+
chip.clone(),
417+
OrchardFixedBases::ValueCommitV(value_commit_v),
418+
)?;
419+
let mul_fixed_short =
420+
value_commit_v.mul(layouter.namespace(|| "mul fixed"), &scalar_fixed_short)?;
421+
if let (Some(x), Some(y)) =
422+
(mul_fixed_short.inner.x.value, mul_fixed_short.inner.y.value)
423+
{
424+
assert_eq!(real_mul_fixed_short.to_affine(), C::from_xy(x, y).unwrap());
425+
}
426+
}
427+
428+
// Check variable-base scalar multiplication
429+
{
430+
let scalar_val = C::Scalar::rand();
431+
let real_mul = p_val * scalar_val;
432+
433+
let scalar_val = C::Base::from_bytes(&scalar_val.to_bytes()).unwrap();
434+
let scalar = super::ScalarVar::new(
435+
chip,
436+
layouter.namespace(|| "ScalarVar"),
437+
Some(scalar_val),
438+
)?;
439+
let mul = p.mul(layouter.namespace(|| "mul"), &scalar)?;
440+
if let (Some(x), Some(y)) = (mul.inner.x.value, mul.inner.y.value) {
441+
assert_eq!(real_mul.to_affine(), C::from_xy(x, y).unwrap());
442+
}
443+
}
444+
445+
Ok(())
446+
}
447+
}
448+
449+
#[test]
450+
fn ecc() {
451+
let k = 11;
452+
let circuit = MyCircuit::<pallas::Affine> {
453+
_marker: std::marker::PhantomData,
454+
};
455+
let prover = MockProver::run(k, &circuit, vec![]).unwrap();
456+
assert_eq!(prover.verify(), Ok(()))
457+
}
458+
}

0 commit comments

Comments
 (0)