@@ -57,18 +57,14 @@ use scalar_mul::VartimeMultiscalarMul;
57
57
pub use serde;
58
58
pub use signature:: Signature ;
59
59
pub use signing_key:: SigningKey ;
60
- pub use traits:: { Ciphersuite , Element , Field , Group , Scalar } ;
60
+ pub use traits:: { Ciphersuite , Element , Field , Group , Scalar , SigningParameters } ;
61
61
pub use verifying_key:: VerifyingKey ;
62
62
63
63
/// A type refinement for the scalar field element representing the per-message _[challenge]_.
64
64
///
65
65
/// [challenge]: https://datatracker.ietf.org/doc/html/rfc9591#name-signature-challenge-computa
66
66
#[ derive( Copy , Clone ) ]
67
- #[ cfg_attr( feature = "internals" , visibility:: make( pub ) ) ]
68
- #[ cfg_attr( docsrs, doc( cfg( feature = "internals" ) ) ) ]
69
- pub ( crate ) struct Challenge < C : Ciphersuite > (
70
- pub ( crate ) <<C :: Group as Group >:: Field as Field >:: Scalar ,
71
- ) ;
67
+ pub struct Challenge < C : Ciphersuite > ( pub ( crate ) <<C :: Group as Group >:: Field as Field >:: Scalar ) ;
72
68
73
69
impl < C > Challenge < C >
74
70
where
@@ -192,9 +188,7 @@ where
192
188
///
193
189
/// <https://github.com/cfrg/draft-irtf-cfrg-frost/blob/master/draft-irtf-cfrg-frost.md>
194
190
#[ derive( Clone , PartialEq , Eq ) ]
195
- #[ cfg_attr( feature = "internals" , visibility:: make( pub ) ) ]
196
- #[ cfg_attr( docsrs, doc( cfg( feature = "internals" ) ) ) ]
197
- pub ( crate ) struct BindingFactor < C : Ciphersuite > ( Scalar < C > ) ;
191
+ pub struct BindingFactor < C : Ciphersuite > ( Scalar < C > ) ;
198
192
199
193
impl < C > BindingFactor < C >
200
194
where
@@ -357,6 +351,54 @@ fn derive_interpolating_value<C: Ciphersuite>(
357
351
)
358
352
}
359
353
354
+ /// The data which the group's signature should commit to. Includes
355
+ /// a message byte vector, and a set of ciphersuite-specific parameters.
356
+ #[ cfg_attr( feature = "serde" , derive( serde:: Serialize , serde:: Deserialize ) ) ]
357
+ #[ cfg_attr( feature = "serde" , serde( bound = "C: Ciphersuite" ) ) ]
358
+ #[ derive( Clone , Debug , PartialEq , Eq , Getters ) ]
359
+ pub struct SigningTarget < C : Ciphersuite > {
360
+ #[ cfg_attr(
361
+ feature = "serde" ,
362
+ serde(
363
+ serialize_with = "serdect::slice::serialize_hex_lower_or_bin" ,
364
+ deserialize_with = "serdect::slice::deserialize_hex_or_bin_vec"
365
+ )
366
+ ) ]
367
+ message : Vec < u8 > ,
368
+
369
+ #[ cfg_attr( feature = "serde" , serde( default ) ) ]
370
+ sig_params : C :: SigningParameters ,
371
+ }
372
+
373
+ impl < C : Ciphersuite > SigningTarget < C > {
374
+ /// Construct a signing target from a message and additional signing parameters.
375
+ pub fn new < T : AsRef < [ u8 ] > , P : Into < C :: SigningParameters > > (
376
+ message : T ,
377
+ sig_params : P ,
378
+ ) -> SigningTarget < C > {
379
+ SigningTarget {
380
+ message : message. as_ref ( ) . to_vec ( ) ,
381
+ sig_params : sig_params. into ( ) ,
382
+ }
383
+ }
384
+
385
+ /// Constructs a signing target from an arbitrary message.
386
+ /// This populates [the `sig_params` field][SigningTarget::sig_params] with
387
+ /// the [`Default`] instance of the [`Ciphersuite::SigningParameters`].
388
+ pub fn from_message < T : AsRef < [ u8 ] > > ( message : T ) -> SigningTarget < C > {
389
+ SigningTarget {
390
+ message : message. as_ref ( ) . to_vec ( ) ,
391
+ sig_params : C :: SigningParameters :: default ( ) ,
392
+ }
393
+ }
394
+ }
395
+
396
+ impl < C : Ciphersuite , T : AsRef < [ u8 ] > > From < T > for SigningTarget < C > {
397
+ fn from ( message : T ) -> Self {
398
+ Self :: from_message ( message)
399
+ }
400
+ }
401
+
360
402
/// Generated by the coordinator of the signing operation and distributed to
361
403
/// each signing party
362
404
#[ derive( Clone , Debug , PartialEq , Eq , Getters ) ]
@@ -370,18 +412,9 @@ pub struct SigningPackage<C: Ciphersuite> {
370
412
/// The set of commitments participants published in the first round of the
371
413
/// protocol.
372
414
signing_commitments : BTreeMap < Identifier < C > , round1:: SigningCommitments < C > > ,
373
- /// Message which each participant will sign.
374
- ///
375
- /// Each signer should perform protocol-specific verification on the
376
- /// message.
377
- #[ cfg_attr(
378
- feature = "serde" ,
379
- serde(
380
- serialize_with = "serdect::slice::serialize_hex_lower_or_bin" ,
381
- deserialize_with = "serdect::slice::deserialize_hex_or_bin_vec"
382
- )
383
- ) ]
384
- message : Vec < u8 > ,
415
+ /// The message and parameters which each participant will use to sign.
416
+ /// Each signer should perform protocol-specific verification on the signing target.
417
+ sig_target : SigningTarget < C > ,
385
418
}
386
419
387
420
impl < C > SigningPackage < C >
@@ -391,14 +424,19 @@ where
391
424
/// Create a new `SigningPackage`
392
425
///
393
426
/// The `signing_commitments` are sorted by participant `identifier`.
427
+ ///
428
+ /// The `sig_target` can be any bytes-like type that implements `AsRef<[u8]>`.
429
+ /// Some ciphersuites like `frost-secp256k1-tr` allow customization of the signing
430
+ /// process by embedding additional parameters into a [`SigningTarget`], but this
431
+ /// is optional and not required by most ciphersuites.
394
432
pub fn new (
395
433
signing_commitments : BTreeMap < Identifier < C > , round1:: SigningCommitments < C > > ,
396
- message : & [ u8 ] ,
434
+ sig_target : impl Into < SigningTarget < C > > ,
397
435
) -> SigningPackage < C > {
398
436
SigningPackage {
399
437
header : Header :: default ( ) ,
400
438
signing_commitments,
401
- message : message . to_vec ( ) ,
439
+ sig_target : sig_target . into ( ) ,
402
440
}
403
441
}
404
442
@@ -410,6 +448,11 @@ where
410
448
self . signing_commitments . get ( identifier) . copied ( )
411
449
}
412
450
451
+ /// Returns the message to be signed.
452
+ pub fn message ( & self ) -> & [ u8 ] {
453
+ & self . sig_target . message
454
+ }
455
+
413
456
/// Compute the preimages to H1 to compute the per-signer binding factors
414
457
// We separate this out into its own method so it can be tested
415
458
#[ cfg_attr( feature = "internals" , visibility:: make( pub ) ) ]
@@ -430,7 +473,7 @@ where
430
473
// The message is hashed with H4 to force the variable-length message
431
474
// into a fixed-length byte string, same for hashing the variable-sized
432
475
// (between runs of the protocol) set of group commitments, but with H5.
433
- binding_factor_input_prefix. extend_from_slice ( C :: H4 ( self . message . as_slice ( ) ) . as_ref ( ) ) ;
476
+ binding_factor_input_prefix. extend_from_slice ( C :: H4 ( self . message ( ) ) . as_ref ( ) ) ;
434
477
binding_factor_input_prefix. extend_from_slice (
435
478
C :: H5 ( & round1:: encode_group_commitments ( self . signing_commitments ( ) ) ?[ ..] ) . as_ref ( ) ,
436
479
) ;
@@ -469,9 +512,7 @@ where
469
512
/// The product of all signers' individual commitments, published as part of the
470
513
/// final signature.
471
514
#[ derive( Clone , PartialEq , Eq ) ]
472
- #[ cfg_attr( feature = "internals" , visibility:: make( pub ) ) ]
473
- #[ cfg_attr( docsrs, doc( cfg( feature = "internals" ) ) ) ]
474
- pub ( crate ) struct GroupCommitment < C : Ciphersuite > ( pub ( crate ) Element < C > ) ;
515
+ pub struct GroupCommitment < C : Ciphersuite > ( pub ( crate ) Element < C > ) ;
475
516
476
517
impl < C > GroupCommitment < C >
477
518
where
@@ -482,6 +523,12 @@ where
482
523
pub fn to_element ( self ) -> <C :: Group as Group >:: Element {
483
524
self . 0
484
525
}
526
+
527
+ /// Check if group commitment is odd
528
+ #[ cfg( feature = "internals" ) ]
529
+ pub fn y_is_odd ( & self ) -> bool {
530
+ <C :: Group as Group >:: y_is_odd ( & self . 0 )
531
+ }
485
532
}
486
533
487
534
/// Generates the group commitment which is published as part of the joint
@@ -589,6 +636,7 @@ where
589
636
compute_binding_factor_list ( signing_package, & pubkeys. verifying_key , & [ ] ) ?;
590
637
// Compute the group commitment from signing commitments produced in round one.
591
638
let group_commitment = compute_group_commitment ( signing_package, & binding_factor_list) ?;
639
+ let R = <C >:: effective_nonce_element ( group_commitment. 0 ) ;
592
640
593
641
// The aggregation of the signature shares by summing them up, resulting in
594
642
// a plain Schnorr signature.
@@ -602,15 +650,13 @@ where
602
650
z = z + signature_share. to_scalar ( ) ;
603
651
}
604
652
605
- let signature = Signature {
606
- R : group_commitment. 0 ,
607
- z,
608
- } ;
653
+ let signature: Signature < C > =
654
+ <C >:: aggregate_sig_finalize ( z, R , & pubkeys. verifying_key , & signing_package. sig_target ) ?;
609
655
610
656
// Verify the aggregate signature
611
657
let verification_result = pubkeys
612
658
. verifying_key
613
- . verify ( signing_package. message ( ) , & signature) ;
659
+ . verify ( signing_package. sig_target . clone ( ) , & signature) ;
614
660
615
661
// Only if the verification of the aggregate signature failed; verify each share to find the cheater.
616
662
// This approach is more efficient since we don't need to verify all shares
@@ -619,6 +665,7 @@ where
619
665
if verification_result. is_err ( ) {
620
666
detect_cheater (
621
667
group_commitment,
668
+ & R ,
622
669
pubkeys,
623
670
signing_package,
624
671
signature_shares,
@@ -631,21 +678,21 @@ where
631
678
632
679
Ok ( signature)
633
680
}
634
-
635
681
/// Optional cheater detection feature
636
682
/// Each share is verified to find the cheater
637
683
fn detect_cheater < C : Ciphersuite > (
638
684
group_commitment : GroupCommitment < C > ,
685
+ effective_group_commitment : & Element < C > ,
639
686
pubkeys : & keys:: PublicKeyPackage < C > ,
640
687
signing_package : & SigningPackage < C > ,
641
688
signature_shares : & BTreeMap < Identifier < C > , round2:: SignatureShare < C > > ,
642
689
binding_factor_list : & BindingFactorList < C > ,
643
690
) -> Result < ( ) , Error < C > > {
644
691
// Compute the per-message challenge.
645
- let challenge = crate :: challenge :: < C > (
646
- & group_commitment . 0 ,
692
+ let challenge = <C >:: challenge (
693
+ effective_group_commitment ,
647
694
& pubkeys. verifying_key ,
648
- signing_package. message ( ) . as_slice ( ) ,
695
+ & signing_package. sig_target ,
649
696
) ?;
650
697
651
698
// Verify the signature shares.
@@ -677,6 +724,9 @@ fn detect_cheater<C: Ciphersuite>(
677
724
signer_pubkey,
678
725
lambda_i,
679
726
& challenge,
727
+ & group_commitment,
728
+ & pubkeys. verifying_key ,
729
+ & signing_package. sig_target . sig_params ,
680
730
) ?;
681
731
}
682
732
0 commit comments