Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add little endian functions to to bits gadget #151

14 changes: 14 additions & 0 deletions algebra/src/bits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,26 @@ use crate::Error;
pub trait ToBits {
/// Serialize `self` into a bit vector using a BigEndian bit order representation.
fn write_bits(&self) -> Vec<bool>;

/// Serialize `self` into a bit vector using a LittleEndian bit order representation.
fn write_bits_le(&self) -> Vec<bool> {
let mut serialized_bits = self.write_bits();
serialized_bits.reverse();
serialized_bits
}
}

pub trait FromBits: Sized {
/// Reads `self` from `bits`, where `bits` are expected to be
/// in a BigEndian bit order representation.
fn read_bits(bits: Vec<bool>) -> Result<Self, Error>;

/// Reads `self` from `bits`, where `bits` are expected to be
/// in a LittleEndian bit order representation.
fn read_bits_le(mut bits: Vec<bool>) -> Result<Self, Error> {
bits.reverse();
Self::read_bits(bits)
}
}

pub trait ToCompressedBits {
Expand Down
12 changes: 12 additions & 0 deletions algebra/src/fields/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,13 @@ fn random_serialization_tests<F: Field, R: Rng>(rng: &mut R) {
serialized.extend_from_slice(a_serialized.as_slice());
let deserialized = F::read_bits(serialized).unwrap();
assert_eq!(a, deserialized);

// test deserialization with leading zeros in little-endian bit representation
let serialized = vec![false; 10];
let mut a_serialized = a.write_bits_le();
a_serialized.extend_from_slice(serialized.as_slice());
let deserialized = F::read_bits_le(a_serialized).unwrap();
assert_eq!(a, deserialized);
}

//Byte serialization test
Expand Down Expand Up @@ -327,6 +334,11 @@ fn random_field_tests<F: Field>() {
let a_serialized = a.write_bits();
let a_deserialized = F::read_bits(a_serialized.clone()).unwrap();
assert_eq!(a, a_deserialized);

// test little-endian serialization
let a_serialized = a.write_bits_le();
let a_deserialized = F::read_bits_le(a_serialized).unwrap();
assert_eq!(a, a_deserialized);
}
}

Expand Down
31 changes: 31 additions & 0 deletions r1cs/gadgets/std/src/bits/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,27 @@ pub trait ToBitsGadget<ConstraintF: Field> {
&self,
cs: CS,
) -> Result<Vec<Boolean>, SynthesisError>;

/// Outputs the little-endian bit representation of `Self`
fn to_bits_le<CS: ConstraintSystemAbstract<ConstraintF>>(
&self,
cs: CS,
) -> Result<Vec<Boolean>, SynthesisError> {
let mut bits = self.to_bits(cs)?;
bits.reverse();
Ok(bits)
}

/// Converts `Self` to little-endian bit representation, checking if the bit representation is
/// 'valid'
fn to_bits_strict_le<CS: ConstraintSystemAbstract<ConstraintF>>(
&self,
cs: CS,
) -> Result<Vec<Boolean>, SynthesisError> {
let mut bits = self.to_bits_strict(cs)?;
bits.reverse();
Ok(bits)
}
}

pub trait FromBitsGadget<ConstraintF: Field>
Expand All @@ -30,6 +51,16 @@ where
cs: CS,
bits: &[Boolean],
) -> Result<Self, SynthesisError>;

/// Reconstruct a `Self` from its *little endian* bit representation `bits` of bit len not
/// higher than CAPACITY (i.e. MODULUS - 1)
fn from_bits_le<CS: ConstraintSystemAbstract<ConstraintF>>(
cs: CS,
bits: &[Boolean],
) -> Result<Self, SynthesisError> {
let big_endian_bits: Vec<_> = bits.iter().rev().map(|el| *el).collect();
Self::from_bits(cs, &big_endian_bits)
}
}

impl<ConstraintF: Field> ToBitsGadget<ConstraintF> for Boolean {
Expand Down
43 changes: 37 additions & 6 deletions r1cs/gadgets/std/src/fields/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,14 @@ pub(crate) mod tests {

#[allow(dead_code)]
pub(crate) fn from_bits_fp_gadget_test<ConstraintF: PrimeField>() {
from_bits_fp_gadget_test_with_endianness::<ConstraintF>(true);
from_bits_fp_gadget_test_with_endianness::<ConstraintF>(false);
}

// if little_endian is true (resp. false), then the reconstruction of a field element from its
// little (resp. big) endian bit representation is tested
#[inline]
fn from_bits_fp_gadget_test_with_endianness<ConstraintF: PrimeField>(little_endian: bool) {
let mut rng = thread_rng();
let mut cs = ConstraintSystem::<ConstraintF>::new(SynthesisMode::Debug);

Expand All @@ -605,13 +613,24 @@ pub(crate) mod tests {
};

//Positive case
let f_g_bits = Vec::<Boolean>::alloc(cs.ns(|| "alloc f bits"), || {
Ok(f.write_bits()[leading_zeros..].to_vec())
})
.unwrap();
let f_g =
let f_g_bits = if little_endian {
Vec::<Boolean>::alloc(cs.ns(|| "alloc f bits"), || {
let f_bits_le = f.write_bits_le();
Ok(f_bits_le[..f_bits_le.len()-leading_zeros].to_vec())
}).unwrap()
} else {
Vec::<Boolean>::alloc(cs.ns(|| "alloc f bits"), || {
Ok(f.write_bits()[leading_zeros..].to_vec())
}).unwrap()
};

let f_g = if little_endian {
FpGadget::<ConstraintF>::from_bits_le(cs.ns(|| "pack f_g_bits"), f_g_bits.as_slice())
.unwrap()
} else {
FpGadget::<ConstraintF>::from_bits(cs.ns(|| "pack f_g_bits"), f_g_bits.as_slice())
.unwrap();
.unwrap()
};
assert_eq!(f, f_g.get_value().unwrap());
assert!(cs.is_satisfied());

Expand Down Expand Up @@ -690,6 +709,18 @@ pub(crate) mod tests {

assert_eq!(a_read, a_g_read.get_value().unwrap());

//test to_bits in little endian form
let a_bits_le = a.write_bits_le();
let a_g_bits_le = a_g.to_bits_le(cs.ns(|| "a_to_bits_le")).unwrap();
assert_eq!(
a_bits_le,
a_g_bits_le.iter().map(|b| b.get_value().unwrap()).collect::<Vec<_>>(),
);

let a_g_bits_le = a_g_bits_le[..a_g_bits_le.len()-1].as_ref();
let a_g_read = FpGadget::<ConstraintF>::from_bits_le(cs.ns(|| "read a_g_le"), a_g_bits_le).unwrap();
assert_eq!(a_read, a_g_read.get_value().unwrap());

//to_bits_with_length_restriction test
let (b, leading_zeros) = loop {
let val = ConstraintF::rand(&mut rng);
Expand Down