acir/circuit/black_box_functions.rs
1//! Black box functions are ACIR opcodes which rely on backends implementing
2//! support for specialized constraints.
3//! This makes certain zk-snark unfriendly computations cheaper than if they were
4//! implemented in more basic constraints.
5
6use serde::{Deserialize, Serialize};
7use strum_macros::EnumIter;
8
9/// Representation of available black box function names.
10/// This enum should be used to represent a black box before we have set up the
11/// appropriate inputs and outputs. At which point it should be converted to a [`crate::circuit::opcodes::BlackBoxFuncCall`]
12#[allow(clippy::upper_case_acronyms)]
13#[derive(Clone, Debug, Hash, Copy, PartialEq, Eq, Serialize, Deserialize, EnumIter)]
14pub enum BlackBoxFunc {
15 /// More details can be found at [`crate::circuit::opcodes::BlackBoxFuncCall::AES128Encrypt`]
16 AES128Encrypt,
17 /// More details can be found at [`crate::circuit::opcodes::BlackBoxFuncCall::AND`]
18 AND,
19 /// More details can be found at [`crate::circuit::opcodes::BlackBoxFuncCall::XOR`]
20 XOR,
21 /// More details can be found at [`crate::circuit::opcodes::BlackBoxFuncCall::RANGE`]
22 RANGE,
23 /// More details can be found at [`crate::circuit::opcodes::BlackBoxFuncCall::Blake2s`]
24 Blake2s,
25 /// More details can be found at [`crate::circuit::opcodes::BlackBoxFuncCall::Blake3`]
26 Blake3,
27 /// More details can be found at [`crate::circuit::opcodes::BlackBoxFuncCall::EcdsaSecp256k1`]
28 EcdsaSecp256k1,
29 /// More details can be found at [`crate::circuit::opcodes::BlackBoxFuncCall::EcdsaSecp256r1`]
30 EcdsaSecp256r1,
31 /// More details can be found at [`crate::circuit::opcodes::BlackBoxFuncCall::MultiScalarMul`]
32 MultiScalarMul,
33 /// More details can be found at [`crate::circuit::opcodes::BlackBoxFuncCall::Keccakf1600`]
34 Keccakf1600,
35 /// More details can be found at [`crate::circuit::opcodes::BlackBoxFuncCall::RecursiveAggregation`]
36 RecursiveAggregation,
37 /// More details can be found at [`crate::circuit::opcodes::BlackBoxFuncCall::EmbeddedCurveAdd`]
38 EmbeddedCurveAdd,
39 /// More details can be found at [`crate::circuit::opcodes::BlackBoxFuncCall::Poseidon2Permutation`]
40 Poseidon2Permutation,
41 /// More details can be found at [`crate::circuit::opcodes::BlackBoxFuncCall::Sha256Compression`]
42 Sha256Compression,
43}
44
45impl std::fmt::Display for BlackBoxFunc {
46 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47 write!(f, "{}", self.name())
48 }
49}
50
51impl BlackBoxFunc {
52 pub fn name(&self) -> &'static str {
53 match self {
54 BlackBoxFunc::AES128Encrypt => "aes128_encrypt",
55 BlackBoxFunc::Blake2s => "blake2s",
56 BlackBoxFunc::Blake3 => "blake3",
57 BlackBoxFunc::EcdsaSecp256k1 => "ecdsa_secp256k1",
58 BlackBoxFunc::MultiScalarMul => "multi_scalar_mul",
59 BlackBoxFunc::EmbeddedCurveAdd => "embedded_curve_add",
60 BlackBoxFunc::AND => "and",
61 BlackBoxFunc::XOR => "xor",
62 BlackBoxFunc::RANGE => "range",
63 BlackBoxFunc::Keccakf1600 => "keccakf1600",
64 BlackBoxFunc::RecursiveAggregation => "recursive_aggregation",
65 BlackBoxFunc::EcdsaSecp256r1 => "ecdsa_secp256r1",
66 BlackBoxFunc::Poseidon2Permutation => "poseidon2_permutation",
67 BlackBoxFunc::Sha256Compression => "sha256_compression",
68 }
69 }
70
71 pub fn lookup(op_name: &str) -> Option<BlackBoxFunc> {
72 match op_name {
73 "aes128_encrypt" => Some(BlackBoxFunc::AES128Encrypt),
74 "blake2s" => Some(BlackBoxFunc::Blake2s),
75 "blake3" => Some(BlackBoxFunc::Blake3),
76 "ecdsa_secp256k1" => Some(BlackBoxFunc::EcdsaSecp256k1),
77 "ecdsa_secp256r1" => Some(BlackBoxFunc::EcdsaSecp256r1),
78 "multi_scalar_mul" => Some(BlackBoxFunc::MultiScalarMul),
79 "embedded_curve_add" => Some(BlackBoxFunc::EmbeddedCurveAdd),
80 "and" => Some(BlackBoxFunc::AND),
81 "xor" => Some(BlackBoxFunc::XOR),
82 "range" => Some(BlackBoxFunc::RANGE),
83 "keccakf1600" => Some(BlackBoxFunc::Keccakf1600),
84 "recursive_aggregation" => Some(BlackBoxFunc::RecursiveAggregation),
85 "poseidon2_permutation" => Some(BlackBoxFunc::Poseidon2Permutation),
86 "sha256_compression" => Some(BlackBoxFunc::Sha256Compression),
87 _ => None,
88 }
89 }
90
91 pub fn has_side_effects(&self) -> bool {
92 match self {
93 BlackBoxFunc::RecursiveAggregation
94 | BlackBoxFunc::MultiScalarMul
95 | BlackBoxFunc::EmbeddedCurveAdd
96 | BlackBoxFunc::EcdsaSecp256k1
97 | BlackBoxFunc::EcdsaSecp256r1
98 | BlackBoxFunc::RANGE => true,
99
100 BlackBoxFunc::AES128Encrypt
101 | BlackBoxFunc::AND
102 | BlackBoxFunc::XOR
103 | BlackBoxFunc::Blake2s
104 | BlackBoxFunc::Blake3
105 | BlackBoxFunc::Keccakf1600
106 | BlackBoxFunc::Poseidon2Permutation
107 | BlackBoxFunc::Sha256Compression => false,
108 }
109 }
110
111 /// This function will return the number of inputs that a blackbox function
112 /// expects. Returning `None` if there is no expectation.
113 pub fn expected_input_size(&self) -> Option<usize> {
114 match self {
115 // Bitwise opcodes will take in 2 parameters
116 BlackBoxFunc::AND | BlackBoxFunc::XOR => Some(2),
117
118 // All of the hash/cipher methods will take in a
119 // variable number of inputs.
120 BlackBoxFunc::AES128Encrypt | BlackBoxFunc::Blake2s | BlackBoxFunc::Blake3 => None,
121
122 BlackBoxFunc::Keccakf1600 => Some(25),
123 // The permutation takes a fixed number of inputs, but the inputs length depends on the proving system implementation.
124 BlackBoxFunc::Poseidon2Permutation => None,
125
126 // SHA256 compression requires 16 u32s as input message and 8 u32s for the hash state.
127 BlackBoxFunc::Sha256Compression => Some(24),
128 // Can only apply a range constraint to one
129 // witness at a time.
130 BlackBoxFunc::RANGE => Some(1),
131
132 // 64 bytes for the signature, 32 bytes for the hashed message,
133 // and 32 bytes each for the x and y coordinates of the public key, plus a predicate.
134 BlackBoxFunc::EcdsaSecp256k1 | BlackBoxFunc::EcdsaSecp256r1 => Some(161),
135
136 // Inputs for multi scalar multiplication is an arbitrary number of [point, scalar] pairs.
137 BlackBoxFunc::MultiScalarMul => None,
138
139 // Recursive aggregation has a variable number of inputs
140 BlackBoxFunc::RecursiveAggregation => None,
141
142 // Addition over the embedded curve: inputs are coordinates (x1,y1) and (x2,y2) of the Grumpkin points
143 // to add, plus a predicate to conditionally perform the addition.
144 BlackBoxFunc::EmbeddedCurveAdd => Some(5),
145 }
146 }
147
148 /// This function will return the number of outputs that a blackbox function
149 /// expects. Returning `None` if there is no expectation.
150 pub fn expected_output_size(&self) -> Option<usize> {
151 match self {
152 // Bitwise opcodes will return 1 parameter which is the output
153 // or the operation.
154 BlackBoxFunc::AND | BlackBoxFunc::XOR => Some(1),
155
156 // 32 byte hash algorithms
157 BlackBoxFunc::Blake2s | BlackBoxFunc::Blake3 => Some(32),
158
159 BlackBoxFunc::Keccakf1600 => Some(25),
160 // The permutation returns a fixed number of outputs, equals to the inputs length which depends on the proving system implementation.
161 BlackBoxFunc::Poseidon2Permutation => None,
162
163 BlackBoxFunc::Sha256Compression => Some(8),
164
165 BlackBoxFunc::RANGE => Some(0),
166
167 // Signature verification algorithms will return a boolean
168 BlackBoxFunc::EcdsaSecp256k1 | BlackBoxFunc::EcdsaSecp256r1 => Some(1),
169
170 // Output of operations over the embedded curve
171 // will be 2 field elements representing the point, i.e. (x,y)
172 BlackBoxFunc::MultiScalarMul | BlackBoxFunc::EmbeddedCurveAdd => Some(2),
173
174 // Recursive aggregation has no output
175 BlackBoxFunc::RecursiveAggregation => Some(0),
176
177 // AES encryption returns a variable number of outputs
178 BlackBoxFunc::AES128Encrypt => None,
179 }
180 }
181}
182
183#[cfg(test)]
184mod tests {
185 use strum::IntoEnumIterator;
186
187 use crate::BlackBoxFunc;
188
189 #[test]
190 fn consistent_function_names() {
191 for bb_func in BlackBoxFunc::iter() {
192 let resolved_func = BlackBoxFunc::lookup(bb_func.name()).unwrap_or_else(|| {
193 panic!("BlackBoxFunc::lookup couldn't find black box function {bb_func}")
194 });
195 assert_eq!(
196 resolved_func, bb_func,
197 "BlackBoxFunc::lookup returns unexpected BlackBoxFunc"
198 );
199 }
200 }
201}