acir/proto/convert/
acir.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
use crate::{
    circuit::{
        self,
        brillig::BrilligFunctionId,
        opcodes::{self, AcirFunctionId, BlockId},
    },
    proto::acir::circuit::{
        AssertMessage, AssertionPayload, BlackBoxFuncCall, BlockType, BrilligInputs,
        BrilligOutputs, Circuit, ConstantOrWitnessEnum, ExpressionOrMemory, ExpressionWidth,
        FunctionInput, MemOp, Opcode, OpcodeLocation,
    },
};
use acir_field::AcirField;
use color_eyre::eyre::{self, Context};
use noir_protobuf::{ProtoCodec, decode_oneof_map};

use super::ProtoSchema;

impl<F: AcirField> ProtoCodec<circuit::Circuit<F>, Circuit> for ProtoSchema<F> {
    fn encode(value: &circuit::Circuit<F>) -> Circuit {
        Circuit {
            current_witness_index: value.current_witness_index,
            opcodes: Self::encode_vec(&value.opcodes),
            expression_width: Self::encode_some(&value.expression_width),
            private_parameters: Self::encode_vec(value.private_parameters.iter()),
            public_parameters: Self::encode_vec(value.public_parameters.0.iter()),
            return_values: Self::encode_vec(value.return_values.0.iter()),
            assert_messages: Self::encode_vec(&value.assert_messages),
        }
    }

    fn decode(value: &Circuit) -> eyre::Result<circuit::Circuit<F>> {
        Ok(circuit::Circuit {
            current_witness_index: value.current_witness_index,
            opcodes: Self::decode_vec_wrap(&value.opcodes, "opcodes")?,
            expression_width: Self::decode_some_wrap(&value.expression_width, "expression_width")?,
            private_parameters: Self::decode_vec_wrap(
                &value.private_parameters,
                "private_parameters",
            )?
            .into_iter()
            .collect(),
            public_parameters: circuit::PublicInputs(
                Self::decode_vec_wrap(&value.public_parameters, "public_parameters")?
                    .into_iter()
                    .collect(),
            ),
            return_values: circuit::PublicInputs(
                Self::decode_vec_wrap(&value.return_values, "return_values")?.into_iter().collect(),
            ),
            assert_messages: Self::decode_vec_wrap(&value.assert_messages, "assert_messages")?,
        })
    }
}

impl<F> ProtoCodec<circuit::ExpressionWidth, ExpressionWidth> for ProtoSchema<F> {
    fn encode(value: &circuit::ExpressionWidth) -> ExpressionWidth {
        use crate::proto::acir::circuit::expression_width::*;
        let value = match value {
            circuit::ExpressionWidth::Unbounded => Value::Unbounded(Unbounded {}),
            circuit::ExpressionWidth::Bounded { width } => {
                Value::Bounded(Bounded { width: Self::encode(width) })
            }
        };
        ExpressionWidth { value: Some(value) }
    }

    fn decode(value: &ExpressionWidth) -> eyre::Result<circuit::ExpressionWidth> {
        use crate::proto::acir::circuit::expression_width::*;
        decode_oneof_map(&value.value, |value| match value {
            Value::Unbounded(_) => Ok(circuit::ExpressionWidth::Unbounded),
            Value::Bounded(v) => Ok(circuit::ExpressionWidth::Bounded {
                width: Self::decode_wrap(&v.width, "width")?,
            }),
        })
    }
}

impl<F> ProtoCodec<(circuit::OpcodeLocation, circuit::AssertionPayload<F>), AssertMessage>
    for ProtoSchema<F>
where
    F: AcirField,
{
    fn encode(value: &(circuit::OpcodeLocation, circuit::AssertionPayload<F>)) -> AssertMessage {
        AssertMessage {
            location: Self::encode_some(&value.0),
            payload: Self::encode_some(&value.1),
        }
    }

    fn decode(
        value: &AssertMessage,
    ) -> eyre::Result<(circuit::OpcodeLocation, circuit::AssertionPayload<F>)> {
        let location = Self::decode_some_wrap(&value.location, "location")?;
        let payload = Self::decode_some_wrap(&value.payload, "payload")?;
        Ok((location, payload))
    }
}

impl<F> ProtoCodec<circuit::OpcodeLocation, OpcodeLocation> for ProtoSchema<F> {
    fn encode(value: &circuit::OpcodeLocation) -> OpcodeLocation {
        use crate::proto::acir::circuit::opcode_location::*;
        let value = match value {
            circuit::OpcodeLocation::Acir(size) => Value::Acir(Self::encode(size)),
            circuit::OpcodeLocation::Brillig { acir_index, brillig_index } => {
                Value::Brillig(BrilligLocation {
                    acir_index: Self::encode(acir_index),
                    brillig_index: Self::encode(brillig_index),
                })
            }
        };
        OpcodeLocation { value: Some(value) }
    }

    fn decode(value: &OpcodeLocation) -> eyre::Result<circuit::OpcodeLocation> {
        use crate::proto::acir::circuit::opcode_location::*;
        decode_oneof_map(&value.value, |value| match value {
            Value::Acir(location) => {
                Ok(circuit::OpcodeLocation::Acir(Self::decode_wrap(location, "location")?))
            }
            Value::Brillig(location) => Ok(circuit::OpcodeLocation::Brillig {
                acir_index: Self::decode_wrap(&location.acir_index, "acir_index")?,
                brillig_index: Self::decode_wrap(&location.brillig_index, "brillig_index")?,
            }),
        })
    }
}

impl<F> ProtoCodec<circuit::AssertionPayload<F>, AssertionPayload> for ProtoSchema<F>
where
    F: AcirField,
{
    fn encode(value: &circuit::AssertionPayload<F>) -> AssertionPayload {
        AssertionPayload {
            error_selector: value.error_selector,
            payload: Self::encode_vec(&value.payload),
        }
    }

    fn decode(value: &AssertionPayload) -> eyre::Result<circuit::AssertionPayload<F>> {
        Ok(circuit::AssertionPayload {
            error_selector: value.error_selector,
            payload: Self::decode_vec_wrap(&value.payload, "payload")?,
        })
    }
}

impl<F> ProtoCodec<circuit::ExpressionOrMemory<F>, ExpressionOrMemory> for ProtoSchema<F>
where
    F: AcirField,
{
    fn encode(value: &circuit::ExpressionOrMemory<F>) -> ExpressionOrMemory {
        use crate::proto::acir::circuit::expression_or_memory::*;
        let value = match value {
            circuit::ExpressionOrMemory::Expression(expression) => {
                Value::Expression(Self::encode(expression))
            }
            circuit::ExpressionOrMemory::Memory(block_id) => Value::Memory(block_id.0),
        };
        ExpressionOrMemory { value: Some(value) }
    }

    fn decode(value: &ExpressionOrMemory) -> eyre::Result<circuit::ExpressionOrMemory<F>> {
        use crate::proto::acir::circuit::expression_or_memory::*;
        decode_oneof_map(&value.value, |value| match value {
            Value::Expression(expression) => Ok(circuit::ExpressionOrMemory::Expression(
                Self::decode_wrap(expression, "expression")?,
            )),
            Value::Memory(id) => Ok(circuit::ExpressionOrMemory::Memory(BlockId(*id))),
        })
    }
}

impl<F> ProtoCodec<circuit::Opcode<F>, Opcode> for ProtoSchema<F>
where
    F: AcirField,
{
    fn encode(value: &circuit::Opcode<F>) -> Opcode {
        use crate::proto::acir::circuit::opcode::*;
        let value = match value {
            circuit::Opcode::AssertZero(expression) => Value::AssertZero(Self::encode(expression)),
            circuit::Opcode::BlackBoxFuncCall(black_box_func_call) => {
                Value::BlackboxFuncCall(Self::encode(black_box_func_call))
            }
            circuit::Opcode::MemoryOp { block_id, op, predicate } => Value::MemoryOp(MemoryOp {
                block_id: block_id.0,
                op: Self::encode_some(op),
                predicate: predicate.as_ref().map(Self::encode),
            }),
            circuit::Opcode::MemoryInit { block_id, init, block_type } => {
                Value::MemoryInit(MemoryInit {
                    block_id: block_id.0,
                    init: Self::encode_vec(init),
                    block_type: Self::encode_some(block_type),
                })
            }
            circuit::Opcode::BrilligCall { id, inputs, outputs, predicate } => {
                Value::BrilligCall(BrilligCall {
                    id: id.0,
                    inputs: Self::encode_vec(inputs),
                    outputs: Self::encode_vec(outputs),
                    predicate: predicate.as_ref().map(Self::encode),
                })
            }
            circuit::Opcode::Call { id, inputs, outputs, predicate } => Value::Call(Call {
                id: id.0,
                inputs: Self::encode_vec(inputs),
                outputs: Self::encode_vec(outputs),
                predicate: predicate.as_ref().map(Self::encode),
            }),
        };
        Opcode { value: Some(value) }
    }

    fn decode(value: &Opcode) -> eyre::Result<circuit::Opcode<F>> {
        use crate::proto::acir::circuit::opcode::*;
        decode_oneof_map(&value.value, |value| match value {
            Value::AssertZero(expression) => {
                Ok(circuit::Opcode::AssertZero(Self::decode_wrap(expression, "assert_zero")?))
            }
            Value::BlackboxFuncCall(black_box_func_call) => Ok(circuit::Opcode::BlackBoxFuncCall(
                Self::decode_wrap(black_box_func_call, "blackbox_func_call")?,
            )),
            Value::MemoryOp(memory_op) => Ok(circuit::Opcode::MemoryOp {
                block_id: BlockId(memory_op.block_id),
                op: Self::decode_some_wrap(&memory_op.op, "op")?,
                predicate: Self::decode_opt_wrap(&memory_op.predicate, "predicate")?,
            }),
            Value::MemoryInit(memory_init) => Ok(circuit::Opcode::MemoryInit {
                block_id: BlockId(memory_init.block_id),
                init: Self::decode_vec_wrap(&memory_init.init, "init")?,
                block_type: Self::decode_some_wrap(&memory_init.block_type, "block_type")?,
            }),
            Value::BrilligCall(brillig_call) => Ok(circuit::Opcode::BrilligCall {
                id: BrilligFunctionId(brillig_call.id),
                inputs: Self::decode_vec_wrap(&brillig_call.inputs, "inputs")?,
                outputs: Self::decode_vec_wrap(&brillig_call.outputs, "outputs")?,
                predicate: Self::decode_opt_wrap(&brillig_call.predicate, "predicate")?,
            }),
            Value::Call(call) => Ok(circuit::Opcode::Call {
                id: AcirFunctionId(call.id),
                inputs: Self::decode_vec_wrap(&call.inputs, "inputs")?,
                outputs: Self::decode_vec_wrap(&call.outputs, "outputs")?,
                predicate: Self::decode_opt_wrap(&call.predicate, "predicate")?,
            }),
        })
    }
}

impl<F> ProtoCodec<opcodes::MemOp<F>, MemOp> for ProtoSchema<F>
where
    F: AcirField,
{
    fn encode(value: &opcodes::MemOp<F>) -> MemOp {
        MemOp {
            operation: Self::encode_some(&value.operation),
            index: Self::encode_some(&value.index),
            value: Self::encode_some(&value.value),
        }
    }

    fn decode(value: &MemOp) -> eyre::Result<opcodes::MemOp<F>> {
        Ok(opcodes::MemOp {
            operation: Self::decode_some_wrap(&value.operation, "operation")?,
            index: Self::decode_some_wrap(&value.index, "index")?,
            value: Self::decode_some_wrap(&value.value, "value")?,
        })
    }
}

impl<F> ProtoCodec<opcodes::BlackBoxFuncCall<F>, BlackBoxFuncCall> for ProtoSchema<F>
where
    F: AcirField,
{
    fn encode(value: &opcodes::BlackBoxFuncCall<F>) -> BlackBoxFuncCall {
        use crate::proto::acir::circuit::black_box_func_call::*;
        let value = match value {
            opcodes::BlackBoxFuncCall::AES128Encrypt { inputs, iv, key, outputs } => {
                Value::Aes128Encrypt(Aes128Encrypt {
                    inputs: Self::encode_vec(inputs),
                    iv: Self::encode_vec(iv.as_ref()),
                    key: Self::encode_vec(key.as_ref()),
                    outputs: Self::encode_vec(outputs),
                })
            }
            opcodes::BlackBoxFuncCall::AND { lhs, rhs, output } => Value::And(And {
                lhs: Self::encode_some(lhs),
                rhs: Self::encode_some(rhs),
                output: Self::encode_some(output),
            }),
            opcodes::BlackBoxFuncCall::XOR { lhs, rhs, output } => Value::Xor(Xor {
                lhs: Self::encode_some(lhs),
                rhs: Self::encode_some(rhs),
                output: Self::encode_some(output),
            }),
            opcodes::BlackBoxFuncCall::RANGE { input } => {
                Value::Range(Range { input: Self::encode_some(input) })
            }
            opcodes::BlackBoxFuncCall::Blake2s { inputs, outputs } => Value::Blake2s(Blake2s {
                inputs: Self::encode_vec(inputs),
                outputs: Self::encode_vec(outputs.as_ref()),
            }),
            opcodes::BlackBoxFuncCall::Blake3 { inputs, outputs } => Value::Blake3(Blake3 {
                inputs: Self::encode_vec(inputs),
                outputs: Self::encode_vec(outputs.as_ref()),
            }),
            opcodes::BlackBoxFuncCall::EcdsaSecp256k1 {
                public_key_x,
                public_key_y,
                signature,
                hashed_message,
                output,
            } => Value::EcdsaSecp256k1(EcdsaSecp256k1 {
                public_key_x: Self::encode_vec(public_key_x.as_ref()),
                public_key_y: Self::encode_vec(public_key_y.as_ref()),
                signature: Self::encode_vec(signature.as_ref()),
                hashed_message: Self::encode_vec(hashed_message.as_ref()),
                output: Self::encode_some(output),
            }),
            opcodes::BlackBoxFuncCall::EcdsaSecp256r1 {
                public_key_x,
                public_key_y,
                signature,
                hashed_message,
                output,
            } => Value::EcdsaSecp256r1(EcdsaSecp256r1 {
                public_key_x: Self::encode_vec(public_key_x.as_ref()),
                public_key_y: Self::encode_vec(public_key_y.as_ref()),
                signature: Self::encode_vec(signature.as_ref()),
                hashed_message: Self::encode_vec(hashed_message.as_ref()),
                output: Self::encode_some(output),
            }),
            opcodes::BlackBoxFuncCall::MultiScalarMul { points, scalars, outputs } => {
                let (w1, w2, w3) = outputs;
                Value::MultiScalarMul(MultiScalarMul {
                    points: Self::encode_vec(points),
                    scalars: Self::encode_vec(scalars),
                    outputs: Self::encode_vec([w1, w2, w3]),
                })
            }
            opcodes::BlackBoxFuncCall::EmbeddedCurveAdd { input1, input2, outputs } => {
                let (w1, w2, w3) = outputs;
                Value::EmbeddedCurveAdd(EmbeddedCurveAdd {
                    input1: Self::encode_vec(input1.as_ref()),
                    input2: Self::encode_vec(input2.as_ref()),
                    outputs: Self::encode_vec([w1, w2, w3]),
                })
            }
            opcodes::BlackBoxFuncCall::Keccakf1600 { inputs, outputs } => {
                Value::KeccakF1600(Keccakf1600 {
                    inputs: Self::encode_vec(inputs.as_ref()),
                    outputs: Self::encode_vec(outputs.as_ref()),
                })
            }
            opcodes::BlackBoxFuncCall::RecursiveAggregation {
                verification_key,
                proof,
                public_inputs,
                key_hash,
                proof_type,
            } => Value::RecursiveAggregation(RecursiveAggregation {
                verification_key: Self::encode_vec(verification_key),
                proof: Self::encode_vec(proof),
                public_inputs: Self::encode_vec(public_inputs),
                key_hash: Self::encode_some(key_hash),
                proof_type: *proof_type,
            }),
            opcodes::BlackBoxFuncCall::BigIntAdd { lhs, rhs, output } => {
                Value::BigIntAdd(BigIntAdd { lhs: *lhs, rhs: *rhs, output: *output })
            }
            opcodes::BlackBoxFuncCall::BigIntSub { lhs, rhs, output } => {
                Value::BigIntSub(BigIntSub { lhs: *lhs, rhs: *rhs, output: *output })
            }
            opcodes::BlackBoxFuncCall::BigIntMul { lhs, rhs, output } => {
                Value::BigIntMul(BigIntMul { lhs: *lhs, rhs: *rhs, output: *output })
            }
            opcodes::BlackBoxFuncCall::BigIntDiv { lhs, rhs, output } => {
                Value::BigIntDiv(BigIntDiv { lhs: *lhs, rhs: *rhs, output: *output })
            }
            opcodes::BlackBoxFuncCall::BigIntFromLeBytes { inputs, modulus, output } => {
                Value::BigIntFromLeBytes(BigIntFromLeBytes {
                    inputs: Self::encode_vec(inputs),
                    modulus: modulus.clone(),
                    output: *output,
                })
            }
            opcodes::BlackBoxFuncCall::BigIntToLeBytes { input, outputs } => {
                Value::BigIntToLeBytes(BigIntToLeBytes {
                    input: *input,
                    outputs: Self::encode_vec(outputs),
                })
            }
            opcodes::BlackBoxFuncCall::Poseidon2Permutation { inputs, outputs, len } => {
                Value::Poseidon2Permutation(Poseidon2Permutation {
                    inputs: Self::encode_vec(inputs),
                    outputs: Self::encode_vec(outputs),
                    len: *len,
                })
            }
            opcodes::BlackBoxFuncCall::Sha256Compression { inputs, hash_values, outputs } => {
                Value::Sha256Compression(Sha256Compression {
                    inputs: Self::encode_vec(inputs.as_ref()),
                    hash_values: Self::encode_vec(hash_values.as_ref()),
                    outputs: Self::encode_vec(outputs.as_ref()),
                })
            }
        };
        BlackBoxFuncCall { value: Some(value) }
    }

    fn decode(value: &BlackBoxFuncCall) -> eyre::Result<opcodes::BlackBoxFuncCall<F>> {
        use crate::proto::acir::circuit::black_box_func_call::*;
        decode_oneof_map(
            &value.value,
            |value| -> Result<opcodes::BlackBoxFuncCall<F>, eyre::Error> {
                match value {
                    Value::Aes128Encrypt(v) => Ok(opcodes::BlackBoxFuncCall::AES128Encrypt {
                        inputs: Self::decode_vec_wrap(&v.inputs, "inputs")?,
                        iv: Self::decode_box_arr_wrap(&v.iv, "iv")?,
                        key: Self::decode_box_arr_wrap(&v.key, "key")?,
                        outputs: Self::decode_vec_wrap(&v.outputs, "witness")?,
                    }),
                    Value::And(v) => Ok(opcodes::BlackBoxFuncCall::AND {
                        lhs: Self::decode_some_wrap(&v.lhs, "lhs")?,
                        rhs: Self::decode_some_wrap(&v.rhs, "rhs")?,
                        output: Self::decode_some_wrap(&v.output, "output")?,
                    }),
                    Value::Xor(v) => Ok(opcodes::BlackBoxFuncCall::XOR {
                        lhs: Self::decode_some_wrap(&v.lhs, "lhs")?,
                        rhs: Self::decode_some_wrap(&v.rhs, "rhs")?,
                        output: Self::decode_some_wrap(&v.output, "output")?,
                    }),
                    Value::Range(v) => Ok(opcodes::BlackBoxFuncCall::RANGE {
                        input: Self::decode_some_wrap(&v.input, "input")?,
                    }),
                    Value::Blake2s(v) => Ok(opcodes::BlackBoxFuncCall::Blake2s {
                        inputs: Self::decode_vec_wrap(&v.inputs, "inputs")?,
                        outputs: Self::decode_box_arr_wrap(&v.outputs, "outputs")?,
                    }),
                    Value::Blake3(v) => Ok(opcodes::BlackBoxFuncCall::Blake3 {
                        inputs: Self::decode_vec_wrap(&v.inputs, "inputs")?,
                        outputs: Self::decode_box_arr_wrap(&v.outputs, "outputs")?,
                    }),
                    Value::EcdsaSecp256k1(v) => Ok(opcodes::BlackBoxFuncCall::EcdsaSecp256k1 {
                        public_key_x: Self::decode_box_arr_wrap(&v.public_key_x, "public_key_x")?,
                        public_key_y: Self::decode_box_arr_wrap(&v.public_key_y, "public_key_y")?,
                        signature: Self::decode_box_arr_wrap(&v.signature, "signature")?,
                        hashed_message: Self::decode_box_arr_wrap(
                            &v.hashed_message,
                            "hashed_message",
                        )?,
                        output: Self::decode_some_wrap(&v.output, "output")?,
                    }),
                    Value::EcdsaSecp256r1(v) => Ok(opcodes::BlackBoxFuncCall::EcdsaSecp256r1 {
                        public_key_x: Self::decode_box_arr_wrap(&v.public_key_x, "public_key_x")?,
                        public_key_y: Self::decode_box_arr_wrap(&v.public_key_y, "public_key_y")?,
                        signature: Self::decode_box_arr_wrap(&v.signature, "signature")?,
                        hashed_message: Self::decode_box_arr_wrap(
                            &v.hashed_message,
                            "hashed_message",
                        )?,
                        output: Self::decode_some_wrap(&v.output, "output")?,
                    }),
                    Value::MultiScalarMul(v) => Ok(opcodes::BlackBoxFuncCall::MultiScalarMul {
                        points: Self::decode_vec_wrap(&v.points, "points")?,
                        scalars: Self::decode_vec_wrap(&v.scalars, "scalars")?,
                        outputs: Self::decode_arr_wrap(&v.outputs, "outputs")
                            .map(|[w1, w2, w3]| (w1, w2, w3))?,
                    }),
                    Value::EmbeddedCurveAdd(v) => Ok(opcodes::BlackBoxFuncCall::EmbeddedCurveAdd {
                        input1: Self::decode_box_arr_wrap(&v.input1, "input1")?,
                        input2: Self::decode_box_arr_wrap(&v.input2, "input2")?,
                        outputs: Self::decode_arr_wrap(&v.outputs, "outputs")
                            .map(|[w1, w2, w3]| (w1, w2, w3))?,
                    }),
                    Value::KeccakF1600(v) => Ok(opcodes::BlackBoxFuncCall::Keccakf1600 {
                        inputs: Self::decode_box_arr_wrap(&v.inputs, "inputs")?,
                        outputs: Self::decode_box_arr_wrap(&v.outputs, "outputs")?,
                    }),
                    Value::RecursiveAggregation(v) => {
                        Ok(opcodes::BlackBoxFuncCall::RecursiveAggregation {
                            verification_key: Self::decode_vec_wrap(
                                &v.verification_key,
                                "verification_key",
                            )?,
                            proof: Self::decode_vec_wrap(&v.proof, "proof")?,
                            public_inputs: Self::decode_vec_wrap(
                                &v.public_inputs,
                                "public_inputs",
                            )?,
                            key_hash: Self::decode_some_wrap(&v.key_hash, "key_hash")?,
                            proof_type: v.proof_type,
                        })
                    }
                    Value::BigIntAdd(v) => Ok(opcodes::BlackBoxFuncCall::BigIntAdd {
                        lhs: v.lhs,
                        rhs: v.rhs,
                        output: v.output,
                    }),
                    Value::BigIntSub(v) => Ok(opcodes::BlackBoxFuncCall::BigIntSub {
                        lhs: v.lhs,
                        rhs: v.rhs,
                        output: v.output,
                    }),
                    Value::BigIntMul(v) => Ok(opcodes::BlackBoxFuncCall::BigIntMul {
                        lhs: v.lhs,
                        rhs: v.rhs,
                        output: v.output,
                    }),
                    Value::BigIntDiv(v) => Ok(opcodes::BlackBoxFuncCall::BigIntDiv {
                        lhs: v.lhs,
                        rhs: v.rhs,
                        output: v.output,
                    }),
                    Value::BigIntFromLeBytes(v) => {
                        Ok(opcodes::BlackBoxFuncCall::BigIntFromLeBytes {
                            inputs: Self::decode_vec_wrap(&v.inputs, "inputs")?,
                            modulus: v.modulus.clone(),
                            output: v.output,
                        })
                    }
                    Value::BigIntToLeBytes(v) => Ok(opcodes::BlackBoxFuncCall::BigIntToLeBytes {
                        input: v.input,
                        outputs: Self::decode_vec_wrap(&v.outputs, "outputs")?,
                    }),
                    Value::Poseidon2Permutation(v) => {
                        Ok(opcodes::BlackBoxFuncCall::Poseidon2Permutation {
                            inputs: Self::decode_vec_wrap(&v.inputs, "inputs")?,
                            outputs: Self::decode_vec_wrap(&v.outputs, "outputs")?,
                            len: v.len,
                        })
                    }
                    Value::Sha256Compression(v) => {
                        Ok(opcodes::BlackBoxFuncCall::Sha256Compression {
                            inputs: Self::decode_box_arr_wrap(&v.inputs, "inputs")?,
                            hash_values: Self::decode_box_arr_wrap(&v.hash_values, "hash_values")?,
                            outputs: Self::decode_box_arr_wrap(&v.outputs, "outputs")?,
                        })
                    }
                }
            },
        )
    }
}

impl<F> ProtoCodec<opcodes::FunctionInput<F>, FunctionInput> for ProtoSchema<F>
where
    F: AcirField,
{
    fn encode(value: &opcodes::FunctionInput<F>) -> FunctionInput {
        FunctionInput { input: Self::encode_some(value.input_ref()), num_bits: value.num_bits() }
    }

    fn decode(value: &FunctionInput) -> eyre::Result<opcodes::FunctionInput<F>> {
        let input = Self::decode_some_wrap(&value.input, "input")?;

        match input {
            opcodes::ConstantOrWitnessEnum::Constant(c) => {
                opcodes::FunctionInput::constant(c, value.num_bits).wrap_err("constant")
            }
            opcodes::ConstantOrWitnessEnum::Witness(w) => {
                Ok(opcodes::FunctionInput::witness(w, value.num_bits))
            }
        }
    }
}

impl<F> ProtoCodec<opcodes::ConstantOrWitnessEnum<F>, ConstantOrWitnessEnum> for ProtoSchema<F>
where
    F: AcirField,
{
    fn encode(value: &opcodes::ConstantOrWitnessEnum<F>) -> ConstantOrWitnessEnum {
        use crate::proto::acir::circuit::constant_or_witness_enum::*;
        let value = match value {
            opcodes::ConstantOrWitnessEnum::Constant(field) => Value::Constant(Self::encode(field)),
            opcodes::ConstantOrWitnessEnum::Witness(witness) => {
                Value::Witness(Self::encode(witness))
            }
        };
        ConstantOrWitnessEnum { value: Some(value) }
    }

    fn decode(value: &ConstantOrWitnessEnum) -> eyre::Result<opcodes::ConstantOrWitnessEnum<F>> {
        use crate::proto::acir::circuit::constant_or_witness_enum::*;
        decode_oneof_map(&value.value, |value| match value {
            Value::Constant(field) => {
                Ok(opcodes::ConstantOrWitnessEnum::Constant(Self::decode_wrap(field, "constant")?))
            }
            Value::Witness(witness) => {
                Ok(opcodes::ConstantOrWitnessEnum::Witness(Self::decode_wrap(witness, "witness")?))
            }
        })
    }
}

impl<F> ProtoCodec<opcodes::BlockType, BlockType> for ProtoSchema<F> {
    fn encode(value: &opcodes::BlockType) -> BlockType {
        use crate::proto::acir::circuit::block_type::*;
        let value = match value {
            opcodes::BlockType::Memory => Value::Memory(Memory {}),
            opcodes::BlockType::CallData(value) => Value::CallData(CallData { value: *value }),
            opcodes::BlockType::ReturnData => Value::ReturnData(ReturnData {}),
        };
        BlockType { value: Some(value) }
    }

    fn decode(value: &BlockType) -> eyre::Result<opcodes::BlockType> {
        use crate::proto::acir::circuit::block_type::*;
        decode_oneof_map(&value.value, |value| match value {
            Value::Memory(_) => Ok(opcodes::BlockType::Memory),
            Value::CallData(v) => Ok(opcodes::BlockType::CallData(v.value)),
            Value::ReturnData(_) => Ok(opcodes::BlockType::ReturnData),
        })
    }
}

impl<F> ProtoCodec<circuit::brillig::BrilligInputs<F>, BrilligInputs> for ProtoSchema<F>
where
    F: AcirField,
{
    fn encode(value: &circuit::brillig::BrilligInputs<F>) -> BrilligInputs {
        use crate::proto::acir::circuit::brillig_inputs::*;
        let value = match value {
            circuit::brillig::BrilligInputs::Single(expression) => {
                Value::Single(Self::encode(expression))
            }
            circuit::brillig::BrilligInputs::Array(expressions) => {
                Value::Array(Array { values: Self::encode_vec(expressions) })
            }
            circuit::brillig::BrilligInputs::MemoryArray(block_id) => {
                Value::MemoryArray(block_id.0)
            }
        };
        BrilligInputs { value: Some(value) }
    }

    fn decode(value: &BrilligInputs) -> eyre::Result<circuit::brillig::BrilligInputs<F>> {
        use crate::proto::acir::circuit::brillig_inputs::*;
        decode_oneof_map(&value.value, |value| match value {
            Value::Single(expression) => Ok(circuit::brillig::BrilligInputs::Single(
                Self::decode_wrap(expression, "single")?,
            )),
            Value::Array(array) => Ok(circuit::brillig::BrilligInputs::Array(
                Self::decode_vec_wrap(&array.values, "array")?,
            )),
            Value::MemoryArray(id) => {
                Ok(circuit::brillig::BrilligInputs::MemoryArray(BlockId(*id)))
            }
        })
    }
}

impl<F> ProtoCodec<circuit::brillig::BrilligOutputs, BrilligOutputs> for ProtoSchema<F> {
    fn encode(value: &circuit::brillig::BrilligOutputs) -> BrilligOutputs {
        use crate::proto::acir::circuit::brillig_outputs::*;
        let value = match value {
            circuit::brillig::BrilligOutputs::Simple(witness) => {
                Value::Simple(Self::encode(witness))
            }
            circuit::brillig::BrilligOutputs::Array(witnesses) => {
                Value::Array(Array { values: Self::encode_vec(witnesses) })
            }
        };
        BrilligOutputs { value: Some(value) }
    }

    fn decode(value: &BrilligOutputs) -> eyre::Result<circuit::brillig::BrilligOutputs> {
        use crate::proto::acir::circuit::brillig_outputs::*;

        decode_oneof_map(&value.value, |value| match value {
            Value::Simple(witness) => {
                Ok(circuit::brillig::BrilligOutputs::Simple(Self::decode_wrap(witness, "simple")?))
            }
            Value::Array(array) => Ok(circuit::brillig::BrilligOutputs::Array(
                Self::decode_vec_wrap(&array.values, "array")?,
            )),
        })
    }
}