@@ -4,7 +4,7 @@ use std::fmt::Debug;
44
55use 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 ( ) ;
0 commit comments