Skip to content
This repository has been archived by the owner on Apr 9, 2024. It is now read-only.

chore!: refactor ToRadix to ToRadixLe and ToRadixBe #58

Merged
merged 20 commits into from
Feb 16, 2023
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 45 additions & 8 deletions acir/src/circuit/directives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,15 @@ pub enum Directive {
bit_size: u32,
},

//decomposition of a: a=\sum b[i]*radix^i where b is an array of witnesses < radix
ToRadix {
//decomposition of a: a=\sum b[i]*radix^i where b is an array of witnesses < radix in little endian form
ToRadixLe {
a: Expression,
b: Vec<Witness>,
radix: u32,
},

//decomposition of a: a=\sum b[i]*radix^i where b is an array of witnesses < radix in big endian form
ToRadixBe {
a: Expression,
b: Vec<Witness>,
radix: u32,
Expand All @@ -57,7 +64,8 @@ impl Directive {
Directive::Quotient { .. } => "quotient",
Directive::Truncate { .. } => "truncate",
Directive::OddRange { .. } => "odd_range",
Directive::ToRadix { .. } => "to_radix",
Directive::ToRadixLe { .. } => "to_radix_le",
Directive::ToRadixBe { .. } => "to_radix_be",
}
}
fn to_u16(&self) -> u16 {
Expand All @@ -66,7 +74,8 @@ impl Directive {
Directive::Quotient { .. } => 1,
Directive::Truncate { .. } => 2,
Directive::OddRange { .. } => 3,
Directive::ToRadix { .. } => 4,
Directive::ToRadixLe { .. } => 4,
Directive::ToRadixBe { .. } => 5,
}
}

Expand Down Expand Up @@ -108,7 +117,15 @@ impl Directive {
write_u32(&mut writer, r.witness_index())?;
write_u32(&mut writer, *bit_size)?;
}
Directive::ToRadix { a, b, radix } => {
Directive::ToRadixLe { a, b, radix } => {
a.write(&mut writer)?;
write_u32(&mut writer, b.len() as u32)?;
for bit in b {
write_u32(&mut writer, bit.witness_index())?;
}
write_u32(&mut writer, *radix)?;
}
Directive::ToRadixBe { a, b, radix } => {
a.write(&mut writer)?;
write_u32(&mut writer, b.len() as u32)?;
for bit in b {
Expand Down Expand Up @@ -176,7 +193,20 @@ impl Directive {

let radix = read_u32(&mut reader)?;

Ok(Directive::ToRadix { a, b, radix })
Ok(Directive::ToRadixLe { a, b, radix })
}
5 => {
let a = Expression::read(&mut reader)?;
let b_len = read_u32(&mut reader)?;
let mut b = Vec::with_capacity(b_len as usize);
for _ in 0..b_len {
let witness = Witness(read_u32(&mut reader)?);
b.push(witness)
}

let radix = read_u32(&mut reader)?;

Ok(Directive::ToRadixBe { a, b, radix })
}

_ => Err(std::io::ErrorKind::InvalidData.into()),
Expand Down Expand Up @@ -228,7 +258,13 @@ fn serialisation_roundtrip() {
bit_size: 32,
};

let to_radix = Directive::ToRadix {
let to_radix_le = Directive::ToRadixLe {
a: Expression::default(),
b: vec![Witness(1u32), Witness(2u32), Witness(3u32), Witness(4u32)],
radix: 4,
};

let to_radix_be = Directive::ToRadixBe {
a: Expression::default(),
b: vec![Witness(1u32), Witness(2u32), Witness(3u32), Witness(4u32)],
radix: 4,
Expand All @@ -240,7 +276,8 @@ fn serialisation_roundtrip() {
quotient_predicate,
truncate,
odd_range,
to_radix,
to_radix_le,
to_radix_be,
];

for directive in directives {
Expand Down
16 changes: 14 additions & 2 deletions acir/src/circuit/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,20 @@ impl std::fmt::Display for Opcode {
)
}
Opcode::BlackBoxFuncCall(g) => write!(f, "{g}"),
Opcode::Directive(Directive::ToRadix { a, b, radix: _ }) => {
write!(f, "DIR::TORADIX ")?;
Opcode::Directive(Directive::ToRadixLe { a, b, radix: _ }) => {
write!(f, "DIR::TORADIXLE ")?;
write!(
f,
// TODO (Note): this assumes that the decomposed bits have contiguous witness indices
// This should be the case, however, we can also have a function which checks this
"(_{}, [_{}..._{}])",
a,
b.first().unwrap().witness_index(),
b.last().unwrap().witness_index(),
)
}
Opcode::Directive(Directive::ToRadixBe { a, b, radix: _ }) => {
write!(f, "DIR::TORADIXLE ")?;
write!(
f,
// TODO (Note): this assumes that the decomposed bits have contiguous witness indices
Expand Down
63 changes: 42 additions & 21 deletions acvm/src/pwg/directives.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,33 +64,25 @@ pub fn solve_directives(

Ok(())
}
Directive::ToRadix { a, b, radix } => {
Directive::ToRadixLe { a, b, radix } => {
let val_a = get_value(a, initial_witness)?;

let a_big = BigUint::from_bytes_be(&val_a.to_be_bytes());
let a_dec = a_big.to_radix_le(*radix);
if b.len() < a_dec.len() {
return Err(OpcodeResolutionError::UnsatisfiedConstrain);
}
for i in 0..b.len() {
let v = if i < a_dec.len() {
FieldElement::from_be_bytes_reduce(&[a_dec[i]])
} else {
FieldElement::zero()
};
match initial_witness.entry(b[i]) {
std::collections::btree_map::Entry::Vacant(e) => {
e.insert(v);
}
std::collections::btree_map::Entry::Occupied(e) => {
if e.get() != &v {
return Err(OpcodeResolutionError::UnsatisfiedConstrain);
}
}
}
match to_radix_outcome(b, &a_dec, initial_witness) {
Ok(()) => Ok(()),
Err(e) => Err(e),
}
}
Directive::ToRadixBe { a, b, radix } => {
let val_a = get_value(a, initial_witness)?;

Ok(())
let a_big = BigUint::from_bytes_be(&val_a.to_be_bytes());
let a_dec = a_big.to_radix_be(*radix);
vezenovm marked this conversation as resolved.
Show resolved Hide resolved
match to_radix_outcome(b, &a_dec, initial_witness) {
Ok(()) => Ok(()),
Err(e) => Err(e),
}
}
Directive::OddRange { a, b, r, bit_size } => {
let val_a = witness_to_value(initial_witness, *a)?;
Expand All @@ -112,3 +104,32 @@ pub fn solve_directives(
}
}
}

fn to_radix_outcome(
b: &Vec<Witness>,
a_dec: &Vec<u8>,
initial_witness: &mut BTreeMap<Witness, FieldElement>,
) -> Result<(), OpcodeResolutionError> {
if b.len() < a_dec.len() {
return Err(OpcodeResolutionError::UnsatisfiedConstrain);
}
for i in 0..b.len() {
let v = if i < a_dec.len() {
FieldElement::from_be_bytes_reduce(&[a_dec[i]])
} else {
FieldElement::zero()
};
match initial_witness.entry(b[i]) {
std::collections::btree_map::Entry::Vacant(e) => {
e.insert(v);
}
std::collections::btree_map::Entry::Occupied(e) => {
if e.get() != &v {
return Err(OpcodeResolutionError::UnsatisfiedConstrain);
}
}
}
}

Ok(())
}
2 changes: 1 addition & 1 deletion stdlib/src/fallback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ pub(crate) fn bit_decomposition(
}

// Next create a directive which computes those bits.
new_gates.push(Opcode::Directive(Directive::ToRadix {
new_gates.push(Opcode::Directive(Directive::ToRadixLe {
a: gate.clone(),
b: bit_vector.clone(),
radix: 2,
Expand Down