Created
May 23, 2021 04:00
-
-
Save alxiong/44a7534c690cb2b468c3ca05e697b92f to your computer and use it in GitHub Desktop.
Two-way, deterministic, infalliable conversion between Scalars and Bytes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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