acir/
lib.rs

1#![forbid(unsafe_code)]
2#![warn(unreachable_pub)]
3#![warn(clippy::semicolon_if_nothing_returned)]
4#![cfg_attr(not(test), warn(unused_crate_dependencies, unused_extern_crates))]
5
6// Arbitrary Circuit Intermediate Representation
7
8pub mod circuit;
9pub mod native_types;
10
11pub use acir_field;
12pub use acir_field::FieldElement;
13pub use brillig;
14pub use circuit::black_box_functions::BlackBoxFunc;
15
16#[cfg(test)]
17mod reflection {
18    //! Getting test failures? You've probably changed the ACIR serialization format.
19    //!
20    //! These tests generate C++ deserializers for [`ACIR bytecode`][super::circuit::Circuit]
21    //! and the [`WitnessMap`] structs. These get checked against the C++ files committed to the `codegen` folder
22    //! to see if changes have been to the serialization format. These are almost always a breaking change!
23    //!
24    //! If you want to make a breaking change to the ACIR serialization format, then just comment out the assertions
25    //! that the file hashes must match and rerun the tests. This will overwrite the `codegen` folder with the new
26    //! logic. Make sure to uncomment these lines afterwards and to commit the changes to the `codegen` folder.
27
28    use std::{
29        fs::File,
30        io::Write,
31        path::{Path, PathBuf},
32    };
33
34    use brillig::{
35        BinaryFieldOp, BinaryIntOp, BlackBoxOp, HeapValueType, Opcode as BrilligOpcode,
36        ValueOrArray,
37    };
38    use serde_reflection::{Tracer, TracerConfig};
39
40    use crate::{
41        circuit::{
42            brillig::{BrilligInputs, BrilligOutputs},
43            directives::Directive,
44            opcodes::BlackBoxFuncCall,
45            AssertionPayload, Circuit, ExpressionOrMemory, ExpressionWidth, Opcode, OpcodeLocation,
46            Program,
47        },
48        native_types::{Witness, WitnessMap, WitnessStack},
49    };
50
51    #[test]
52    fn serde_acir_cpp_codegen() {
53        let path = PathBuf::from("./codegen/acir.cpp");
54
55        let old_hash = if path.is_file() {
56            let old_source = std::fs::read(&path).unwrap();
57            Some(fxhash::hash64(&old_source))
58        } else {
59            None
60        };
61
62        let mut tracer = Tracer::new(TracerConfig::default());
63        tracer.trace_simple_type::<Program>().unwrap();
64        tracer.trace_simple_type::<Circuit>().unwrap();
65        tracer.trace_simple_type::<ExpressionWidth>().unwrap();
66        tracer.trace_simple_type::<Opcode>().unwrap();
67        tracer.trace_simple_type::<OpcodeLocation>().unwrap();
68        tracer.trace_simple_type::<BinaryFieldOp>().unwrap();
69        tracer.trace_simple_type::<BlackBoxFuncCall>().unwrap();
70        tracer.trace_simple_type::<BrilligInputs>().unwrap();
71        tracer.trace_simple_type::<BrilligOutputs>().unwrap();
72        tracer.trace_simple_type::<BrilligOpcode>().unwrap();
73        tracer.trace_simple_type::<BinaryIntOp>().unwrap();
74        tracer.trace_simple_type::<BlackBoxOp>().unwrap();
75        tracer.trace_simple_type::<Directive>().unwrap();
76        tracer.trace_simple_type::<ValueOrArray>().unwrap();
77        tracer.trace_simple_type::<HeapValueType>().unwrap();
78        tracer.trace_simple_type::<AssertionPayload>().unwrap();
79        tracer.trace_simple_type::<ExpressionOrMemory>().unwrap();
80
81        let registry = tracer.registry().unwrap();
82
83        // Create C++ class definitions.
84        let mut source = Vec::new();
85        let config = serde_generate::CodeGeneratorConfig::new("Program".to_string())
86            .with_encodings(vec![serde_generate::Encoding::Bincode]);
87        let generator = serde_generate::cpp::CodeGenerator::new(&config);
88        generator.output(&mut source, &registry).unwrap();
89
90        // Comment this out to write updated C++ code to file.
91        if let Some(old_hash) = old_hash {
92            let new_hash = fxhash::hash64(&source);
93            assert_eq!(new_hash, old_hash, "Serialization format has changed");
94        }
95
96        write_to_file(&source, &path);
97    }
98
99    #[test]
100    fn serde_witness_map_cpp_codegen() {
101        let path = PathBuf::from("./codegen/witness.cpp");
102
103        let old_hash = if path.is_file() {
104            let old_source = std::fs::read(&path).unwrap();
105            Some(fxhash::hash64(&old_source))
106        } else {
107            None
108        };
109
110        let mut tracer = Tracer::new(TracerConfig::default());
111        tracer.trace_simple_type::<Witness>().unwrap();
112        tracer.trace_simple_type::<WitnessMap>().unwrap();
113        tracer.trace_simple_type::<WitnessStack>().unwrap();
114
115        let registry = tracer.registry().unwrap();
116
117        // Create C++ class definitions.
118        let mut source = Vec::new();
119        let config = serde_generate::CodeGeneratorConfig::new("WitnessStack".to_string())
120            .with_encodings(vec![serde_generate::Encoding::Bincode]);
121        let generator = serde_generate::cpp::CodeGenerator::new(&config);
122        generator.output(&mut source, &registry).unwrap();
123
124        // Comment this out to write updated C++ code to file.
125        if let Some(old_hash) = old_hash {
126            let new_hash = fxhash::hash64(&source);
127            assert_eq!(new_hash, old_hash, "Serialization format has changed");
128        }
129
130        write_to_file(&source, &path);
131    }
132
133    fn write_to_file(bytes: &[u8], path: &Path) -> String {
134        let display = path.display();
135
136        let parent_dir = path.parent().unwrap();
137        if !parent_dir.is_dir() {
138            std::fs::create_dir_all(parent_dir).unwrap();
139        }
140
141        let mut file = match File::create(path) {
142            Err(why) => panic!("couldn't create {display}: {why}"),
143            Ok(file) => file,
144        };
145
146        match file.write_all(bytes) {
147            Err(why) => panic!("couldn't write to {display}: {why}"),
148            Ok(_) => display.to_string(),
149        }
150    }
151}