Skip to content

Instantly share code, notes, and snippets.

@alxiong
Created May 23, 2021 04:00
Show Gist options
  • Save alxiong/44a7534c690cb2b468c3ca05e697b92f to your computer and use it in GitHub Desktop.
Save alxiong/44a7534c690cb2b468c3ca05e697b92f to your computer and use it in GitHub Desktop.
Two-way, deterministic, infalliable conversion between Scalars and Bytes
use ark_bls12_381::Fr as BlsScalar;
use ark_ff::{FpParameters, PrimeField};
// The number of bits that can be reliably stored for BlsScalar. (Should equal
// SELF::MODULUS_BITS - 1)
const BLS_SCALAR_BIT_CAPACITY: u32 = <BlsScalar as PrimeField>::Params::CAPACITY;
// 31 bytes a chunk
const BLS_SCALAR_BYTE_CAPACITY: usize = BLS_SCALAR_BIT_CAPACITY as usize / 8;
/// Two-way, deterministic, infalliable conversion between arbitrary bytes (of
/// unknown length and potentially non-canonical) and field elements.
/// This function converts bytes to vector of BlsScalar.
pub(crate) fn to_bls_scalars(bytes: &[u8]) -> Vec<BlsScalar> {
// pad with "100..0" until the overall length equals the next multiple of
// BLS_SCALAR_BYTE_CAPACITY, note that always append "1" for chunk in
let mut padded_bytes = bytes.to_owned();
padded_bytes.push(1u8);
padded_bytes.resize(
next_multiple(padded_bytes.len(), BLS_SCALAR_BYTE_CAPACITY),
0u8,
);
assert!(padded_bytes.len() % BLS_SCALAR_BYTE_CAPACITY == 0);
let mut result = vec![];
for chunk in padded_bytes.chunks(BLS_SCALAR_BYTE_CAPACITY) {
result.push(BlsScalar::from_le_bytes_mod_order(chunk));
}
result
}
/// Two-way, deterministic, infalliable conversion between arbitrary bytes (of
/// unknown length and potentially non-canonical) and field elements.
/// This function converts vector of BlsScalar to bytes.
pub(crate) fn from_bls_scalars(scalars: &[BlsScalar]) -> Vec<u8> {
let mut padded_bytes = vec![];
for scalar in scalars.iter() {
let mut scalar_bytes: Vec<u8> = scalar.into_repr().to_bytes_le();
scalar_bytes.truncate(BLS_SCALAR_BYTE_CAPACITY);
padded_bytes.extend_from_slice(&scalar_bytes);
}
// remove padding
while *padded_bytes.last().unwrap() == 0u8 {
padded_bytes.pop();
}
assert_eq!(*padded_bytes.last().unwrap(), 1u8);
padded_bytes.pop();
padded_bytes
}
// returns the smallest multiple of `multiple` no smaller than `current`
fn next_multiple(current: usize, multiple: usize) -> usize {
if current % multiple == 0 {
current
} else {
current + multiple - current % multiple
}
}
#[test]
fn test_from_to_bls_scalars() {
use ark_std::rand::Rng;
let mut rng = ark_std::test_rng();
let msg1 = b"The quick brown fox jumps over the lazy dog".to_vec();
let mut msg2 = vec![0u8; 31];
let mut msg3 = vec![0u8; 32];
let mut msg4 = vec![0u8; 500];
rng.fill(&mut msg2[..]);
rng.fill(&mut msg3[..]);
rng.fill(&mut msg4[..]);
assert_eq!(msg1, from_bls_scalars(&to_bls_scalars(&msg1)));
assert_eq!(msg2, from_bls_scalars(&to_bls_scalars(&msg2)));
assert_eq!(msg3, from_bls_scalars(&to_bls_scalars(&msg3)));
assert_eq!(msg4, from_bls_scalars(&to_bls_scalars(&msg4)));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment