@@ -6,7 +6,7 @@ use std::fmt::Debug;
6
6
pub mod chip;
7
7
mod message;
8
8
9
- // pub use chip::{SinsemillaChip, SinsemillaConfig};
9
+ pub use chip:: { SinsemillaChip , SinsemillaConfig } ;
10
10
11
11
/// The set of circuit instructions required to use the [`Sinsemilla`](https://zcash.github.io/halo2/design/gadgets/sinsemilla.html) gadget.
12
12
/// This trait is bounded on two constant parameters: `K`, the number of bits
@@ -303,3 +303,200 @@ where
303
303
p. map ( |p| p. extract_p ( ) )
304
304
}
305
305
}
306
+
307
+ #[ cfg( test) ]
308
+ mod tests {
309
+ use halo2:: {
310
+ arithmetic:: { CurveAffine , FieldExt } ,
311
+ circuit:: { layouter:: SingleChipLayouter , Layouter } ,
312
+ dev:: MockProver ,
313
+ pasta:: pallas,
314
+ plonk:: { Assignment , Circuit , ConstraintSystem , Error } ,
315
+ } ;
316
+
317
+ use super :: {
318
+ chip:: { SinsemillaCommitDomains , SinsemillaHashDomains } ,
319
+ CommitDomain , HashDomain , Message , SinsemillaChip , SinsemillaConfig ,
320
+ SinsemillaInstructions ,
321
+ } ;
322
+
323
+ use crate :: circuit:: gadget:: {
324
+ ecc:: {
325
+ chip:: { EccChip , EccConfig } ,
326
+ ScalarFixed ,
327
+ } ,
328
+ utilities:: Var ,
329
+ } ;
330
+
331
+ use std:: convert:: TryInto ;
332
+
333
+ struct MyCircuit < C : CurveAffine , const K : usize , const MAX_WORDS : usize > {
334
+ _marker : std:: marker:: PhantomData < C > ,
335
+ }
336
+
337
+ impl < C : CurveAffine , const K : usize , const MAX_WORDS : usize > Circuit < C :: Base >
338
+ for MyCircuit < C , K , MAX_WORDS >
339
+ {
340
+ type Config = (
341
+ EccConfig ,
342
+ SinsemillaConfig < C , K , MAX_WORDS > ,
343
+ SinsemillaConfig < C , K , MAX_WORDS > ,
344
+ ) ;
345
+
346
+ #[ allow( non_snake_case) ]
347
+ fn configure ( meta : & mut ConstraintSystem < C :: Base > ) -> Self :: Config {
348
+ let advices = [
349
+ meta. advice_column ( ) ,
350
+ meta. advice_column ( ) ,
351
+ meta. advice_column ( ) ,
352
+ meta. advice_column ( ) ,
353
+ meta. advice_column ( ) ,
354
+ meta. advice_column ( ) ,
355
+ meta. advice_column ( ) ,
356
+ meta. advice_column ( ) ,
357
+ meta. advice_column ( ) ,
358
+ meta. advice_column ( ) ,
359
+ ] ;
360
+ let perm = meta. permutation (
361
+ & advices
362
+ . iter ( )
363
+ . map ( |advice| ( * advice) . into ( ) )
364
+ . collect :: < Vec < _ > > ( ) ,
365
+ ) ;
366
+
367
+ let ecc_config = EccChip :: < C > :: configure ( meta, advices, perm. clone ( ) ) ;
368
+
369
+ // Fixed columns for the Sinsemilla generator lookup table
370
+ let lookup = (
371
+ meta. fixed_column ( ) ,
372
+ meta. fixed_column ( ) ,
373
+ meta. fixed_column ( ) ,
374
+ ) ;
375
+
376
+ let config1 = SinsemillaChip :: < C , K , MAX_WORDS > :: configure (
377
+ meta,
378
+ advices[ ..5 ] . try_into ( ) . unwrap ( ) ,
379
+ lookup,
380
+ perm. clone ( ) ,
381
+ ) ;
382
+ let config2 = SinsemillaChip :: < C , K , MAX_WORDS > :: configure (
383
+ meta,
384
+ advices[ 5 ..] . try_into ( ) . unwrap ( ) ,
385
+ lookup,
386
+ perm,
387
+ ) ;
388
+ ( ecc_config, config1, config2)
389
+ }
390
+
391
+ fn synthesize (
392
+ & self ,
393
+ cs : & mut impl Assignment < C :: Base > ,
394
+ config : Self :: Config ,
395
+ ) -> Result < ( ) , Error > {
396
+ let mut layouter = SingleChipLayouter :: new ( cs) ?;
397
+ let ecc_chip = EccChip :: < C > :: construct ( config. 0 ) ;
398
+
399
+ // The two `SinsemillaChip`s share the same lookup table.
400
+ SinsemillaChip :: < C , K , MAX_WORDS > :: load ( config. 1 . clone ( ) , & mut layouter) ?;
401
+
402
+ // This MerkleCRH example is purely for illustrative purposes.
403
+ // It is not an implementation of the Orchard protocol spec.
404
+ {
405
+ let chip1 = SinsemillaChip :: < C , K , MAX_WORDS > :: construct ( config. 1 ) ;
406
+
407
+ let merkle_crh = HashDomain :: new (
408
+ chip1. clone ( ) ,
409
+ ecc_chip. clone ( ) ,
410
+ & SinsemillaHashDomains :: MerkleCrh ,
411
+ ) ;
412
+
413
+ // Left leaf
414
+ let left = {
415
+ let left: Vec < Option < bool > > =
416
+ ( 0 ..250 ) . map ( |_| Some ( rand:: random :: < bool > ( ) ) ) . collect ( ) ;
417
+ let left = Message :: from_bitstring (
418
+ chip1. clone ( ) ,
419
+ layouter. namespace ( || "witness left" ) ,
420
+ left,
421
+ 25 ,
422
+ ) ?;
423
+ let left = merkle_crh. hash_to_point ( layouter. namespace ( || "left" ) , left) ?;
424
+ let left = left. extract_p ( ) ;
425
+ chip1. witness_message_piece_field (
426
+ layouter. namespace ( || "witness left piece" ) ,
427
+ left. inner ( ) . value ( ) ,
428
+ 25 ,
429
+ ) ?
430
+ } ;
431
+
432
+ // Right leaf
433
+ let right = {
434
+ let right: Vec < Option < bool > > =
435
+ ( 0 ..250 ) . map ( |_| Some ( rand:: random :: < bool > ( ) ) ) . collect ( ) ;
436
+ let right = Message :: from_bitstring (
437
+ chip1. clone ( ) ,
438
+ layouter. namespace ( || "witness right" ) ,
439
+ right,
440
+ 25 ,
441
+ ) ?;
442
+ let right = merkle_crh. hash_to_point ( layouter. namespace ( || "right" ) , right) ?;
443
+ let right = right. extract_p ( ) ;
444
+ chip1. witness_message_piece_field (
445
+ layouter. namespace ( || "witness left piece" ) ,
446
+ right. inner ( ) . value ( ) ,
447
+ 25 ,
448
+ ) ?
449
+ } ;
450
+
451
+ // Layer 0
452
+ let l = {
453
+ let merkle_depth_orchard = 32 ;
454
+ let layer = 0 ;
455
+ let l = C :: Base :: from_u64 ( merkle_depth_orchard - 1 - layer) ;
456
+ chip1. witness_message_piece_field ( layouter. namespace ( || "l" ) , Some ( l) , 1 ) ?
457
+ } ;
458
+
459
+ // Parent
460
+ let parent = Message :: from_pieces ( chip1, vec ! [ l, left, right] ) ;
461
+ merkle_crh. hash_to_point ( layouter. namespace ( || "parent" ) , parent) ?;
462
+ }
463
+
464
+ {
465
+ let chip2 = SinsemillaChip :: < C , K , MAX_WORDS > :: construct ( config. 2 ) ;
466
+
467
+ let commit_ivk = CommitDomain :: new (
468
+ chip2. clone ( ) ,
469
+ ecc_chip. clone ( ) ,
470
+ & SinsemillaCommitDomains :: CommitIvk ,
471
+ ) ;
472
+ let r = ScalarFixed :: < C , EccChip < C > > :: new (
473
+ ecc_chip,
474
+ layouter. namespace ( || "r" ) ,
475
+ Some ( C :: Scalar :: rand ( ) ) ,
476
+ ) ?;
477
+ let message: Vec < Option < bool > > =
478
+ ( 0 ..500 ) . map ( |_| Some ( rand:: random :: < bool > ( ) ) ) . collect ( ) ;
479
+ let message = Message :: from_bitstring (
480
+ chip2,
481
+ layouter. namespace ( || "witness message" ) ,
482
+ message,
483
+ 50 ,
484
+ ) ?;
485
+ commit_ivk. commit ( layouter. namespace ( || "commit" ) , message, r) ?;
486
+ }
487
+
488
+ Ok ( ( ) )
489
+ }
490
+ }
491
+
492
+ #[ test]
493
+ fn sinsemilla ( ) {
494
+ use crate :: primitives:: sinsemilla:: { C , K } ;
495
+ let k = 11 ;
496
+ let circuit = MyCircuit :: < pallas:: Affine , K , C > {
497
+ _marker : std:: marker:: PhantomData ,
498
+ } ;
499
+ let prover = MockProver :: run ( k, & circuit, vec ! [ ] ) . unwrap ( ) ;
500
+ assert_eq ! ( prover. verify( ) , Ok ( ( ) ) )
501
+ }
502
+ }
0 commit comments