@@ -811,3 +811,125 @@ pub fn print_password(
811811 print_file. write_all ( & [ CR , FF ] ) ?;
812812 Ok ( ( ) )
813813}
814+
815+ #[ cfg( test) ]
816+ mod tests {
817+ use super :: * ;
818+
819+ // secret split into the feldman verifier & shares below
820+ const SECRET : & str =
821+ "f259a45c17624b9317d8e292050c46a0f3d7387724b4cd26dd94f8bd3d1c0e1a" ;
822+
823+ // verifier created and serialized to json by `new_split_wrap`
824+ const VERIFIER : & str = r#"
825+ {
826+ "generator": "036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
827+ "commitments": [
828+ "02315e9e3cd76d0917ecd60378b75259bbdf2e35a31f46c05a497409d5d89c69dc",
829+ "0250e4e04d42e92bc15eecbe0789f5ac4831abe962df6b1eaed897e4634df702e3",
830+ "02dfc3c60074cb4896163e7e188f8ec93d3bd1e2fd2ed68854c9324e4a56e94cc7"
831+ ]
832+ }"# ;
833+
834+ // shares dumped to the printer by `new_split_wrap`
835+ const SHARE_ARRAY : [ & str ; SHARES ] = [
836+ "01 b5b7dd6a 8ef8762f 0f266784 be191202 7b8a4b21 72fcb410 f28b2e1a e3669f9c" ,
837+ "02 042cfd2b 1ede9e78 d7827065 2d8c20ef 1cb43bf1 c722f2e3 a08ac387 b57b18f8" ,
838+ "03 ddb9039b c714c472 70ecfd33 53657366 51230043 6f56c6a8 cf074e89 ac1fc4d0" ,
839+ "04 425bf0bf 879ae818 db660def 2fa509f8 e221a80d 765153d1 a2d34dd7 d22d3321" ,
840+ "05 3215c494 6071096e 16eda298 c24ae4a6 497e28ab 2a41d768 036261f8 2063ae8d" ,
841+ ] ;
842+
843+ fn secret_bytes ( ) -> [ u8 ; KEY_LEN ] {
844+ let mut secret = [ 0u8 ; KEY_LEN ] ;
845+ hex:: decode_to_slice ( SECRET , & mut secret) . unwrap ( ) ;
846+
847+ secret
848+ }
849+
850+ fn deserialize_share ( share : & str ) -> Result < Share < { KEY_LEN + 1 } > > {
851+ // filter out whitespace to keep hex::decode happy
852+ let share: String =
853+ share. chars ( ) . filter ( |c| !c. is_whitespace ( ) ) . collect ( ) ;
854+ let share = hex:: decode ( share) ?;
855+
856+ Ok ( Share :: try_from ( & share[ ..] ) ?)
857+ }
858+
859+ #[ test]
860+ fn round_trip ( ) -> Result < ( ) > {
861+ use rand:: rngs:: ThreadRng ;
862+
863+ let secret = secret_bytes ( ) ;
864+ let secret_key = SecretKey :: from_be_bytes ( & secret) ?;
865+ let nzs = secret_key. to_nonzero_scalar ( ) ;
866+
867+ let mut rng = ThreadRng :: default ( ) ;
868+ let ( shares, verifier) = Feldman :: < THRESHOLD , SHARES > :: split_secret :: <
869+ Scalar ,
870+ ProjectivePoint ,
871+ ThreadRng ,
872+ { KEY_LEN + 1 } ,
873+ > ( * nzs. as_ref ( ) , None , & mut rng)
874+ . map_err ( |e| anyhow:: anyhow!( "failed to split secret: {}" , e) ) ?;
875+
876+ for s in & shares {
877+ assert ! ( verifier. verify( s) ) ;
878+ }
879+
880+ let scalar = Feldman :: < THRESHOLD , SHARES > :: combine_shares :: <
881+ Scalar ,
882+ { KEY_LEN + 1 } ,
883+ > ( & shares)
884+ . map_err ( |e| anyhow:: anyhow!( "failed to combine secret: {}" , e) ) ?;
885+
886+ let nzs_dup = NonZeroScalar :: from_repr ( scalar. to_repr ( ) ) . unwrap ( ) ;
887+ let sk_dup = SecretKey :: from ( nzs_dup) ;
888+ let new_secret: [ u8 ; KEY_LEN ] = sk_dup. to_be_bytes ( ) . try_into ( ) ?;
889+
890+ assert_eq ! ( new_secret, secret) ;
891+
892+ Ok ( ( ) )
893+ }
894+
895+ // deserialize a verifier & use it to verify the shares in SHARE_ARRAY
896+ #[ test]
897+ fn verify_shares ( ) -> Result < ( ) > {
898+ use vsss_rs:: FeldmanVerifier ;
899+
900+ let verifier: FeldmanVerifier <
901+ Scalar ,
902+ ProjectivePoint ,
903+ { KEY_LEN + 1 } ,
904+ > = serde_json:: from_str ( VERIFIER ) ?;
905+
906+ for share in SHARE_ARRAY {
907+ let share = deserialize_share ( share) ?;
908+ assert ! ( verifier. verify( & share) ) ;
909+ }
910+
911+ Ok ( ( ) )
912+ }
913+
914+ #[ test]
915+ fn recover_secret ( ) -> Result < ( ) > {
916+ let mut shares: Vec < Share < { KEY_LEN + 1 } > > = Vec :: new ( ) ;
917+ for share in SHARE_ARRAY {
918+ shares. push ( deserialize_share ( share) ?) ;
919+ }
920+
921+ let scalar = Feldman :: < THRESHOLD , SHARES > :: combine_shares :: <
922+ Scalar ,
923+ { KEY_LEN + 1 } ,
924+ > ( & shares)
925+ . map_err ( |e| anyhow:: anyhow!( "failed to combine secret: {}" , e) ) ?;
926+
927+ let nzs_dup = NonZeroScalar :: from_repr ( scalar. to_repr ( ) ) . unwrap ( ) ;
928+ let sk_dup = SecretKey :: from ( nzs_dup) ;
929+ let secret: [ u8 ; KEY_LEN ] = sk_dup. to_be_bytes ( ) . try_into ( ) ?;
930+
931+ assert_eq ! ( secret, secret_bytes( ) ) ;
932+
933+ Ok ( ( ) )
934+ }
935+ }
0 commit comments