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

Basic strings #622

Merged
merged 34 commits into from
Jan 25, 2023
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
19bd86b
preliminary strings work, type added to Hir and abi
vezenovm Jan 6, 2023
4a2d6da
nargo build working for simple str types
vezenovm Jan 6, 2023
a627b02
initial strings work. can input to abi and compare string literal. st…
vezenovm Jan 9, 2023
c6f40b5
little cleanup and test addition
vezenovm Jan 9, 2023
b4f9e5c
cargo clippy and fixed decoding of public string values in toml
vezenovm Jan 9, 2023
fdc3058
Merge branch 'master' into mv/strings
vezenovm Jan 10, 2023
a1eaba3
some pr comments, moving to use str keyword
vezenovm Jan 11, 2023
8aeab6a
clarifying comment for string toml type to input value
vezenovm Jan 11, 2023
8780311
pr comments
vezenovm Jan 11, 2023
82af973
update display for string types
vezenovm Jan 11, 2023
92a6b69
merge conflicts
vezenovm Jan 17, 2023
9828d63
merge conflicts with master
vezenovm Jan 17, 2023
279d266
fix convert type for new string type
vezenovm Jan 17, 2023
dcb3a0a
fix up some minor PR nitpicks
vezenovm Jan 17, 2023
deeabd3
parsing toml now follow abi
vezenovm Jan 19, 2023
c11a1bc
additional parser error and some comments
vezenovm Jan 19, 2023
7168c4b
merge conflicts
vezenovm Jan 19, 2023
755417f
fix usage of to_bytes with master merge
vezenovm Jan 19, 2023
31ded35
working string inputs inside struct inputs to main
vezenovm Jan 19, 2023
2715eb0
cargo clippy cleanup
vezenovm Jan 19, 2023
09998b9
remove unused err
vezenovm Jan 19, 2023
cf2eb44
additional test case for type directed toml parsing
vezenovm Jan 19, 2023
d6e2270
merge conflicts
vezenovm Jan 20, 2023
6bfcfda
using less and greater than for str type
vezenovm Jan 23, 2023
ed44404
Merge branch 'master' into mv/strings
vezenovm Jan 23, 2023
0917038
cargo clippy
vezenovm Jan 23, 2023
41e6a80
fix type def for str fields in struct_inputs test
vezenovm Jan 23, 2023
7bea868
Merge branch 'master' into mv/strings
vezenovm Jan 23, 2023
1722c2d
merge conflicts
vezenovm Jan 23, 2023
861da20
uncommit accidental prover input to test and cargo fmt
vezenovm Jan 24, 2023
7d0b3e4
switch to using abi BTreeMap instead of flattened vec
vezenovm Jan 24, 2023
4019440
comments
vezenovm Jan 24, 2023
099828a
pr comments, mainly style
vezenovm Jan 25, 2023
fed1292
Merge branch 'master' into mv/strings
vezenovm Jan 25, 2023
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
28 changes: 14 additions & 14 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 6 additions & 2 deletions crates/nargo/src/cli/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
pub use build_cmd::build_from_path;
use clap::{App, AppSettings, Arg};
use noirc_abi::input_parser::{Format, InputValue};
use noirc_abi::{
input_parser::{Format, InputValue},
Abi,
};
use noirc_driver::Driver;
use noirc_frontend::graph::{CrateName, CrateType};
use std::{
Expand Down Expand Up @@ -138,6 +141,7 @@ pub fn read_inputs_from_file<P: AsRef<Path>>(
path: P,
file_name: &str,
format: Format,
abi: Abi,
) -> Result<BTreeMap<String, InputValue>, CliError> {
let file_path = {
let mut dir_path = path.as_ref().to_path_buf();
Expand All @@ -150,7 +154,7 @@ pub fn read_inputs_from_file<P: AsRef<Path>>(
}

let input_string = std::fs::read_to_string(file_path).unwrap();
Ok(format.parse(&input_string)?)
Ok(format.parse(&input_string, abi)?)
}

fn write_inputs_to_file<P: AsRef<Path>>(
Expand Down
6 changes: 4 additions & 2 deletions crates/nargo/src/cli/prove_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,10 @@ pub fn parse_and_solve_witness<P: AsRef<Path>>(
program_dir: P,
compiled_program: &noirc_driver::CompiledProgram,
) -> Result<BTreeMap<Witness, FieldElement>, CliError> {
let abi = compiled_program.abi.as_ref().expect("compiled program is missing an abi object");
// Parse the initial witness values from Prover.toml
let witness_map = read_inputs_from_file(&program_dir, PROVER_INPUT_FILE, Format::Toml)?;
let witness_map =
read_inputs_from_file(&program_dir, PROVER_INPUT_FILE, Format::Toml, abi.clone())?;

// Solve the remaining witnesses
let solved_witness = solve_witness(compiled_program, &witness_map)?;
Expand All @@ -73,7 +75,7 @@ pub fn parse_and_solve_witness<P: AsRef<Path>>(
.map(|index| solved_witness[index])
.collect();

let public_abi = compiled_program.abi.as_ref().unwrap().clone().public_abi();
let public_abi = abi.clone().public_abi();
let public_inputs = public_abi.decode(&encoded_public_inputs)?;

// Write public inputs into Verifier.toml
Expand Down
3 changes: 2 additions & 1 deletion crates/nargo/src/cli/verify_cmd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ pub fn verify_with_path<P: AsRef<Path>>(
let num_pub_params = public_abi.num_parameters();
if num_pub_params != 0 {
let curr_dir = program_dir;
public_inputs = read_inputs_from_file(curr_dir, VERIFIER_INPUT_FILE, Format::Toml)?;
public_inputs =
read_inputs_from_file(curr_dir, VERIFIER_INPUT_FILE, Format::Toml, public_abi)?;
}

let valid_proof = verify_proof(compiled_program, public_inputs, load_proof(proof_path)?)?;
Expand Down
5 changes: 5 additions & 0 deletions crates/nargo/tests/test_data/strings/Nargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[package]
authors = [""]
compiler_version = "0.1"

[dependencies]
3 changes: 3 additions & 0 deletions crates/nargo/tests/test_data/strings/Prover.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
message = "hello world"
hex_as_string = "0x41"
hex_as_field = "0x41"
12 changes: 12 additions & 0 deletions crates/nargo/tests/test_data/strings/src/main.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
fn main(message : pub str<11>, hex_as_string : str<4>, hex_as_field : Field) {
let mut bad_message = "hello world";

constrain message == "hello world";
bad_message = "helld world";

constrain message != bad_message;

constrain hex_as_string == "0x41";
// constrain hex_as_string != 0x41; This will fail with a type mismatch between str[4] and Field
constrain hex_as_field == 0x41;
}
2 changes: 1 addition & 1 deletion crates/nargo/tests/test_data/struct/Prover.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
x = "0"
y = "1"
y = "1"
5 changes: 4 additions & 1 deletion crates/nargo/tests/test_data/struct_inputs/Prover.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@ return = ""
[y]
foo = "5"
bar = "10"
message = "hello"

[z]
val = "1"
array = [0, 1]
message = "helld"

[a]
[a.bar_struct]
val = "1"
array = [0, 1]
array = [0, 1]
message = "hello"
1 change: 1 addition & 0 deletions crates/nargo/tests/test_data/struct_inputs/src/foo/bar.nr
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ global N = 2;
struct barStruct {
val: Field,
array: [Field; 2],
message: str<5>,
}
6 changes: 5 additions & 1 deletion crates/nargo/tests/test_data/struct_inputs/src/main.nr
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ mod foo;
struct myStruct {
foo: u32,
bar: Field,
message: str<5>,
}

fn main(x : Field, y : pub myStruct, z: pub foo::bar::barStruct, a: pub foo::fooStruct) -> pub Field {
let struct_from_bar = foo::bar::barStruct { val: 1, array: [0, 1] };
let struct_from_bar = foo::bar::barStruct { val: 1, array: [0, 1], message: "hello" };

check_inner_struct(a, z);

Expand All @@ -20,6 +21,9 @@ fn main(x : Field, y : pub myStruct, z: pub foo::bar::barStruct, a: pub foo::foo
constrain (struct_from_bar.val * x) == x;

constrain x != y.bar;

constrain y.message == "hello";
constrain a.bar_struct.message == struct_from_bar.message;

a.bar_struct.array[1]
}
Expand Down
6 changes: 5 additions & 1 deletion crates/noirc_abi/src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use crate::{input_parser::InputValue, AbiParameter};
use crate::{input_parser::InputValue, AbiParameter, AbiType};

#[derive(Debug)]
pub enum InputParserError {
ParseTomlMap(String),
ParseStr(String),
ParseHexStr(String),
DuplicateVariableName(String),
AbiTypeMismatch(AbiType),
}

impl std::fmt::Display for InputParserError {
Expand All @@ -24,6 +25,9 @@ impl std::fmt::Display for InputParserError {
InputParserError::DuplicateVariableName(err_msg) => {
write!(f, "duplicate variable name {err_msg}")
}
InputParserError::AbiTypeMismatch(abi_type) => {
write!(f, "cannot parse a string toml type into {:?}", abi_type)
}
}
}
}
Expand Down
10 changes: 8 additions & 2 deletions crates/noirc_abi/src/input_parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ use acvm::FieldElement;
use serde::Serialize;

use crate::errors::InputParserError;
use crate::AbiType;
use crate::{Abi, AbiType};
/// This is what all formats eventually transform into
/// For example, a toml file will parse into TomlTypes
/// and those TomlTypes will be mapped to Value
#[derive(Debug, Clone, Serialize)]
pub enum InputValue {
Field(FieldElement),
Vec(Vec<FieldElement>),
String(String),
Struct(BTreeMap<String, InputValue>),
Undefined,
}
Expand All @@ -39,6 +40,10 @@ impl InputValue {
.all(|field_element| Self::Field(*field_element).matches_abi(typ))
}

(InputValue::String(string), AbiType::String { length }) => {
string.len() == *length as usize
}

(InputValue::Struct(map), AbiType::Struct { fields, .. }) => {
if map.len() != fields.len() {
return false;
Expand Down Expand Up @@ -85,9 +90,10 @@ impl Format {
pub fn parse(
&self,
input_string: &str,
abi: Abi,
) -> Result<BTreeMap<String, InputValue>, InputParserError> {
match self {
Format::Toml => toml::parse_toml(input_string),
Format::Toml => toml::parse_toml(input_string, abi),
}
}

Expand Down
44 changes: 33 additions & 11 deletions crates/noirc_abi/src/input_parser/toml.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,26 @@
use super::InputValue;
use crate::errors::InputParserError;
use crate::{errors::InputParserError, Abi, AbiType};
use acvm::FieldElement;
use serde::Serialize;
use serde_derive::Deserialize;
use std::collections::BTreeMap;

pub(crate) fn parse_toml(
input_string: &str,
abi: Abi,
) -> Result<BTreeMap<String, InputValue>, InputParserError> {
// Parse input.toml into a BTreeMap, converting the argument to field elements
let data: BTreeMap<String, TomlTypes> = toml::from_str(input_string)
.map_err(|err_msg| InputParserError::ParseTomlMap(err_msg.to_string()))?;
toml_map_to_field(data)

// The toml map is stored in an ordered BTreeMap. As the keys are strings the map is in alphanumerical order.
// When parsing the toml map we recursively go through each field to enable struct inputs.
// To match this map with the correct abi type we reorganize our abi by parameter name in a BTreeMap, while the struct fields
// in the abi are already stored in a BTreeMap.
let abi_map = abi.to_btree_map();

let toml_map = toml_map_to_field(data, abi_map)?;
Ok(toml_map)
}

pub(crate) fn serialise_to_toml(
Expand Down Expand Up @@ -50,17 +59,24 @@ pub(crate) fn serialise_to_toml(
/// understands for Inputs
fn toml_map_to_field(
toml_map: BTreeMap<String, TomlTypes>,
abi_map: BTreeMap<String, AbiType>,
) -> Result<BTreeMap<String, InputValue>, InputParserError> {
let mut field_map = BTreeMap::new();
for (parameter, value) in toml_map {
let mapped_value = match value {
TomlTypes::String(string) => {
let new_value = parse_str(&string)?;

if let Some(field_element) = new_value {
InputValue::Field(field_element)
} else {
InputValue::Undefined
let param_type = abi_map.get(&parameter).unwrap();
match param_type {
AbiType::String { .. } => InputValue::String(string),
AbiType::Field | AbiType::Integer { .. } => {
let new_value = parse_str_to_field(&string)?;
if let Some(field_element) = new_value {
InputValue::Field(field_element)
} else {
InputValue::Undefined
}
}
_ => return Err(InputParserError::AbiTypeMismatch(param_type.clone())),
}
}
TomlTypes::Integer(integer) => {
Expand All @@ -84,13 +100,18 @@ fn toml_map_to_field(
TomlTypes::ArrayString(arr_str) => {
let array_elements: Vec<_> = arr_str
.into_iter()
.map(|elem_str| parse_str(&elem_str).unwrap().unwrap())
.map(|elem_str| parse_str_to_field(&elem_str).unwrap().unwrap())
.collect();

InputValue::Vec(array_elements)
}
TomlTypes::Table(table) => {
let native_table = toml_map_to_field(table)?;
let param_type = abi_map.get(&parameter).unwrap();
let fields = match param_type {
AbiType::Struct { fields } => fields.clone(),
_ => return Err(InputParserError::AbiTypeMismatch(param_type.clone())),
};
let native_table = toml_map_to_field(table, fields)?;

InputValue::Struct(native_table)
}
Expand All @@ -116,6 +137,7 @@ fn toml_remap(map: &BTreeMap<String, InputValue>) -> BTreeMap<String, TomlTypes>
let array = v.iter().map(|i| format!("0x{}", i.to_hex())).collect();
TomlTypes::ArrayString(array)
}
InputValue::String(s) => TomlTypes::String(s.clone()),
InputValue::Struct(map) => {
let map_with_toml_types = toml_remap(map);
TomlTypes::Table(map_with_toml_types)
Expand Down Expand Up @@ -145,7 +167,7 @@ enum TomlTypes {
Table(BTreeMap<String, TomlTypes>),
}

fn parse_str(value: &str) -> Result<Option<FieldElement>, InputParserError> {
fn parse_str_to_field(value: &str) -> Result<Option<FieldElement>, InputParserError> {
if value.is_empty() {
Ok(None)
} else if value.starts_with("0x") {
Expand Down
Loading