@@ -10,13 +10,18 @@ use elliptic_curve::{
10
10
point:: { AffineCoordinates , NonIdentity } ,
11
11
zeroize:: DefaultIsZeroes ,
12
12
} ;
13
+ use hash2curve:: { ExpandMsgXof , GroupDigest } ;
13
14
use rand_core:: TryRngCore ;
15
+ use sha3:: Shake256 ;
14
16
use subtle:: { Choice , ConditionallySelectable , ConstantTimeEq , CtOption } ;
15
17
16
- use super :: { MontgomeryScalar , MontgomeryXpoint , ProjectiveMontgomeryXpoint } ;
18
+ use super :: {
19
+ DEFAULT_ENCODE_TO_CURVE_SUITE , DEFAULT_HASH_TO_CURVE_SUITE , MontgomeryScalar , MontgomeryXpoint ,
20
+ ProjectiveMontgomeryXpoint ,
21
+ } ;
17
22
use crate :: constants:: MONTGOMERY_BASEPOINT_ORDER ;
18
23
use crate :: field:: { ConstMontyType , FieldElement } ;
19
- use crate :: { AffinePoint , Curve448FieldBytes } ;
24
+ use crate :: { AffinePoint , Curve448 , Curve448FieldBytes } ;
20
25
21
26
/// A point in Montgomery form including the y-coordinate.
22
27
#[ derive( Copy , Clone , Debug , Default , Eq ) ]
@@ -195,6 +200,27 @@ impl ProjectiveMontgomeryPoint {
195
200
pub ( crate ) fn new ( U : FieldElement , V : FieldElement , W : FieldElement ) -> Self {
196
201
Self { U , V , W }
197
202
}
203
+
204
+ /// Hash a message to a point on the curve
205
+ ///
206
+ /// Hash using the default domain separation tag and hash function.
207
+ /// For more control see [`GroupDigest::hash_from_bytes()`].
208
+ pub fn hash_with_defaults ( msg : & [ u8 ] ) -> Self {
209
+ Curve448 :: hash_from_bytes :: < ExpandMsgXof < Shake256 > > ( & [ msg] , & [ DEFAULT_HASH_TO_CURVE_SUITE ] )
210
+ . expect ( "should never fail with the given `ExpandMsg` and `dst`" )
211
+ }
212
+
213
+ /// Encode a message to a point on the curve
214
+ ///
215
+ /// Encode using the default domain separation tag and hash function.
216
+ /// For more control see [`GroupDigest::encode_from_bytes()`].
217
+ pub fn encode_with_defaults ( msg : & [ u8 ] ) -> Self {
218
+ Curve448 :: encode_from_bytes :: < ExpandMsgXof < Shake256 > > (
219
+ & [ msg] ,
220
+ & [ DEFAULT_ENCODE_TO_CURVE_SUITE ] ,
221
+ )
222
+ . expect ( "should never fail with the given `ExpandMsg` and `dst`" )
223
+ }
198
224
}
199
225
200
226
impl ConditionallySelectable for ProjectiveMontgomeryPoint {
@@ -303,11 +329,13 @@ impl CofactorGroup for ProjectiveMontgomeryPoint {
303
329
impl Group for ProjectiveMontgomeryPoint {
304
330
type Scalar = MontgomeryScalar ;
305
331
306
- fn try_from_rng < R > ( _rng : & mut R ) -> Result < Self , R :: Error >
332
+ fn try_from_rng < R > ( rng : & mut R ) -> Result < Self , R :: Error >
307
333
where
308
334
R : TryRngCore + ?Sized ,
309
335
{
310
- todo ! ( )
336
+ let mut uniform_bytes = [ 0u8 ; 112 ] ;
337
+ rng. try_fill_bytes ( & mut uniform_bytes) ?;
338
+ Ok ( Self :: hash_with_defaults ( & uniform_bytes) )
311
339
}
312
340
313
341
fn identity ( ) -> Self {
@@ -447,6 +475,7 @@ impl TryFrom<ProjectiveMontgomeryPoint> for NonIdentity<ProjectiveMontgomeryPoin
447
475
mod tests {
448
476
use super :: * ;
449
477
use crate :: EdwardsPoint ;
478
+ use hex_literal:: hex;
450
479
451
480
#[ test]
452
481
fn to_edwards ( ) {
@@ -491,4 +520,56 @@ mod tests {
491
520
492
521
assert_eq ! ( identity, x_identity) ;
493
522
}
523
+
524
+ #[ test]
525
+ fn hash_with_test_vectors ( ) {
526
+ const DST : & [ u8 ] = b"QUUX-V01-CS02-with-curve448_XOF:SHAKE256_ELL2_RO_" ;
527
+ const MSGS : & [ ( & [ u8 ] , [ u8 ; 56 ] , [ u8 ; 56 ] ) ] = & [
528
+ ( b"" , hex ! ( "5ea5ff623d27c75e73717514134e73e419f831a875ca9e82915fdfc7069d0a9f8b532cfb32b1d8dd04ddeedbe3fa1d0d681c01e825d6a9ea" ) , hex ! ( "afadd8de789f8f8e3516efbbe313a7eba364c939ecba00dabf4ced5c563b18e70a284c17d8f46b564c4e6ce11784a3825d941116622128c1" ) ) ,
529
+ ( b"abc" , hex ! ( "9b2f7ce34878d7cebf34c582db14958308ea09366d1ec71f646411d3de0ae564d082b06f40cd30dfc08d9fb7cb21df390cf207806ad9d0e4" ) , hex ! ( "138a0eef0a4993ea696152ed7db61f7ddb4e8100573591e7466d61c0c568ecaec939e36a84d276f34c402526d8989a96e99760c4869ed633" ) ) ,
530
+ ( b"abcdef0123456789" , hex ! ( "f54ecd14b85a50eeeee0618452df3a75be7bfba11da5118774ae4ea55ac204e153f77285d780c4acee6c96abe3577a0c0b00be6e790cf194" ) , hex ! ( "935247a64bf78c107069943c7e3ecc52acb27ce4a3230407c8357341685ea2152e8c3da93f8cd77da1bddb5bb759c6e7ae7d516dced42850" ) ) ,
531
+ ( b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq" , hex ! ( "5bd67c4f88adf6beb10f7e0d0054659776a55c97b809ec8b3101729e104fd0f684e103792f267fd87cc4afc25a073956ef4f268fb02824d5" ) , hex ! ( "da1f5cb16a352719e4cb064cf47ba72aeba7752d03e8ca2c56229f419b4ef378785a5af1a53dd7ab4d467c1f92f7b139b3752faf29c96432" ) ) ,
532
+ ( b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" , hex ! ( "ea441c10b3636ecedd5c0dfcae96384cc40de8390a0ab648765b4508da12c586d55dc981275776507ebca0e4d1bcaa302bb69dcfa31b3451" ) , hex ! ( "fee0192d49bcc0c28d954763c2cbe739b9265c4bebe3883803c64971220cfda60b9ac99ad986cd908c0534b260b5cfca46f6c2b0f3f21bda" ) ) ,
533
+ ] ;
534
+
535
+ for ( msg, x, y) in MSGS {
536
+ let p = Curve448 :: hash_from_bytes :: < ExpandMsgXof < Shake256 > > ( & [ msg] , & [ DST ] )
537
+ . unwrap ( )
538
+ . to_affine ( ) ;
539
+ let mut xx = [ 0u8 ; 56 ] ;
540
+ xx. copy_from_slice ( & x[ ..] ) ;
541
+ xx. reverse ( ) ;
542
+ let mut yy = [ 0u8 ; 56 ] ;
543
+ yy. copy_from_slice ( & y[ ..] ) ;
544
+ yy. reverse ( ) ;
545
+ assert_eq ! ( p. x( ) , xx) ;
546
+ assert_eq ! ( p. y( ) , yy) ;
547
+ }
548
+ }
549
+
550
+ #[ test]
551
+ fn encode_with_test_vectors ( ) {
552
+ const DST : & [ u8 ] = b"QUUX-V01-CS02-with-curve448_XOF:SHAKE256_ELL2_NU_" ;
553
+ const MSGS : & [ ( & [ u8 ] , [ u8 ; 56 ] , [ u8 ; 56 ] ) ] = & [
554
+ ( b"" , hex ! ( "b65e8dbb279fd656f926f68d463b13ca7a982b32f5da9c7cc58afcf6199e4729863fb75ca9ae3c95c6887d95a5102637a1c5c40ff0aafadc" ) , hex ! ( "ea1ea211cf29eca11c057fe8248181591a19f6ac51d45843a65d4bb8b71bc83a64c771ed7686218a278ef1c5d620f3d26b53162188645453" ) ) ,
555
+ ( b"abc" , hex ! ( "51aceca4fa95854bbaba58d8a5e17a86c07acadef32e1188cafda26232131800002cc2f27c7aec454e5e0c615bddffb7df6a5f7f0f14793f" ) , hex ! ( "c590c9246eb28b08dee816d608ef233ea5d76e305dc458774a1e1bd880387e6734219e2018e4aa50a49486dce0ba8740065da37e6cf5212c" ) ) ,
556
+ ( b"abcdef0123456789" , hex ! ( "c6d65987f146b8d0cb5d2c44e1872ac3af1f458f6a8bd8c232ffe8b9d09496229a5a27f350eb7d97305bcc4e0f38328718352e8e3129ed71" ) , hex ! ( "4d2f901bf333fdc4135b954f20d59207e9f6a4ecf88ce5af11c892b44f79766ec4ecc9f60d669b95ca8940f39b1b7044140ac2040c1bf659" ) ) ,
557
+ ( b"q128_qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq" , hex ! ( "9b8d008863beb4a02fb9e4efefd2eba867307fb1c7ce01746115d32e1db551bb254e8e3e4532d5c74a83949a69a60519ecc9178083cbe943" ) , hex ! ( "346a1fca454d1e67c628437c270ec0f0c4256bb774fe6c0e49de7004ff6d9199e2cd99d8f7575a96aafc4dc8db1811ba0a44317581f41371" ) ) ,
558
+ ( b"a512_aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" , hex ! ( "8746dc34799112d1f20acda9d7f722c9abb29b1fb6b7e9e566983843c20bd7c9bfad21b45c5166b808d2f5d44e188f1fdaf29cdee8a72e4c" ) , hex ! ( "7c1293484c9287c298a1a0600c64347eee8530acf563cd8705e05728274d8cd8101835f8003b6f3b78b5beb28f5be188a3d7bce1ec5a36b1" ) ) ,
559
+ ] ;
560
+
561
+ for ( msg, x, y) in MSGS {
562
+ let p = Curve448 :: encode_from_bytes :: < ExpandMsgXof < Shake256 > > ( & [ msg] , & [ DST ] )
563
+ . unwrap ( )
564
+ . to_affine ( ) ;
565
+ let mut xx = [ 0u8 ; 56 ] ;
566
+ xx. copy_from_slice ( & x[ ..] ) ;
567
+ xx. reverse ( ) ;
568
+ let mut yy = [ 0u8 ; 56 ] ;
569
+ yy. copy_from_slice ( & y[ ..] ) ;
570
+ yy. reverse ( ) ;
571
+ assert_eq ! ( p. x( ) , xx) ;
572
+ assert_eq ! ( p. y( ) , yy) ;
573
+ }
574
+ }
494
575
}
0 commit comments