Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: optimize brillig execution of split_X_bits functions #47

Merged
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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's we're taking advantage of truncating 64 bit limbs from the input field
// and then subtracting them from the input such the field division is equivalent to integer division.
TomAFrench marked this conversation as resolved.
Show resolved Hide resolved
let low_lower_64 = (x as u64) as Field;
TomAFrench marked this conversation as resolved.
Show resolved Hide resolved
x = (x - low_lower_64) / TWO_POW_64 as Field;
let low_upper_56 = ((x as u64) % TWO_POW_56) as Field;
TomAFrench marked this conversation as resolved.
Show resolved Hide resolved

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's we're taking advantage of truncating 64 bit limbs from the input field
// and then subtracting them from the input such the field division is equivalent to integer division.
let x_lower_64 = (x as u64);
TomAFrench marked this conversation as resolved.
Show resolved Hide resolved
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
Loading