@@ -4,7 +4,7 @@ use std::fmt::Debug;
4
4
5
5
use halo2_proofs:: {
6
6
arithmetic:: CurveAffine ,
7
- circuit:: { Chip , Layouter , Value } ,
7
+ circuit:: { AssignedCell , Chip , Layouter , Value } ,
8
8
plonk:: Error ,
9
9
} ;
10
10
@@ -60,6 +60,15 @@ pub trait EccInstructions<C: CurveAffine>:
60
60
value : Value < C > ,
61
61
) -> Result < Self :: Point , Error > ;
62
62
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
+
63
72
/// Witnesses the given point as a private input to the circuit.
64
73
/// This returns an error if the point is the identity.
65
74
fn witness_point_non_id (
@@ -111,6 +120,15 @@ pub trait EccInstructions<C: CurveAffine>:
111
120
b : & B ,
112
121
) -> Result < Self :: Point , Error > ;
113
122
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
+
114
132
/// Performs variable-base scalar multiplication, returning `[scalar] base`.
115
133
fn mul (
116
134
& self ,
@@ -390,6 +408,17 @@ impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> Point<C,
390
408
point. map ( |inner| Point { chip, inner } )
391
409
}
392
410
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
+
393
422
/// Constrains this point to be equal in value to another point.
394
423
pub fn constrain_equal < Other : Into < Point < C , EccChip > > + Clone > (
395
424
& self ,
@@ -432,6 +461,21 @@ impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug + Eq> Point<C,
432
461
inner,
433
462
} )
434
463
}
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
+ }
435
479
}
436
480
437
481
/// The affine short Weierstrass x-coordinate of a point on a specific elliptic curve.
@@ -598,7 +642,9 @@ pub(crate) mod tests {
598
642
} ;
599
643
use crate :: {
600
644
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
+ } ,
602
648
} ;
603
649
604
650
#[ derive( Debug , Eq , PartialEq , Clone ) ]
@@ -727,12 +773,12 @@ pub(crate) mod tests {
727
773
type Base = BaseField ;
728
774
}
729
775
730
- struct MyCircuit < Lookup : PallasLookupRangeCheck > {
776
+ struct MyEccCircuit < Lookup : PallasLookupRangeCheck > {
731
777
test_errors : bool ,
732
778
_lookup_marker : PhantomData < Lookup > ,
733
779
}
734
780
735
- impl < Lookup : PallasLookupRangeCheck > MyCircuit < Lookup > {
781
+ impl < Lookup : PallasLookupRangeCheck > MyEccCircuit < Lookup > {
736
782
fn new ( test_errors : bool ) -> Self {
737
783
Self {
738
784
test_errors,
@@ -742,12 +788,12 @@ pub(crate) mod tests {
742
788
}
743
789
744
790
#[ allow( non_snake_case) ]
745
- impl < Lookup : PallasLookupRangeCheck > Circuit < pallas:: Base > for MyCircuit < Lookup > {
791
+ impl < Lookup : PallasLookupRangeCheck > Circuit < pallas:: Base > for MyEccCircuit < Lookup > {
746
792
type Config = EccConfig < TestFixedBases , Lookup > ;
747
793
type FloorPlanner = SimpleFloorPlanner ;
748
794
749
795
fn without_witnesses ( & self ) -> Self {
750
- MyCircuit :: new ( false )
796
+ MyEccCircuit :: new ( false )
751
797
}
752
798
753
799
fn configure ( meta : & mut ConstraintSystem < pallas:: Base > ) -> Self :: Config {
@@ -796,7 +842,7 @@ pub(crate) mod tests {
796
842
797
843
// Load 10-bit lookup table. In the Action circuit, this will be
798
844
// provided by the Sinsemilla chip.
799
- config. lookup_config . load ( & mut layouter) ?;
845
+ config. lookup_config . load_range_check_table ( & mut layouter) ?;
800
846
801
847
// Generate a random non-identity point P
802
848
let p_val = pallas:: Point :: random ( rand:: rngs:: OsRng ) . to_affine ( ) ; // P
@@ -884,6 +930,14 @@ pub(crate) mod tests {
884
930
) ?;
885
931
}
886
932
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
+
887
941
// Test full-width fixed-base scalar multiplication
888
942
{
889
943
super :: chip:: mul_fixed:: full_width:: tests:: test_mul_fixed (
@@ -915,14 +969,14 @@ pub(crate) mod tests {
915
969
#[ test]
916
970
fn ecc_chip ( ) {
917
971
let k = 13 ;
918
- let circuit = MyCircuit :: < PallasLookupRangeCheckConfig > :: new ( true ) ;
972
+ let circuit = MyEccCircuit :: < PallasLookupRangeCheckConfig > :: new ( true ) ;
919
973
let prover = MockProver :: run ( k, & circuit, vec ! [ ] ) . unwrap ( ) ;
920
974
assert_eq ! ( prover. verify( ) , Ok ( ( ) ) )
921
975
}
922
976
923
977
#[ test]
924
978
fn test_ecc_chip_against_stored_circuit ( ) {
925
- let circuit = MyCircuit :: < PallasLookupRangeCheckConfig > :: new ( false ) ;
979
+ let circuit = MyEccCircuit :: < PallasLookupRangeCheckConfig > :: new ( false ) ;
926
980
test_against_stored_circuit ( circuit, "ecc_chip" , 3872 ) ;
927
981
}
928
982
@@ -935,7 +989,37 @@ pub(crate) mod tests {
935
989
root. fill ( & WHITE ) . unwrap ( ) ;
936
990
let root = root. titled ( "Ecc Chip Layout" , ( "sans-serif" , 60 ) ) . unwrap ( ) ;
937
991
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 ) ;
939
1023
halo2_proofs:: dev:: CircuitLayout :: default ( )
940
1024
. render ( 13 , & circuit, & root)
941
1025
. unwrap ( ) ;
0 commit comments