Skip to content

Commit 2308caf

Browse files
authored
Merge pull request #845 from QED-it/zsa1
Add ZSA features
2 parents 5741cc5 + 27b2b33 commit 2308caf

34 files changed

+30228
-372
lines changed

halo2_gadgets/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,16 @@ and this project adheres to Rust's notion of
1212
a shorthand for `LookupRangeCheck` specialized with `pallas::Base` and `sinsemilla::K`
1313
- `halo2_gadgets::utilities::lookup_range_check::PallasLookupRangeCheckConfig` which is
1414
a shorthand for `LookupRangeCheckConfig` specialized with `pallas::Base` and `sinsemilla::K`
15+
- `halo2_gadgets::ecc::Point::{mul_sign, new_from_constant}`
16+
- `halo2_gadgets::sinsemilla::CommitDomain::{blinding_factor, hash_with_private_init, q_init}`
17+
- `halo2_gadgets::utilities::cond_swap::CondSwapChip::{mux_on_points, mux_on_non_identity_points}`
1518

1619
### Changed
1720
- `halo2_gadgets::utilities::lookup_range_check::witness_short` now takes a generic `Lookup`
1821
instead of directly taking a `LookupRangeCheckConfig<F, K>` reference
22+
- `halo2_gadgets::sinsemilla::merkle::chip::MerkleConfig::cond_swap_config` is now public
23+
- `halo2_gadgets::sinsemilla::chip::SinsemillaChip::configure` has a new input
24+
`allow_init_from_private_point` to enable the evaluation of Sinsemilla hash from a private point.
1925

2026
## [0.3.1] - 2024-12-16
2127
- `halo2_gadgets::poseidon::primitives` is now a re-export of the new `halo2_poseidon`

halo2_gadgets/src/ecc.rs

Lines changed: 94 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::fmt::Debug;
44

55
use halo2_proofs::{
66
arithmetic::CurveAffine,
7-
circuit::{Chip, Layouter, Value},
7+
circuit::{AssignedCell, Chip, Layouter, Value},
88
plonk::Error,
99
};
1010

@@ -60,6 +60,15 @@ pub trait EccInstructions<C: CurveAffine>:
6060
value: Value<C>,
6161
) -> Result<Self::Point, Error>;
6262

63+
/// Witnesses the given constant point as a private input to the circuit.
64+
/// This allows the point to be the identity, mapped to (0, 0) in
65+
/// affine coordinates.
66+
fn witness_point_from_constant(
67+
&self,
68+
layouter: &mut impl Layouter<C::Base>,
69+
value: C,
70+
) -> Result<Self::Point, Error>;
71+
6372
/// Witnesses the given point as a private input to the circuit.
6473
/// This returns an error if the point is the identity.
6574
fn witness_point_non_id(
@@ -111,6 +120,15 @@ pub trait EccInstructions<C: CurveAffine>:
111120
b: &B,
112121
) -> Result<Self::Point, Error>;
113122

123+
/// Performs variable-base sign-scalar multiplication, returning `[sign] point`.
124+
/// This constrains `sign` to be in {-1, 1}.
125+
fn mul_sign(
126+
&self,
127+
layouter: &mut impl Layouter<C::Base>,
128+
sign: &AssignedCell<C::Base, C::Base>,
129+
point: &Self::Point,
130+
) -> Result<Self::Point, Error>;
131+
114132
/// Performs variable-base scalar multiplication, returning `[scalar] base`.
115133
fn mul(
116134
&self,
@@ -390,6 +408,17 @@ impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> Point<C,
390408
point.map(|inner| Point { chip, inner })
391409
}
392410

411+
/// Witnesses the given constant point as a private input to the circuit.
412+
/// This allows the point to be the identity, mapped to (0, 0) in affine coordinates.
413+
pub fn new_from_constant(
414+
chip: EccChip,
415+
mut layouter: impl Layouter<C::Base>,
416+
value: C,
417+
) -> Result<Self, Error> {
418+
let point = chip.witness_point_from_constant(&mut layouter, value);
419+
point.map(|inner| Point { chip, inner })
420+
}
421+
393422
/// Constrains this point to be equal in value to another point.
394423
pub fn constrain_equal<Other: Into<Point<C, EccChip>> + Clone>(
395424
&self,
@@ -432,6 +461,21 @@ impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> Point<C,
432461
inner,
433462
})
434463
}
464+
465+
/// Returns `[sign] self`.
466+
/// This constrains `sign` to be in {-1, 1}.
467+
pub fn mul_sign(
468+
&self,
469+
mut layouter: impl Layouter<C::Base>,
470+
sign: &AssignedCell<C::Base, C::Base>,
471+
) -> Result<Point<C, EccChip>, Error> {
472+
self.chip
473+
.mul_sign(&mut layouter, sign, &self.inner)
474+
.map(|point| Point {
475+
chip: self.chip.clone(),
476+
inner: point,
477+
})
478+
}
435479
}
436480

437481
/// The affine short Weierstrass x-coordinate of a point on a specific elliptic curve.
@@ -598,7 +642,9 @@ pub(crate) mod tests {
598642
};
599643
use crate::{
600644
test_circuits::test_utils::test_against_stored_circuit,
601-
utilities::lookup_range_check::{PallasLookupRangeCheck, PallasLookupRangeCheckConfig},
645+
utilities::lookup_range_check::{
646+
PallasLookupRangeCheck, PallasLookupRangeCheck4_5BConfig, PallasLookupRangeCheckConfig,
647+
},
602648
};
603649

604650
#[derive(Debug, Eq, PartialEq, Clone)]
@@ -727,12 +773,12 @@ pub(crate) mod tests {
727773
type Base = BaseField;
728774
}
729775

730-
struct MyCircuit<Lookup: PallasLookupRangeCheck> {
776+
struct MyEccCircuit<Lookup: PallasLookupRangeCheck> {
731777
test_errors: bool,
732778
_lookup_marker: PhantomData<Lookup>,
733779
}
734780

735-
impl<Lookup: PallasLookupRangeCheck> MyCircuit<Lookup> {
781+
impl<Lookup: PallasLookupRangeCheck> MyEccCircuit<Lookup> {
736782
fn new(test_errors: bool) -> Self {
737783
Self {
738784
test_errors,
@@ -742,12 +788,12 @@ pub(crate) mod tests {
742788
}
743789

744790
#[allow(non_snake_case)]
745-
impl<Lookup: PallasLookupRangeCheck> Circuit<pallas::Base> for MyCircuit<Lookup> {
791+
impl<Lookup: PallasLookupRangeCheck> Circuit<pallas::Base> for MyEccCircuit<Lookup> {
746792
type Config = EccConfig<TestFixedBases, Lookup>;
747793
type FloorPlanner = SimpleFloorPlanner;
748794

749795
fn without_witnesses(&self) -> Self {
750-
MyCircuit::new(false)
796+
MyEccCircuit::new(false)
751797
}
752798

753799
fn configure(meta: &mut ConstraintSystem<pallas::Base>) -> Self::Config {
@@ -796,7 +842,7 @@ pub(crate) mod tests {
796842

797843
// Load 10-bit lookup table. In the Action circuit, this will be
798844
// provided by the Sinsemilla chip.
799-
config.lookup_config.load(&mut layouter)?;
845+
config.lookup_config.load_range_check_table(&mut layouter)?;
800846

801847
// Generate a random non-identity point P
802848
let p_val = pallas::Point::random(rand::rngs::OsRng).to_affine(); // P
@@ -884,6 +930,14 @@ pub(crate) mod tests {
884930
)?;
885931
}
886932

933+
// Test variable-base sign-scalar multiplication
934+
{
935+
super::chip::mul_fixed::short::tests::test_mul_sign(
936+
chip.clone(),
937+
layouter.namespace(|| "variable-base sign-scalar mul"),
938+
)?;
939+
}
940+
887941
// Test full-width fixed-base scalar multiplication
888942
{
889943
super::chip::mul_fixed::full_width::tests::test_mul_fixed(
@@ -915,14 +969,14 @@ pub(crate) mod tests {
915969
#[test]
916970
fn ecc_chip() {
917971
let k = 13;
918-
let circuit = MyCircuit::<PallasLookupRangeCheckConfig>::new(true);
972+
let circuit = MyEccCircuit::<PallasLookupRangeCheckConfig>::new(true);
919973
let prover = MockProver::run(k, &circuit, vec![]).unwrap();
920974
assert_eq!(prover.verify(), Ok(()))
921975
}
922976

923977
#[test]
924978
fn test_ecc_chip_against_stored_circuit() {
925-
let circuit = MyCircuit::<PallasLookupRangeCheckConfig>::new(false);
979+
let circuit = MyEccCircuit::<PallasLookupRangeCheckConfig>::new(false);
926980
test_against_stored_circuit(circuit, "ecc_chip", 3872);
927981
}
928982

@@ -935,7 +989,37 @@ pub(crate) mod tests {
935989
root.fill(&WHITE).unwrap();
936990
let root = root.titled("Ecc Chip Layout", ("sans-serif", 60)).unwrap();
937991

938-
let circuit = MyCircuit::<PallasLookupRangeCheckConfig>::new(false);
992+
let circuit = MyEccCircuit::<PallasLookupRangeCheckConfig>::new(false);
993+
halo2_proofs::dev::CircuitLayout::default()
994+
.render(13, &circuit, &root)
995+
.unwrap();
996+
}
997+
998+
#[test]
999+
fn ecc_chip_4_5b() {
1000+
let k = 13;
1001+
let circuit = MyEccCircuit::<PallasLookupRangeCheck4_5BConfig>::new(true);
1002+
let prover = MockProver::run(k, &circuit, vec![]).unwrap();
1003+
1004+
assert_eq!(prover.verify(), Ok(()))
1005+
}
1006+
1007+
#[test]
1008+
fn test_against_stored_ecc_chip_4_5b() {
1009+
let circuit = MyEccCircuit::<PallasLookupRangeCheck4_5BConfig>::new(false);
1010+
test_against_stored_circuit(circuit, "ecc_chip_4_5b", 3968);
1011+
}
1012+
1013+
#[cfg(feature = "test-dev-graph")]
1014+
#[test]
1015+
fn print_ecc_chip_4_5b() {
1016+
use plotters::prelude::*;
1017+
1018+
let root = BitMapBackend::new("ecc-chip-4_5b-layout.png", (1024, 7680)).into_drawing_area();
1019+
root.fill(&WHITE).unwrap();
1020+
let root = root.titled("Ecc Chip Layout", ("sans-serif", 60)).unwrap();
1021+
1022+
let circuit = MyEccCircuit::<PallasLookupRangeCheck4_5BConfig>::new(false);
9391023
halo2_proofs::dev::CircuitLayout::default()
9401024
.render(13, &circuit, &root)
9411025
.unwrap();

halo2_gadgets/src/ecc/chip.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,21 @@ where
465465
)
466466
}
467467

468+
/// Witnesses the given constant point as a private input to the circuit.
469+
/// This allows the point to be the identity, mapped to (0, 0) in
470+
/// affine coordinates.
471+
fn witness_point_from_constant(
472+
&self,
473+
layouter: &mut impl Layouter<pallas::Base>,
474+
value: pallas::Affine,
475+
) -> Result<Self::Point, Error> {
476+
let config = self.config().witness_point;
477+
layouter.assign_region(
478+
|| "witness point (constant)",
479+
|mut region| config.constant_point(value, 0, &mut region),
480+
)
481+
}
482+
468483
fn witness_point_non_id(
469484
&self,
470485
layouter: &mut impl Layouter<pallas::Base>,
@@ -544,6 +559,24 @@ where
544559
)
545560
}
546561

562+
/// Performs variable-base sign-scalar multiplication, returning `[sign] point`.
563+
/// This constrains `sign` to be in {-1, 1}.
564+
fn mul_sign(
565+
&self,
566+
layouter: &mut impl Layouter<pallas::Base>,
567+
sign: &AssignedCell<pallas::Base, pallas::Base>,
568+
point: &Self::Point,
569+
) -> Result<Self::Point, Error> {
570+
// Multiply point by sign, using the same gate as mul_fixed::short.
571+
// This also constrains sign to be in {-1, 1}.
572+
let config_short = self.config().mul_fixed_short.clone();
573+
config_short.assign_scalar_sign(
574+
layouter.namespace(|| "variable-base sign-scalar mul"),
575+
sign,
576+
point,
577+
)
578+
}
579+
547580
fn mul(
548581
&self,
549582
layouter: &mut impl Layouter<pallas::Base>,

0 commit comments

Comments
 (0)