Skip to content

Commit

Permalink
feat: optimize brillig execution of split_X_bits functions (#47)
Browse files Browse the repository at this point in the history
Co-authored-by: Maxim Vezenov <[email protected]>
  • Loading branch information
TomAFrench and vezenovm authored Nov 5, 2024
1 parent fbca8b8 commit 31ebc7c
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 55 deletions.
2 changes: 1 addition & 1 deletion src/runtime_bignum.nr
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::utils::map::map;
use crate::params::BigNumParams;
use crate::utils::map::map;

use crate::fns::{
constrained_ops::{
Expand Down
71 changes: 17 additions & 54 deletions src/utils/split_bits.nr
Original file line number Diff line number Diff line change
@@ -1,38 +1,18 @@
// Decomposes a single field into two 120 bit fields and a carry
pub unconstrained fn split_120_bits(x: Field) -> (Field, Field) {
let x_bytes: [u8; 32] = x.to_le_bytes();
global TWO_POW_56: u64 = 0x100000000000000;
global TWO_POW_60: u64 = 0x1000000000000000;
global TWO_POW_64: Field = 0x10000000000000000;

let mut low: Field = 0;
let mut high: Field = 0;
// Decomposes a single field into two 120 bit fields
pub unconstrained fn split_120_bits(mut x: Field) -> (Field, Field) {
// Here we're taking advantage of truncating 64 bit limbs from the input field
// and then subtracting them from the input such that the field division is equivalent to integer division.
let low_lower_64 = (x as u64) as Field;
x = (x - low_lower_64) / TWO_POW_64;
let low_upper_56 = ((x as u64) % TWO_POW_56) as Field;

let offsets: [Field; 17] = [
1,
0x100,
0x10000,
0x1000000,
0x100000000,
0x10000000000,
0x1000000000000,
0x100000000000000,
0x10000000000000000,
0x1000000000000000000,
0x100000000000000000000,
0x10000000000000000000000,
0x1000000000000000000000000,
0x100000000000000000000000000,
0x10000000000000000000000000000,
0x1000000000000000000000000000000,
0x100000000000000000000000000000000,
];
let low = low_lower_64 + TWO_POW_64 * low_upper_56;
let high = (x - low_upper_56) / TWO_POW_56 as Field;

for i in 0..15 {
low += (x_bytes[i] as Field) * offsets[i];
high += (x_bytes[i + 15] as Field) * offsets[i];
}
high += (x_bytes[30] as Field) * offsets[15];
high += (x_bytes[31] as Field) * offsets[16];
// TDOO: investigate why this is triggered in BigCurve crate? it shouldn't be?
// assert(x_bytes[31] == 0);
(low, high)
}

Expand All @@ -42,29 +22,12 @@ pub unconstrained fn split_120_bits(x: Field) -> (Field, Field) {
* @description Expects the input limb to be in the range [0, ..., 2^{120 - 1}]
**/
pub unconstrained fn split_60_bits(x: Field) -> (u64, u64) {
let x_bytes: [u8; 32] = x.to_le_bytes();

let mut low: u64 = 0;
let mut high: u64 = 0;
// Here we're taking advantage of truncating 64 bit limbs from the input field
// and then subtracting them from the input such that the field division is equivalent to integer division.
let x_lower_64 = (x as u64);
let low = x_lower_64 % TWO_POW_60;
let high = ((x - (low as Field)) / TWO_POW_60 as Field) as u64;

let offsets: [u64; 8] = [
1,
0x100,
0x10000,
0x1000000,
0x100000000,
0x10000000000,
0x1000000000000,
0x100000000000000,
];
for i in 0..8 {
low += (x_bytes[i] as u64) * offsets[i];
high += (x_bytes[i + 8] as u64) * offsets[i];
}
let t1 = low >> 60;
let mask = ((1 as u64) << 60 as u8) - 1;
low = low & mask;
high = (high << 4) | t1;
(low, high)
}

Expand Down

0 comments on commit 31ebc7c

Please sign in to comment.