Skip to content

Commit

Permalink
chore: move encode_value and decode_value back inside Abi's impl
Browse files Browse the repository at this point in the history
  • Loading branch information
TomAFrench committed Feb 15, 2023
1 parent 0f829ed commit f3a78f6
Showing 1 changed file with 66 additions and 65 deletions.
131 changes: 66 additions & 65 deletions crates/noirc_abi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ impl Abi {
// First encode each input separately
let encoded_input_map: BTreeMap<String, Vec<FieldElement>> =
try_btree_map(input_map, |(key, value)| {
encode_value(value, &key).map(|v| (key.clone(), v))
Self::encode_value(value, &key).map(|v| (key.clone(), v))
})?;

// Write input field elements into witness indices specified in `abi_witness_map`.
Expand Down Expand Up @@ -216,7 +216,7 @@ impl Abi {
return Err(AbiError::TypeMismatch { param, value });
}

encoded_inputs.extend(encode_value(value, &param.name)?);
encoded_inputs.extend(Self::encode_value(value, &param.name)?);
}

// Check that no extra witness values have been provided.
Expand All @@ -230,6 +230,27 @@ impl Abi {
Ok(encoded_inputs)
}

fn encode_value(value: InputValue, param_name: &String) -> Result<Vec<FieldElement>, AbiError> {
let mut encoded_value = Vec::new();
match value {
InputValue::Field(elem) => encoded_value.push(elem),
InputValue::Vec(vec_elem) => encoded_value.extend(vec_elem),
InputValue::String(string) => {
let str_as_fields =
string.bytes().map(|byte| FieldElement::from_be_bytes_reduce(&[byte]));
encoded_value.extend(str_as_fields)
}
InputValue::Struct(object) => {
for (field_name, value) in object {
let new_name = format!("{param_name}.{field_name}");
encoded_value.extend(Self::encode_value(value, &new_name)?)
}
}
InputValue::Undefined => return Err(AbiError::UndefinedInput(param_name.to_string())),
}
Ok(encoded_value)
}

/// Decode a `WitnessMap` into the types specified in the ABI.
pub fn decode_from_witness(
&self,
Expand All @@ -244,7 +265,7 @@ impl Abi {
witness_map[&witness_index]
});

decode_value(&mut param_witness_values.into_iter(), typ)
Self::decode_value(&mut param_witness_values.into_iter(), typ)
.map(|input_value| (name.clone(), input_value))
.unwrap()
})
Expand All @@ -269,79 +290,59 @@ impl Abi {
let mut field_iterator = encoded_inputs.iter().cloned();
let mut decoded_inputs = BTreeMap::new();
for param in &self.parameters {
let decoded_value = decode_value(&mut field_iterator, &param.typ)?;
let decoded_value = Self::decode_value(&mut field_iterator, &param.typ)?;

decoded_inputs.insert(param.name.to_owned(), decoded_value);
}
Ok(decoded_inputs)
}
}

fn encode_value(value: InputValue, param_name: &String) -> Result<Vec<FieldElement>, AbiError> {
let mut encoded_value = Vec::new();
match value {
InputValue::Field(elem) => encoded_value.push(elem),
InputValue::Vec(vec_elem) => encoded_value.extend(vec_elem),
InputValue::String(string) => {
let str_as_fields =
string.bytes().map(|byte| FieldElement::from_be_bytes_reduce(&[byte]));
encoded_value.extend(str_as_fields)
}
InputValue::Struct(object) => {
for (field_name, value) in object {
let new_name = format!("{param_name}.{field_name}");
encoded_value.extend(encode_value(value, &new_name)?)
fn decode_value(
field_iterator: &mut impl Iterator<Item = FieldElement>,
value_type: &AbiType,
) -> Result<InputValue, AbiError> {
// This function assumes that `field_iterator` contains enough `FieldElement`s in order to decode a `value_type`
// `Abi.decode` enforces that the encoded inputs matches the expected length defined by the ABI so this is safe.
let value = match value_type {
AbiType::Field | AbiType::Integer { .. } | AbiType::Boolean => {
let field_element = field_iterator.next().unwrap();

InputValue::Field(field_element)
}
}
InputValue::Undefined => return Err(AbiError::UndefinedInput(param_name.to_string())),
}
Ok(encoded_value)
}
AbiType::Array { length, .. } => {
let field_elements: Vec<FieldElement> =
field_iterator.take(*length as usize).collect();

fn decode_value(
field_iterator: &mut impl Iterator<Item = FieldElement>,
value_type: &AbiType,
) -> Result<InputValue, AbiError> {
// This function assumes that `field_iterator` contains enough `FieldElement`s in order to decode a `value_type`
// `Abi.decode` enforces that the encoded inputs matches the expected length defined by the ABI so this is safe.
let value = match value_type {
AbiType::Field | AbiType::Integer { .. } | AbiType::Boolean => {
let field_element = field_iterator.next().unwrap();

InputValue::Field(field_element)
}
AbiType::Array { length, .. } => {
let field_elements: Vec<FieldElement> = field_iterator.take(*length as usize).collect();
InputValue::Vec(field_elements)
}
AbiType::String { length } => {
let string_as_slice: Vec<u8> = field_iterator
.take(*length as usize)
.map(|e| {
let mut field_as_bytes = e.to_be_bytes();
let char_byte = field_as_bytes.pop().unwrap(); // A character in a string is represented by a u8, thus we just want the last byte of the element
assert!(field_as_bytes.into_iter().all(|b| b == 0)); // Assert that the rest of the field element's bytes are empty
char_byte
})
.collect();

let final_string = str::from_utf8(&string_as_slice).unwrap();

InputValue::String(final_string.to_owned())
}
AbiType::Struct { fields, .. } => {
let mut struct_map = BTreeMap::new();

InputValue::Vec(field_elements)
}
AbiType::String { length } => {
let string_as_slice: Vec<u8> = field_iterator
.take(*length as usize)
.map(|e| {
let mut field_as_bytes = e.to_be_bytes();
let char_byte = field_as_bytes.pop().unwrap(); // A character in a string is represented by a u8, thus we just want the last byte of the element
assert!(field_as_bytes.into_iter().all(|b| b == 0)); // Assert that the rest of the field element's bytes are empty
char_byte
})
.collect();

let final_string = str::from_utf8(&string_as_slice).unwrap();

InputValue::String(final_string.to_owned())
}
AbiType::Struct { fields, .. } => {
let mut struct_map = BTreeMap::new();
for (field_key, param_type) in fields {
let field_value = Self::decode_value(field_iterator, param_type)?;

for (field_key, param_type) in fields {
let field_value = decode_value(field_iterator, param_type)?;
struct_map.insert(field_key.to_owned(), field_value);
}

struct_map.insert(field_key.to_owned(), field_value);
InputValue::Struct(struct_map)
}
};

InputValue::Struct(struct_map)
}
};

Ok(value)
Ok(value)
}
}

0 comments on commit f3a78f6

Please sign in to comment.