@@ -311,3 +311,148 @@ impl<C: CurveAffine, EccChip: EccInstructions<C> + Clone + Debug> FixedPointShor
311
311
} )
312
312
}
313
313
}
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