Skip to content

Commit f17a1ba

Browse files
committed
feat: add from_be_bytes_mod_order to facilitate hash_to_field implementation
1 parent 6646be1 commit f17a1ba

1 file changed

Lines changed: 45 additions & 0 deletions

File tree

src/scalar.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)