Skip to content

Commit

Permalink
Merge pull request iden3#79 from victorcrrd/plonk-custom-gates
Browse files Browse the repository at this point in the history
Plonk custom gates
  • Loading branch information
alrubio authored Jul 15, 2022
2 parents 59739df + fb54a5d commit d472c3f
Show file tree
Hide file tree
Showing 9 changed files with 336 additions and 65 deletions.
108 changes: 107 additions & 1 deletion parser/src/include_logic.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use super::errors::FileOsError;
use program_structure::error_definition::Report;
use std::collections::HashSet;
use std::collections::{HashMap, HashSet};
use std::path::PathBuf;

pub struct FileStack {
Expand Down Expand Up @@ -45,3 +45,109 @@ impl FileStack {
}
}
}

pub struct IncludesNode {
pub path: PathBuf,
pub custom_gates_pragma: bool,
}

#[derive(Default)]
pub struct IncludesGraph {
nodes: Vec<IncludesNode>,
adjacency: HashMap<PathBuf, Vec<usize>>,
custom_gates_nodes: Vec<PathBuf>,
}

impl IncludesGraph {
pub fn new() -> IncludesGraph {
IncludesGraph::default()
}

pub fn add_node(
&mut self,
path: PathBuf,
custom_gates_pragma: bool,
custom_gates_usage: bool
) {
self.nodes.push(IncludesNode { path: path.clone(), custom_gates_pragma });
if custom_gates_usage {
self.custom_gates_nodes.push(path.clone());
}
}

pub fn add_edge(&mut self, path: String) -> Result<(), Report> {
let mut crr = self.nodes.last().unwrap().path.clone();
crr.pop();
crr.push(path.clone());
let path = std::fs::canonicalize(crr)
.map_err(|_| FileOsError { path: path })
.map_err(|e| FileOsError::produce_report(e))?;
let edges = self.adjacency.entry(path).or_insert(vec![]);
edges.push(self.nodes.len() - 1);
Ok(())
}

pub fn get_problematic_paths(&self) -> Vec<Vec<PathBuf>> {
let mut problematic_paths = Vec::new();
for file in &self.custom_gates_nodes {
let path_covered = vec![file.clone()];
let traversed_edges = HashSet::new();
problematic_paths.append(
&mut self.traverse(file, true, path_covered, traversed_edges)
);
}
problematic_paths
}

fn traverse(
&self,
from: &PathBuf,
ok: bool,
path: Vec<PathBuf>,
traversed_edges: HashSet<(PathBuf, PathBuf)>
) -> Vec<Vec<PathBuf>> {
let mut problematic_paths = Vec::new();
if let Some(edges) = self.adjacency.get(from) {
for to in edges {
let next = &self.nodes[*to];
let edge = (from.clone(), next.path.clone());
if !traversed_edges.contains(&edge) {
let new_path = {
let mut new_path = path.clone();
new_path.push(next.path.clone());
new_path
};
let new_traversed_edges = {
let mut new_traversed_edges = traversed_edges.clone();
new_traversed_edges.insert((from.clone(), next.path.clone()));
new_traversed_edges
};
problematic_paths.append(
&mut self.traverse(
&next.path,
ok && next.custom_gates_pragma,
new_path,
new_traversed_edges
)
);
}
}
problematic_paths
} else {
if ok { vec![] } else { vec![path] }
}
}

pub fn display_path(path: &Vec<PathBuf>) -> String {
let path = path.iter().map(|file| -> String {
let file = format!("{}", file.display());
let (_, file) = file.rsplit_once("/").unwrap();
file.clone().to_string()
}).collect::<Vec<String>>();
let mut path_covered = format!("{}", path[0]);
for file in &path[1..] {
path_covered = format!("{} -> {}", path_covered, file);
}
path_covered
}
}
24 changes: 5 additions & 19 deletions parser/src/lang.lalrpop
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ ParsePragma : Version = { // maybe change to usize instead of BigInt
=> version,
};

// Pragma to indicate that we are using PLONK with custom gates.
// Pragma to indicate that we are allowing the definition of custom gates.
ParseCustomGates : () = {
"pragma" "ultraPlonk" ";" => ()
"pragma" "custom_templates" ";" => ()
}

// Includes are added at the start of the file.
Expand Down Expand Up @@ -77,19 +77,12 @@ pub ParseDefinition : Definition = {
Some(a)
=> build_function(Meta::new(s,e),name,a,args..arge,body),
},
<s:@L> "template" <parallel: "parallel"?> <name: IDENTIFIER> "(" <args:@L> <arg_names: IdentifierListDef?> <arge:@R> ")" <body: ParseBlock> <e:@R>
<s:@L> "template" <custom_gate: "custom"?> <parallel: "parallel"?> <name: IDENTIFIER> "(" <args:@L> <arg_names: IdentifierListDef?> <arge:@R> ")" <body: ParseBlock> <e:@R>
=> match arg_names {
None
=> build_template(Meta::new(s,e), name, Vec::new(), args..arge, body, parallel.is_some(), false),
=> build_template(Meta::new(s,e), name, Vec::new(), args..arge, body, parallel.is_some(), custom_gate.is_some()),
Some(a)
=> build_template(Meta::new(s,e), name, a, args..arge, body, parallel.is_some(), false),
},
<s:@L> "custom_gate" <parallel: "parallel"?> <name: IDENTIFIER> "(" <args:@L> <arg_names: IdentifierListDef?> <arge:@R> ")" <body: ParseBlock> <e:@R>
=> match arg_names {
None
=> build_template(Meta::new(s,e), name, Vec::new(), args..arge, body, parallel.is_some(), true),
Some(a)
=> build_template(Meta::new(s,e), name, a, args..arge, body, parallel.is_some(), true),
=> build_template(Meta::new(s,e), name, a, args..arge, body, parallel.is_some(), custom_gate.is_some()),
},
};

Expand Down Expand Up @@ -196,13 +189,6 @@ ParseDeclaration : Statement = {
symbols.push(symbol);
ast_shortcuts::split_declaration_into_single_nodes(meta,xtype,symbols,AssignOp::AssignVar)
},
<s:@L> "custom_component" <symbols:(<SomeSymbol> ",")*> <symbol: SomeSymbol> <e:@R> => {
let mut symbols = symbols;
let meta = Meta::new(s,e);
let xtype = VariableType::Component;
symbols.push(symbol);
ast_shortcuts::split_declaration_into_single_nodes(meta,xtype,symbols,AssignOp::AssignVar)
},
<s:@L><xtype: SignalHeader> <symbols:(<SignalSymbol> ",")*> <symbol: SignalSymbol> <e:@R>
=> {
let mut symbols = symbols;
Expand Down
99 changes: 67 additions & 32 deletions parser/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ extern crate lalrpop_util;

lalrpop_mod!(pub lang);


mod errors;
mod include_logic;
mod parser_logic;
use include_logic::FileStack;
use include_logic::{FileStack, IncludesGraph};
use program_structure::error_code::ReportCode;
use program_structure::error_definition::{Report, ReportCollection};
use program_structure::file_definition::{FileLibrary};
use program_structure::program_archive::ProgramArchive;
Expand All @@ -20,30 +20,41 @@ use std::str::FromStr;

pub type Version = (usize, usize, usize);


pub fn run_parser(file: String, version: &str) -> Result<(ProgramArchive, ReportCollection), (FileLibrary, ReportCollection)> {
pub fn run_parser(
file: String,
version: &str
) -> Result<(ProgramArchive, ReportCollection), (FileLibrary, ReportCollection)> {
let mut file_library = FileLibrary::new();
let mut definitions = Vec::new();
let mut main_components = Vec::new();
let mut file_stack = FileStack::new(PathBuf::from(file));
let mut includes_graph = IncludesGraph::new();
let mut warnings = Vec::new();

while let Some(crr_file) = FileStack::take_next(&mut file_stack) {
let (path, src) = open_file(crr_file).map_err(|e| (file_library.clone(), vec![e]))?;
let (path, src) = open_file(crr_file.clone())
.map_err(|e| (file_library.clone(), vec![e]))?;
let file_id = file_library.add_file(path.clone(), src.clone());
let program =
parser_logic::parse_file(&src, file_id).map_err(|e| (file_library.clone(), vec![e]))?;

let program = parser_logic::parse_file(&src, file_id)
.map_err(|e| (file_library.clone(), vec![e]))?;
if let Some(main) = program.main_component {
main_components.push((file_id, main));
}
includes_graph.add_node(crr_file, program.custom_gates, program.custom_gates_declared);
let includes = program.includes;
definitions.push((file_id, program.definitions));
for include in includes {
FileStack::add_include(&mut file_stack, include)
FileStack::add_include(&mut file_stack, include.clone())
.map_err(|e| (file_library.clone(), vec![e]))?;
includes_graph.add_edge(include).map_err(|e| (file_library.clone(), vec![e]))?;
}
warnings.append(&mut check_number_version(path, program.compiler_version, parse_number_version(version)).map_err(|e| (file_library.clone(), vec![e]))?);
warnings.append(
&mut check_number_version(
path,
program.compiler_version,
parse_number_version(version)
).map_err(|e| (file_library.clone(), vec![e]))?
);
}

if main_components.len() == 0 {
Expand All @@ -53,21 +64,34 @@ pub fn run_parser(file: String, version: &str) -> Result<(ProgramArchive, Report
let report = errors::MultipleMainError::produce_report();
Err((file_library, vec![report]))
} else {
let (main_id, main_component) = main_components.pop().unwrap();
let result_program_archive =
ProgramArchive::new(file_library, main_id, main_component, definitions);
match result_program_archive {
Err((lib, rep)) => {
Err((lib, rep))
}
Ok(program_archive) => {
Ok((program_archive, warnings))
let errors: ReportCollection = includes_graph.get_problematic_paths().iter().map(|path|
Report::error(
format!(
"Missing custom gates' pragma in the following chain of includes {}",
IncludesGraph::display_path(path)
),
ReportCode::CustomGatesPragmaError
)
).collect();
if errors.len() > 0 {
Err((file_library, errors))
} else {
let (main_id, main_component) = main_components.pop().unwrap();
let result_program_archive =
ProgramArchive::new(file_library, main_id, main_component, definitions);
match result_program_archive {
Err((lib, rep)) => {
Err((lib, rep))
}
Ok(program_archive) => {
Ok((program_archive, warnings))
}
}
}
}
}

fn open_file(path: PathBuf) -> Result<(String, String), Report> /* path, src*/ {
fn open_file(path: PathBuf) -> Result<(String, String), Report> /* path, src */ {
use errors::FileOsError;
use std::fs::read_to_string;
let path_str = format!("{:?}", path);
Expand All @@ -77,28 +101,39 @@ fn open_file(path: PathBuf) -> Result<(String, String), Report> /* path, src*/ {
.map_err(|e| FileOsError::produce_report(e))
}

fn parse_number_version(version: &str) -> Version{
fn parse_number_version(version: &str) -> Version {
let version_splitted: Vec<&str> = version.split(".").collect();

(usize::from_str(version_splitted[0]).unwrap(), usize::from_str(version_splitted[1]).unwrap(), usize::from_str(version_splitted[2]).unwrap())
}

fn check_number_version(file_path: String, version_file: Option<Version>, version_compiler: Version) -> Result<ReportCollection, Report>{
fn check_number_version(
file_path: String,
version_file: Option<Version>,
version_compiler: Version
) -> Result<ReportCollection, Report> {
use errors::{CompilerVersionError, NoCompilerVersionWarning};
if let Some(required_version) = version_file {

if required_version.0 == version_compiler.0
&& required_version.1 == version_compiler.1
&& required_version.2 <= version_compiler.2{
&& required_version.2 <= version_compiler.2 {
Ok(vec![])
}
else{
let report = CompilerVersionError::produce_report(CompilerVersionError{path: file_path, required_version: required_version, version: version_compiler});
} else {
let report = CompilerVersionError::produce_report(
CompilerVersionError{
path: file_path,
required_version,
version: version_compiler
}
);
Err(report)
}
}
else{
let report = NoCompilerVersionWarning::produce_report(NoCompilerVersionWarning{path: file_path, version: version_compiler});
} else {
let report = NoCompilerVersionWarning::produce_report(
NoCompilerVersionWarning{
path: file_path,
version: version_compiler
}
);
Ok(vec![report])
}
}
}
14 changes: 13 additions & 1 deletion program_structure/src/abstract_syntax_tree/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ pub struct AST {
pub meta: Meta,
pub compiler_version: Option<Version>,
pub custom_gates: bool,
pub custom_gates_declared: bool,
pub includes: Vec<String>,
pub definitions: Vec<Definition>,
pub main_component: Option<MainComponent>,
Expand All @@ -94,7 +95,18 @@ impl AST {
definitions: Vec<Definition>,
main_component: Option<MainComponent>,
) -> AST {
AST { meta, compiler_version, custom_gates, includes, definitions, main_component }
let custom_gates_declared = definitions.iter().any(
|definition| matches!(definition, Definition::Template { is_custom_gate: true, .. })
);
AST {
meta,
compiler_version,
custom_gates,
custom_gates_declared,
includes,
definitions,
main_component
}
}
}

Expand Down
8 changes: 8 additions & 0 deletions program_structure/src/program_library/error_code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ pub enum ReportCode {
OneConstraintIntermediate,
NoOutputInInstance,
ErrorWat2Wasm,
CustomGateIntermediateSignalWarning,
CustomGateConstraint,
CustomGateSubComponent,
CustomGatesPragmaError,
}
impl fmt::Display for ReportCode {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
Expand Down Expand Up @@ -138,6 +142,10 @@ impl fmt::Display for ReportCode {
OneConstraintIntermediate => "CA02",
NoOutputInInstance => "CA03",
ErrorWat2Wasm => "W01",
CustomGateIntermediateSignalWarning => "CG01",
CustomGateConstraint => "CG02",
CustomGateSubComponent => "CG03",
CustomGatesPragmaError => "CG04",
};
f.write_str(string_format)
}
Expand Down
Loading

0 comments on commit d472c3f

Please sign in to comment.