Skip to content
Permalink
Browse files

Change default `to_bits` and `to_bytes` functions to the safe versions

  • Loading branch information
Pratyush committed Mar 19, 2020
1 parent e45013a commit 295d25d847c6d519551b8a8005e05ed8310a6301
@@ -388,13 +388,6 @@ where
}
Ok(bytes)
}

fn to_bytes_strict<CS: ConstraintSystem<ConstraintF>>(
&self,
cs: CS,
) -> Result<Vec<UInt8>, SynthesisError> {
self.to_bytes(cs)
}
}

#[cfg(test)]
@@ -335,13 +335,6 @@ where
}
Ok(bytes)
}

fn to_bytes_strict<CS: ConstraintSystem<ConstraintF>>(
&self,
cs: CS,
) -> Result<Vec<UInt8>, SynthesisError> {
self.to_bytes(cs)
}
}

#[cfg(test)]
@@ -447,14 +447,6 @@ impl<ConstraintF: PrimeField> ToBytesGadget<ConstraintF> for Blake2sOutputGadget
) -> Result<Vec<UInt8>, SynthesisError> {
Ok(self.0.clone())
}

#[inline]
fn to_bytes_strict<CS: ConstraintSystem<ConstraintF>>(
&self,
cs: CS,
) -> Result<Vec<UInt8>, SynthesisError> {
self.to_bytes(cs)
}
}

impl<ConstraintF: PrimeField> AllocGadget<[u8; 32], ConstraintF> for Blake2sOutputGadget {
@@ -208,12 +208,4 @@ where
) -> Result<Vec<UInt8>, SynthesisError> {
self.pub_key.to_bytes(&mut cs.ns(|| "PubKey To Bytes"))
}

fn to_bytes_strict<CS: ConstraintSystem<ConstraintF>>(
&self,
mut cs: CS,
) -> Result<Vec<UInt8>, SynthesisError> {
self.pub_key
.to_bytes_strict(&mut cs.ns(|| "PubKey To Bytes"))
}
}
@@ -802,6 +802,7 @@ impl<ConstraintF: Field> ConditionalEqGadget<ConstraintF> for Boolean {
}

impl<ConstraintF: Field> ToBytesGadget<ConstraintF> for Boolean {
/// Outputs `1u8` if `self` is true, and `0u8` otherwise.
fn to_bytes<CS: ConstraintSystem<ConstraintF>>(
&self,
_cs: CS,
@@ -813,14 +814,6 @@ impl<ConstraintF: Field> ToBytesGadget<ConstraintF> for Boolean {
let byte = UInt8 { bits, value };
Ok(vec![byte])
}

/// Additionally checks if the produced list of booleans is 'valid'.
fn to_bytes_strict<CS: ConstraintSystem<ConstraintF>>(
&self,
cs: CS,
) -> Result<Vec<UInt8>, SynthesisError> {
self.to_bytes(cs)
}
}

impl<ConstraintF: PrimeField> CondSelectGadget<ConstraintF> for Boolean {
@@ -11,16 +11,24 @@ pub mod uint64;
pub mod uint8;

pub trait ToBitsGadget<ConstraintF: Field> {
/// Outputs the canonical bit-wise representation of `self`.
///
/// This is the correct default for 99% of use cases.
fn to_bits<CS: ConstraintSystem<ConstraintF>>(
&self,
cs: CS,
) -> Result<Vec<Boolean>, SynthesisError>;

/// Additionally checks if the produced list of booleans is 'valid'.
fn to_bits_strict<CS: ConstraintSystem<ConstraintF>>(
/// Outputs a possibly non-unique bit-wise representation of `self`.
///
/// If you're not absolutely certain that your usecase can get away with a
/// non-canonical representation, please use `self.to_bits(cs)` instead.
fn to_non_unique_bits<CS: ConstraintSystem<ConstraintF>>(
&self,
cs: CS,
) -> Result<Vec<Boolean>, SynthesisError>;
) -> Result<Vec<Boolean>, SynthesisError> {
self.to_bits(cs)
}
}

impl<ConstraintF: Field> ToBitsGadget<ConstraintF> for Boolean {
@@ -30,13 +38,6 @@ impl<ConstraintF: Field> ToBitsGadget<ConstraintF> for Boolean {
) -> Result<Vec<Boolean>, SynthesisError> {
Ok(vec![self.clone()])
}

fn to_bits_strict<CS: ConstraintSystem<ConstraintF>>(
&self,
_: CS,
) -> Result<Vec<Boolean>, SynthesisError> {
Ok(vec![self.clone()])
}
}

impl<ConstraintF: Field> ToBitsGadget<ConstraintF> for [Boolean] {
@@ -46,28 +47,15 @@ impl<ConstraintF: Field> ToBitsGadget<ConstraintF> for [Boolean] {
) -> Result<Vec<Boolean>, SynthesisError> {
Ok(self.to_vec())
}

fn to_bits_strict<CS: ConstraintSystem<ConstraintF>>(
&self,
_cs: CS,
) -> Result<Vec<Boolean>, SynthesisError> {
Ok(self.to_vec())
}
}

impl<ConstraintF: Field> ToBitsGadget<ConstraintF> for Vec<Boolean> {
fn to_bits<CS: ConstraintSystem<ConstraintF>>(
&self,
_cs: CS,
) -> Result<Vec<Boolean>, SynthesisError> {
Ok(self.clone())
}

fn to_bits_strict<CS: ConstraintSystem<ConstraintF>>(
&self,
_cs: CS,
) -> Result<Vec<Boolean>, SynthesisError> {
Ok(self.clone())
}
}

impl<ConstraintF: Field> ToBitsGadget<ConstraintF> for [UInt8] {
@@ -81,26 +69,27 @@ impl<ConstraintF: Field> ToBitsGadget<ConstraintF> for [UInt8] {
}
Ok(result)
}

fn to_bits_strict<CS: ConstraintSystem<ConstraintF>>(
&self,
cs: CS,
) -> Result<Vec<Boolean>, SynthesisError> {
self.to_bits(cs)
}
}

pub trait ToBytesGadget<ConstraintF: Field> {
/// Outputs a canonical byte-wise representation of `self`.
///
/// This is the correct default for 99% of use cases.
fn to_bytes<CS: ConstraintSystem<ConstraintF>>(
&self,
cs: CS,
) -> Result<Vec<UInt8>, SynthesisError>;

/// Additionally checks if the produced list of booleans is 'valid'.
fn to_bytes_strict<CS: ConstraintSystem<ConstraintF>>(
/// Outputs a possibly non-unique byte decomposition of `self`.
///
/// If you're not absolutely certain that your usecase can get away with a
/// non-canonical representation, please use `self.to_bytes(cs)` instead.
fn to_non_unique_bytes<CS: ConstraintSystem<ConstraintF>>(
&self,
cs: CS,
) -> Result<Vec<UInt8>, SynthesisError>;
) -> Result<Vec<UInt8>, SynthesisError> {
self.to_bytes(cs)
}
}

impl<ConstraintF: Field> ToBytesGadget<ConstraintF> for [UInt8] {
@@ -110,13 +99,6 @@ impl<ConstraintF: Field> ToBytesGadget<ConstraintF> for [UInt8] {
) -> Result<Vec<UInt8>, SynthesisError> {
Ok(self.to_vec())
}

fn to_bytes_strict<CS: ConstraintSystem<ConstraintF>>(
&self,
cs: CS,
) -> Result<Vec<UInt8>, SynthesisError> {
self.to_bytes(cs)
}
}

impl<'a, ConstraintF: Field, T: 'a + ToBytesGadget<ConstraintF>> ToBytesGadget<ConstraintF>
@@ -128,13 +110,6 @@ impl<'a, ConstraintF: Field, T: 'a + ToBytesGadget<ConstraintF>> ToBytesGadget<C
) -> Result<Vec<UInt8>, SynthesisError> {
(*self).to_bytes(cs)
}

fn to_bytes_strict<CS: ConstraintSystem<ConstraintF>>(
&self,
cs: CS,
) -> Result<Vec<UInt8>, SynthesisError> {
self.to_bytes(cs)
}
}

impl<'a, ConstraintF: Field> ToBytesGadget<ConstraintF> for &'a [UInt8] {
@@ -144,11 +119,4 @@ impl<'a, ConstraintF: Field> ToBytesGadget<ConstraintF> for &'a [UInt8] {
) -> Result<Vec<UInt8>, SynthesisError> {
Ok(self.to_vec())
}

fn to_bytes_strict<CS: ConstraintSystem<ConstraintF>>(
&self,
cs: CS,
) -> Result<Vec<UInt8>, SynthesisError> {
self.to_bytes(cs)
}
}
@@ -306,13 +306,6 @@ impl<ConstraintF: Field> ToBytesGadget<ConstraintF> for UInt32 {

Ok(bytes)
}

fn to_bytes_strict<CS: ConstraintSystem<ConstraintF>>(
&self,
cs: CS,
) -> Result<Vec<UInt8>, SynthesisError> {
self.to_bytes(cs)
}
}

impl PartialEq for UInt32 {
@@ -310,13 +310,6 @@ impl<ConstraintF: Field> ToBytesGadget<ConstraintF> for UInt64 {

Ok(bytes)
}

fn to_bytes_strict<CS: ConstraintSystem<ConstraintF>>(
&self,
cs: CS,
) -> Result<Vec<UInt8>, SynthesisError> {
self.to_bytes(cs)
}
}

impl PartialEq for UInt64 {
@@ -326,9 +326,18 @@ impl<F: PrimeField> NEqGadget<F> for FpGadget<F> {
}

impl<F: PrimeField> ToBitsGadget<F> for FpGadget<F> {
/// Outputs the binary representation of the value in `self` in *big-endian*
/// Outputs the unique bit-wise decomposition of `self` in *big-endian*
/// form.
fn to_bits<CS: ConstraintSystem<F>>(&self, mut cs: CS) -> Result<Vec<Boolean>, SynthesisError> {
let bits = self.to_non_unique_bits(&mut cs)?;
Boolean::enforce_in_field::<_, _, F>(&mut cs, &bits)?;
Ok(bits)
}

fn to_non_unique_bits<CS: ConstraintSystem<F>>(
&self,
mut cs: CS,
) -> Result<Vec<Boolean>, SynthesisError> {
let num_bits = F::Params::MODULUS_BITS;
use algebra::BitIterator;
let bit_values = match self.value {
@@ -375,20 +384,29 @@ impl<F: PrimeField> ToBitsGadget<F> for FpGadget<F> {

Ok(bits.into_iter().map(Boolean::from).collect())
}

fn to_bits_strict<CS: ConstraintSystem<F>>(
&self,
mut cs: CS,
) -> Result<Vec<Boolean>, SynthesisError> {
let bits = self.to_bits(&mut cs)?;
Boolean::enforce_in_field::<_, _, F>(&mut cs, &bits)?;

Ok(bits)
}
}

impl<F: PrimeField> ToBytesGadget<F> for FpGadget<F> {
/// Outputs the unique byte decomposition of `self` in *little-endian*
/// form.
fn to_bytes<CS: ConstraintSystem<F>>(&self, mut cs: CS) -> Result<Vec<UInt8>, SynthesisError> {
let bytes = self.to_non_unique_bytes(&mut cs)?;
Boolean::enforce_in_field::<_, _, F>(
&mut cs,
&bytes.iter()
.flat_map(|byte_gadget| byte_gadget.into_bits_le())
// This reverse maps the bits into big-endian form, as required by `enforce_in_field`.
.rev()
.collect::<Vec<_>>(),
)?;

Ok(bytes)
}

fn to_non_unique_bytes<CS: ConstraintSystem<F>>(
&self,
mut cs: CS,
) -> Result<Vec<UInt8>, SynthesisError> {
let byte_values = match self.value {
Some(value) => to_bytes![&value.into_repr()]?
.into_iter()
@@ -425,23 +443,6 @@ impl<F: PrimeField> ToBytesGadget<F> for FpGadget<F> {

Ok(bytes)
}

fn to_bytes_strict<CS: ConstraintSystem<F>>(
&self,
mut cs: CS,
) -> Result<Vec<UInt8>, SynthesisError> {
let bytes = self.to_bytes(&mut cs)?;
Boolean::enforce_in_field::<_, _, F>(
&mut cs,
&bytes.iter()
.flat_map(|byte_gadget| byte_gadget.into_bits_le())
// This reverse maps the bits into big-endian form, as required by `enforce_in_field`.
.rev()
.collect::<Vec<_>>(),
)?;

Ok(bytes)
}
}

impl<F: PrimeField> CondSelectGadget<F> for FpGadget<F> {
@@ -731,12 +731,12 @@ where
Ok(c0)
}

fn to_bits_strict<CS: ConstraintSystem<ConstraintF>>(
fn to_non_unique_bits<CS: ConstraintSystem<ConstraintF>>(
&self,
mut cs: CS,
) -> Result<Vec<Boolean>, SynthesisError> {
let mut c0 = self.c0.to_bits_strict(cs.ns(|| "c0"))?;
let mut c1 = self.c1.to_bits_strict(cs.ns(|| "c1"))?;
let mut c0 = self.c0.to_non_unique_bits(cs.ns(|| "c0"))?;
let mut c1 = self.c1.to_non_unique_bits(cs.ns(|| "c1"))?;
c0.append(&mut c1);
Ok(c0)
}
@@ -757,12 +757,12 @@ where
Ok(c0)
}

fn to_bytes_strict<CS: ConstraintSystem<ConstraintF>>(
fn to_non_unique_bytes<CS: ConstraintSystem<ConstraintF>>(
&self,
mut cs: CS,
) -> Result<Vec<UInt8>, SynthesisError> {
let mut c0 = self.c0.to_bytes_strict(cs.ns(|| "c0"))?;
let mut c1 = self.c1.to_bytes_strict(cs.ns(|| "c1"))?;
let mut c0 = self.c0.to_non_unique_bytes(cs.ns(|| "c0"))?;
let mut c1 = self.c1.to_non_unique_bytes(cs.ns(|| "c1"))?;
c0.append(&mut c1);
Ok(c0)
}

0 comments on commit 295d25d

Please sign in to comment.
You can’t perform that action at this time.