88//! Common functionality between multiple OPRF modes.
99
1010use core:: convert:: TryFrom ;
11+ use core:: ops:: Add ;
1112
1213use derive_where:: derive_where;
1314use digest:: core_api:: BlockSizeUser ;
1415use digest:: { Digest , Output , OutputSizeUser } ;
1516use generic_array:: sequence:: Concat ;
16- use generic_array:: typenum:: { IsLess , IsLessOrEqual , Unsigned , U11 , U2 , U256 } ;
17+ use generic_array:: typenum:: { IsLess , IsLessOrEqual , Unsigned , U2 , U256 , U9 } ;
1718use generic_array:: { ArrayLength , GenericArray } ;
1819use rand_core:: { CryptoRng , RngCore } ;
1920use subtle:: ConstantTimeEq ;
@@ -33,7 +34,7 @@ pub(crate) const STR_DERIVE_KEYPAIR: [u8; 13] = *b"DeriveKeyPair";
3334pub ( crate ) const STR_COMPOSITE : [ u8 ; 9 ] = * b"Composite" ;
3435pub ( crate ) const STR_CHALLENGE : [ u8 ; 9 ] = * b"Challenge" ;
3536pub ( crate ) const STR_INFO : [ u8 ; 4 ] = * b"Info" ;
36- pub ( crate ) const STR_VOPRF : [ u8 ; 8 ] = * b"VOPRF10 -" ;
37+ pub ( crate ) const STR_OPRF : [ u8 ; 7 ] = * b"OPRFV1 -" ;
3738pub ( crate ) const STR_HASH_TO_SCALAR : [ u8 ; 13 ] = * b"HashToScalar-" ;
3839pub ( crate ) const STR_HASH_TO_GROUP : [ u8 ; 12 ] = * b"HashToGroup-" ;
3940
@@ -194,9 +195,9 @@ where
194195 & STR_CHALLENGE ,
195196 ] ;
196197
197- let dst = GenericArray :: from ( STR_HASH_TO_SCALAR ) . concat ( create_context_string :: < CS > ( mode) ) ;
198+ let dst = Dst :: new :: < CS , _ , _ > ( STR_HASH_TO_SCALAR , mode) ;
198199 // This can't fail, the size of the `input` is known.
199- let c_scalar = CS :: Group :: hash_to_scalar :: < CS :: Hash > ( & h2_input, & dst) . unwrap ( ) ;
200+ let c_scalar = CS :: Group :: hash_to_scalar :: < CS :: Hash > ( & h2_input, & dst. as_dst ( ) ) . unwrap ( ) ;
200201 let s_scalar = r - & ( c_scalar * & k) ;
201202
202203 Ok ( Proof { c_scalar, s_scalar } )
@@ -254,9 +255,9 @@ where
254255 & STR_CHALLENGE ,
255256 ] ;
256257
257- let dst = GenericArray :: from ( STR_HASH_TO_SCALAR ) . concat ( create_context_string :: < CS > ( mode) ) ;
258+ let dst = Dst :: new :: < CS , _ , _ > ( STR_HASH_TO_SCALAR , mode) ;
258259 // This can't fail, the size of the `input` is known.
259- let c = CS :: Group :: hash_to_scalar :: < CS :: Hash > ( & h2_input, & dst) . unwrap ( ) ;
260+ let c = CS :: Group :: hash_to_scalar :: < CS :: Hash > ( & h2_input, & dst. as_dst ( ) ) . unwrap ( ) ;
260261
261262 match c. ct_eq ( & proof. c_scalar ) . into ( ) {
262263 true => Ok ( ( ) ) ,
@@ -296,16 +297,16 @@ where
296297 let len = u16:: try_from ( c_slice. len ( ) ) . map_err ( |_| Error :: Batch ) ?;
297298
298299 // seedDST = "Seed-" || contextString
299- let seed_dst = GenericArray :: from ( STR_SEED ) . concat ( create_context_string :: < CS > ( mode) ) ;
300+ let seed_dst = Dst :: new :: < CS , _ , _ > ( STR_SEED , mode) ;
300301
301302 // h1Input = I2OSP(len(Bm), 2) || Bm ||
302303 // I2OSP(len(seedDST), 2) || seedDST
303304 // seed = Hash(h1Input)
304305 let seed = CS :: Hash :: new ( )
305306 . chain_update ( elem_len)
306307 . chain_update ( CS :: Group :: serialize_elem ( b) )
307- . chain_update ( i2osp_2_array ( & seed_dst) )
308- . chain_update ( seed_dst)
308+ . chain_update ( seed_dst. i2osp_2 ( ) )
309+ . chain_update_multi ( & seed_dst. as_dst ( ) )
309310 . finalize ( ) ;
310311 let seed_len = i2osp_2_array ( & seed) ;
311312
@@ -332,9 +333,9 @@ where
332333 & STR_COMPOSITE ,
333334 ] ;
334335
335- let dst = GenericArray :: from ( STR_HASH_TO_SCALAR ) . concat ( create_context_string :: < CS > ( mode) ) ;
336+ let dst = Dst :: new :: < CS , _ , _ > ( STR_HASH_TO_SCALAR , mode) ;
336337 // This can't fail, the size of the `input` is known.
337- let di = CS :: Group :: hash_to_scalar :: < CS :: Hash > ( & h2_input, & dst) . unwrap ( ) ;
338+ let di = CS :: Group :: hash_to_scalar :: < CS :: Hash > ( & h2_input, & dst. as_dst ( ) ) . unwrap ( ) ;
338339 m = c * & di + & m;
339340 z = match k_option {
340341 Some ( _) => z,
@@ -365,8 +366,7 @@ where
365366 <CS :: Hash as OutputSizeUser >:: OutputSize :
366367 IsLess < U256 > + IsLessOrEqual < <CS :: Hash as BlockSizeUser >:: BlockSize > ,
367368{
368- let context_string = create_context_string :: < CS > ( mode) ;
369- let dst = GenericArray :: from ( STR_DERIVE_KEYPAIR ) . concat ( context_string) ;
369+ let dst = Dst :: new :: < CS , _ , _ > ( STR_DERIVE_KEYPAIR , mode) ;
370370
371371 let info_len = i2osp_2 ( info. len ( ) ) . map_err ( |_| Error :: DeriveKeyPair ) ?;
372372
@@ -376,7 +376,7 @@ where
376376 // || contextString)
377377 let sk_s = CS :: Group :: hash_to_scalar :: < CS :: Hash > (
378378 & [ seed, & info_len, info, & counter. to_be_bytes ( ) ] ,
379- & dst,
379+ & dst. as_dst ( ) ,
380380 )
381381 . map_err ( |_| Error :: DeriveKeyPair ) ?;
382382
@@ -455,8 +455,8 @@ where
455455 <CS :: Hash as OutputSizeUser >:: OutputSize :
456456 IsLess < U256 > + IsLessOrEqual < <CS :: Hash as BlockSizeUser >:: BlockSize > ,
457457{
458- let dst = GenericArray :: from ( STR_HASH_TO_GROUP ) . concat ( create_context_string :: < CS > ( mode) ) ;
459- CS :: Group :: hash_to_curve :: < CS :: Hash > ( & [ input] , & dst) . map_err ( |_| Error :: Input )
458+ let dst = Dst :: new :: < CS , _ , _ > ( STR_HASH_TO_GROUP , mode) ;
459+ CS :: Group :: hash_to_curve :: < CS :: Hash > ( & [ input] , & dst. as_dst ( ) ) . map_err ( |_| Error :: Input )
460460}
461461
462462/// Internal function that finalizes the hash input for OPRF, VOPRF & POPRF.
@@ -497,16 +497,64 @@ where
497497 . finalize ( ) )
498498}
499499
500- /// Generates the contextString parameter as defined in
501- /// <https://datatracker.ietf.org/doc/draft-irtf-cfrg-voprf/>
502- pub ( crate ) fn create_context_string < CS : CipherSuite > ( mode : Mode ) -> GenericArray < u8 , U11 >
500+ pub ( crate ) struct Dst < L : ArrayLength < u8 > > {
501+ dst_1 : GenericArray < u8 , L > ,
502+ dst_2 : & ' static str ,
503+ }
504+
505+ impl < L : ArrayLength < u8 > > Dst < L > {
506+ pub ( crate ) fn new < CS : CipherSuite , T , TL : ArrayLength < u8 > > ( par_1 : T , mode : Mode ) -> Self
507+ where
508+ T : Into < GenericArray < u8 , TL > > ,
509+ TL : Add < U9 , Output = L > ,
510+ <CS :: Hash as OutputSizeUser >:: OutputSize :
511+ IsLess < U256 > + IsLessOrEqual < <CS :: Hash as BlockSizeUser >:: BlockSize > ,
512+ {
513+ let par_1 = par_1. into ( ) ;
514+ // Generates the contextString parameter as defined in
515+ // <https://datatracker.ietf.org/doc/draft-irtf-cfrg-voprf/>
516+ let par_2 = GenericArray :: from ( STR_OPRF )
517+ . concat ( [ mode. to_u8 ( ) ] . into ( ) )
518+ . concat ( [ b'-' ] . into ( ) ) ;
519+
520+ let dst_1 = par_1. concat ( par_2) ;
521+ let dst_2 = CS :: ID ;
522+
523+ assert ! (
524+ L :: USIZE + dst_2. len( ) <= u16 :: MAX . into( ) ,
525+ "constructed DST longer then {}" ,
526+ u16 :: MAX
527+ ) ;
528+
529+ Self { dst_1, dst_2 }
530+ }
531+
532+ pub ( crate ) fn as_dst ( & self ) -> [ & [ u8 ] ; 2 ] {
533+ [ & self . dst_1 , self . dst_2 . as_bytes ( ) ]
534+ }
535+
536+ pub ( crate ) fn i2osp_2 ( & self ) -> [ u8 ; 2 ] {
537+ u16:: try_from ( L :: USIZE + self . dst_2 . len ( ) )
538+ . unwrap ( )
539+ . to_be_bytes ( )
540+ }
541+ }
542+
543+ trait DigestExt {
544+ fn chain_update_multi ( self , data : & [ & [ u8 ] ] ) -> Self ;
545+ }
546+
547+ impl < T > DigestExt for T
503548where
504- <CS :: Hash as OutputSizeUser >:: OutputSize :
505- IsLess < U256 > + IsLessOrEqual < <CS :: Hash as BlockSizeUser >:: BlockSize > ,
549+ T : Digest ,
506550{
507- GenericArray :: from ( STR_VOPRF )
508- . concat ( [ mode. to_u8 ( ) ] . into ( ) )
509- . concat ( CS :: ID . to_be_bytes ( ) . into ( ) )
551+ fn chain_update_multi ( mut self , datas : & [ & [ u8 ] ] ) -> Self {
552+ for data in datas {
553+ self . update ( data)
554+ }
555+
556+ self
557+ }
510558}
511559
512560///////////////////////
0 commit comments