@@ -569,6 +569,25 @@ impl Scalar {
569569 Self :: from_bytes_le ( & le_bytes)
570570 }
571571
572+ /// Interprets `bytes` as a big-endian integer of any length and reduces it modulo the
573+ /// group order.
574+ pub fn from_be_bytes_mod_order ( bytes : & [ u8 ] ) -> Self {
575+ // Memory safety: on length 0, `blst_scalar_from_be_bytes` reads 32 bytes past `bytes`
576+ // and underflows its digit count.
577+ if bytes. is_empty ( ) {
578+ return Self :: ZERO ;
579+ }
580+
581+ let mut raw = blst_scalar:: default ( ) ;
582+ // This step does the modular reduction
583+ unsafe { blst_scalar_from_be_bytes ( & mut raw, bytes. as_ptr ( ) , bytes. len ( ) ) } ;
584+
585+ let mut out = blst_fr:: default ( ) ;
586+ unsafe { blst_fr_from_scalar ( & mut out, & raw ) } ;
587+
588+ Scalar ( out)
589+ }
590+
572591 /// Converts an element of `Scalar` into a byte representation in
573592 /// little-endian byte order.
574593 #[ inline]
@@ -1895,4 +1914,30 @@ mod tests {
18951914 }
18961915 assert_eq ! ( 0 , yep_bad. len( ) ) ;
18971916 }
1917+
1918+ /// Vectors from `bls12_381`'s `map_scalar`. These pin the endianness; blst covers the
1919+ /// reduction itself.
1920+ #[ test]
1921+ fn test_from_be_bytes_mod_order ( ) {
1922+ let vectors: & [ ( & [ u8 ] , & str ) ] = & [
1923+ (
1924+ b"aaaaaabbbbbbccccccddddddeeeeeeffffffgggggghhhhhh" ,
1925+ "Scalar(0x2228450bf55d8fe62395161bd3677ff6fc28e45b89bc87e02a818eda11a8c5da)" ,
1926+ ) ,
1927+ (
1928+ b"111111222222333333444444555555666666777777888888" ,
1929+ "Scalar(0x4aa543cbd2f0c8f37f8a375ce2e383eb343e7e3405f61e438b0a15fb8899d1ae)" ,
1930+ ) ,
1931+ ] ;
1932+
1933+ for ( okm, expected) in vectors {
1934+ assert_eq ! (
1935+ & format!( "{:?}" , Scalar :: from_be_bytes_mod_order( okm) ) ,
1936+ expected
1937+ ) ;
1938+ }
1939+
1940+ // The empty-input guard is ours: blst would read out of bounds here.
1941+ assert_eq ! ( Scalar :: from_be_bytes_mod_order( & [ ] ) , Scalar :: ZERO ) ;
1942+ }
18981943}
0 commit comments