Skip to content

Commit

Permalink
feat: Make Brillig do integer arithmetic operations using u128 instea…
Browse files Browse the repository at this point in the history
…d of Bigint (#7518)

This PR:
 - Restricts Brillig bit sizes to the ones supported by noir and the AVM
- Avoids using BigInteger, using u128 to represent integers in brillig
instead
 - Fixes a bug in truncate discovered by making bit size an enum
- Removes truncation in brillig_directive_quotient that wasn't needed
anymore

This generates a big performance boost, where [this
test](https://github.com/zac-williamson/noir_bigcurve/blob/main/src/bigcurve_test.nr#L129)
spent 110 seconds running the ACVM before, and 34 seconds after this
change.

Before:

![image](https://github.com/user-attachments/assets/18ba8cfa-867d-4a68-8d80-fdbda7018bd8)
After:

![image](https://github.com/user-attachments/assets/06b9eb08-5dbc-4be7-9f88-f32065839038)
  • Loading branch information
sirasistant authored Jul 23, 2024
1 parent 086522d commit 4a2011e
Show file tree
Hide file tree
Showing 25 changed files with 5,220 additions and 4,055 deletions.
42 changes: 25 additions & 17 deletions avm-transpiler/src/transpile.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::collections::BTreeMap;

use acvm::acir::brillig::Opcode as BrilligOpcode;
use acvm::acir::brillig::{BitSize, IntegerBitSize, Opcode as BrilligOpcode};

use acvm::acir::circuit::OpcodeLocation;
use acvm::brillig_vm::brillig::{
Expand Down Expand Up @@ -74,7 +74,7 @@ pub fn brillig_to_avm(
avm_instrs.push(AvmInstruction {
opcode: avm_opcode,
indirect: Some(ALL_DIRECT),
tag: Some(tag_from_bit_size(*bit_size)),
tag: Some(tag_from_bit_size(BitSize::Integer(*bit_size))),
operands: vec![
AvmOperand::U32 { value: lhs.to_usize() as u32 },
AvmOperand::U32 { value: rhs.to_usize() as u32 },
Expand Down Expand Up @@ -359,12 +359,12 @@ fn handle_cast(
avm_instrs: &mut Vec<AvmInstruction>,
source: &MemoryAddress,
destination: &MemoryAddress,
bit_size: u32,
bit_size: BitSize,
) {
let source_offset = source.to_usize() as u32;
let dest_offset = destination.to_usize() as u32;

if bit_size == 1 {
if bit_size == BitSize::Integer(IntegerBitSize::U1) {
assert!(
matches!(tag_from_bit_size(bit_size), AvmTypeTag::UINT8),
"If u1 doesn't map to u8 anymore, change this code!"
Expand Down Expand Up @@ -666,7 +666,7 @@ fn handle_const(
avm_instrs: &mut Vec<AvmInstruction>,
destination: &MemoryAddress,
value: &FieldElement,
bit_size: &u32,
bit_size: &BitSize,
) {
let tag = tag_from_bit_size(*bit_size);
let dest = destination.to_usize() as u32;
Expand Down Expand Up @@ -1079,8 +1079,8 @@ pub fn map_brillig_pcs_to_avm_pcs(brillig_bytecode: &[BrilligOpcode<FieldElement
pc_map[0] = 0; // first PC is always 0 as there are no instructions inserted by AVM at start
for i in 0..brillig_bytecode.len() - 1 {
let num_avm_instrs_for_this_brillig_instr = match &brillig_bytecode[i] {
BrilligOpcode::Const { bit_size: 254, .. } => 2,
BrilligOpcode::Cast { bit_size: 1, .. } => 3,
BrilligOpcode::Const { bit_size: BitSize::Field, .. } => 2,
BrilligOpcode::Cast { bit_size: BitSize::Integer(IntegerBitSize::U1), .. } => 3,
_ => 1,
};
// next Brillig pc will map to an AVM pc offset by the
Expand All @@ -1090,19 +1090,27 @@ pub fn map_brillig_pcs_to_avm_pcs(brillig_bytecode: &[BrilligOpcode<FieldElement
pc_map
}

fn is_integral_bit_size(bit_size: u32) -> bool {
matches!(bit_size, 1 | 8 | 16 | 32 | 64 | 128)
fn is_integral_bit_size(bit_size: IntegerBitSize) -> bool {
matches!(
bit_size,
IntegerBitSize::U1
| IntegerBitSize::U8
| IntegerBitSize::U16
| IntegerBitSize::U32
| IntegerBitSize::U64
| IntegerBitSize::U128
)
}

fn tag_from_bit_size(bit_size: u32) -> AvmTypeTag {
fn tag_from_bit_size(bit_size: BitSize) -> AvmTypeTag {
match bit_size {
1 => AvmTypeTag::UINT8, // temp workaround
8 => AvmTypeTag::UINT8,
16 => AvmTypeTag::UINT16,
32 => AvmTypeTag::UINT32,
64 => AvmTypeTag::UINT64,
128 => AvmTypeTag::UINT128,
254 => AvmTypeTag::FIELD,
BitSize::Integer(IntegerBitSize::U1) => AvmTypeTag::UINT8, // temp workaround
BitSize::Integer(IntegerBitSize::U8) => AvmTypeTag::UINT8,
BitSize::Integer(IntegerBitSize::U16) => AvmTypeTag::UINT16,
BitSize::Integer(IntegerBitSize::U32) => AvmTypeTag::UINT32,
BitSize::Integer(IntegerBitSize::U64) => AvmTypeTag::UINT64,
BitSize::Integer(IntegerBitSize::U128) => AvmTypeTag::UINT128,
BitSize::Field => AvmTypeTag::FIELD,
_ => panic!("The AVM doesn't support integer bit size {:?}", bit_size),
}
}
Loading

0 comments on commit 4a2011e

Please sign in to comment.