Skip to content

Commit

Permalink
Test/metal/bigint (#26)
Browse files Browse the repository at this point in the history
* chore: remove auto-gen intermediate files

* chore: update .gitignore to specify path for constants.metal file

* refactor(tests): enhance bigint addition tests with random number generation for overflow detection

- Updated `test_bigint_add_unsafe` to generate random BigInt values that do not overflow during addition.
- Modified `test_bigint_add_overflow` to ensure it tests for overflow by generating random BigInt values that do overflow.
- Adjusted limb size from 13 to 16 in both tests for consistency and accuracy.
- Improved assertions to compare results directly with expected values derived from the generated inputs.

* test(bigint): add random number generation for underflow detection

* refactor(tests): align limb_size and num_limbs with mont_mul cios optimal limb size

* lint
  • Loading branch information
moven0831 authored Dec 24, 2024
1 parent b71011f commit 95b36ca
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 128 deletions.
2 changes: 1 addition & 1 deletion mopro-msm/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ src/msm/metal_msm/shader/**/*.ir
src/msm/metal_msm/shader/**/*.lib

# Metal shader constants file
src/msm/metal_msm/shader/**/constants.metal
src/msm/metal_msm/shader/constants.metal
Binary file not shown.
8 changes: 0 additions & 8 deletions mopro-msm/src/msm/metal_msm/shader/constants.metal

This file was deleted.

44 changes: 24 additions & 20 deletions mopro-msm/src/msm/metal_msm/tests/bigint/bigint_add_unsafe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,31 @@ use crate::msm::metal_msm::host::gpu::{
};
use crate::msm::metal_msm::host::shader::{compile_metal, write_constants};
use crate::msm::metal_msm::utils::limbs_conversion::{FromLimbs, ToLimbs};
use ark_ff::{BigInt, BigInteger};
use ark_ff::{BigInt, BigInteger, UniformRand};
use ark_std::rand;
use metal::*;

#[test]
#[serial_test::serial]
pub fn test_bigint_add_unsafe() {
let log_limb_size = 13;
let num_limbs = 20;

// Create two test numbers (equivalent to the previous hex values)
let a = BigInt::new([
0x0000000100000001,
0x0000000000000000,
0x1800a1101800a110,
0x0000000d0000000d,
]);
let b = a.clone(); // Same value as a for this test

let mut expected = a.clone();
let overflow = expected.add_with_carry(&b);

// We are testing add_unsafe, so the sum should not overflow
assert!(!overflow);
// adjusted by bn254 scalar bits and mont_mul cios optimal limb size
let log_limb_size = 16;
let num_limbs = 16;

// Create two test numbers that do not cause overflow
let mut rng = rand::thread_rng();
let (a, b, expected) = loop {
let a = BigInt::rand(&mut rng);
let b = BigInt::rand(&mut rng);

let mut expected = a.clone();
let overflow = expected.add_with_carry(&b);

// Break the loop if addition does not overflow
if !overflow {
break (a, b, expected);
}
};

let device = get_default_device();
let a_buf = create_buffer(&device, &a.to_limbs(num_limbs, log_limb_size));
Expand Down Expand Up @@ -87,7 +89,9 @@ pub fn test_bigint_add_unsafe() {
command_buffer.wait_until_completed();

let result_limbs: Vec<u32> = read_buffer(&result_buf, num_limbs);
let result = BigInt::from_limbs(&result_limbs, log_limb_size);
let expected_limbs = expected.to_limbs(num_limbs, log_limb_size);
assert_eq!(result_limbs, expected_limbs);

assert!(result.eq(&expected));
let result = BigInt::from_limbs(&result_limbs, log_limb_size);
assert_eq!(result, expected);
}
100 changes: 50 additions & 50 deletions mopro-msm/src/msm/metal_msm/tests/bigint/bigint_add_wide.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,33 +5,31 @@ use crate::msm::metal_msm::host::gpu::{
};
use crate::msm::metal_msm::host::shader::{compile_metal, write_constants};
use crate::msm::metal_msm::utils::limbs_conversion::{FromLimbs, ToLimbs};
use ark_ff::{BigInt, BigInteger};
use ark_ff::{BigInt, BigInteger, UniformRand};
use ark_std::rand;
use metal::*;

#[test]
#[serial_test::serial]
pub fn test_bigint_add() {
let log_limb_size = 13;
let num_limbs = 20;

// Create two large numbers that will overflow when added
let a = BigInt::new([
0xffffffffffffffff,
0xffffffffffffffff,
0xffffffffffffffff,
0xffffffffffffffff,
]);
let b = BigInt::new([
0x1000000000000000,
0x0000000000000000,
0x0000000000000000,
0x0000000000000000,
]);

let mut expected = a.clone();

let overflow = expected.add_with_carry(&b);
assert!(overflow);
pub fn test_bigint_add_no_overflow() {
// adjusted by bn254 scalar bits and mont_mul cios optimal limb size
let log_limb_size = 16;
let num_limbs = 16;

// Create two test numbers that do not cause overflow
let mut rng = rand::thread_rng();
let (a, b, expected) = loop {
let a = BigInt::rand(&mut rng);
let b = BigInt::rand(&mut rng);

let mut expected = a.clone();
let overflow = expected.add_with_carry(&b);

// Break the loop if addition does not overflow
if !overflow {
break (a, b, expected);
}
};

let device = get_default_device();
let a_buf = create_buffer(&device, &a.to_limbs(num_limbs, log_limb_size));
Expand Down Expand Up @@ -91,35 +89,35 @@ pub fn test_bigint_add() {
command_buffer.commit();
command_buffer.wait_until_completed();

let result_limbs: Vec<u32> = read_buffer(&result_buf, num_limbs + 1);
let result = BigInt::from_limbs(&result_limbs, log_limb_size);
let result_limbs: Vec<u32> = read_buffer(&result_buf, num_limbs);
let expected_limbs = expected.to_limbs(num_limbs, log_limb_size);
assert_eq!(result_limbs, expected_limbs);

assert!(result.eq(&expected));
let result = BigInt::from_limbs(&result_limbs, log_limb_size);
assert_eq!(result, expected);
}

#[test]
#[serial_test::serial]
pub fn test_bigint_add_no_overflow() {
let log_limb_size = 13;
let num_limbs = 20;

// Create two numbers that won't overflow when added
let a = BigInt::new([
0x0000000000000000,
0x0000000000000000,
0x0000000000000000,
0x0000000000000001,
]);
let b = BigInt::new([
0x0000000000000000,
0x0000000000000000,
0x0000000000000000,
0x0000000000000002,
]);

let mut expected = a.clone();
let overflow = expected.add_with_carry(&b);
assert!(!overflow);
pub fn test_bigint_add_overflow() {
// adjusted by bn254 scalar bits and mont_mul cios optimal limb size
let log_limb_size = 16;
let num_limbs = 16;

// Create two test numbers that cause overflow
let mut rng = rand::thread_rng();
let (a, b, expected) = loop {
let a = BigInt::rand(&mut rng);
let b = BigInt::rand(&mut rng);

let mut expected = a.clone();
let overflow = expected.add_with_carry(&b);

// Break the loop if addition overflow
if overflow {
break (a, b, expected);
}
};

let device = get_default_device();
let a_buf = create_buffer(&device, &a.to_limbs(num_limbs, log_limb_size));
Expand Down Expand Up @@ -179,8 +177,10 @@ pub fn test_bigint_add_no_overflow() {
command_buffer.commit();
command_buffer.wait_until_completed();

let result_limbs: Vec<u32> = read_buffer(&result_buf, num_limbs + 1);
let result = BigInt::from_limbs(&result_limbs, log_limb_size);
let result_limbs: Vec<u32> = read_buffer(&result_buf, num_limbs);
let expected_limbs = expected.to_limbs(num_limbs, log_limb_size);
assert_eq!(result_limbs, expected_limbs);

assert!(result.eq(&expected));
let result = BigInt::from_limbs(&result_limbs, log_limb_size);
assert_eq!(result, expected);
}
99 changes: 50 additions & 49 deletions mopro-msm/src/msm/metal_msm/tests/bigint/bigint_sub.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,41 @@
// adapted from: https://github.com/geometryxyz/msl-secp256k1

use core::borrow;

use crate::msm::metal_msm::host::gpu::{
create_buffer, create_empty_buffer, get_default_device, read_buffer,
};
use crate::msm::metal_msm::host::shader::{compile_metal, write_constants};
use crate::msm::metal_msm::utils::limbs_conversion::{FromLimbs, ToLimbs};
use ark_ff::{BigInt, BigInteger};
use ark_ff::{BigInt, BigInteger, UniformRand};
use ark_std::rand;
use metal::*;

#[test]
#[serial_test::serial]
pub fn test_bigint_sub() {
let log_limb_size = 13;
let num_limbs = 20;

let mut a = BigInt::new([0xf09f8fb3, 0xefb88fe2, 0x808df09f, 0x8c880010]);
let b = BigInt::new([0xf09f8fb3, 0xefb88fe2, 0x808df09f, 0x8c880001]);
pub fn test_bigint_sub_no_underflow() {
// adjusted by bn254 scalar bits and mont_mul cios optimal limb size
let log_limb_size = 16;
let num_limbs = 16;

// Create two test numbers that do not cause underflow
let mut rng = rand::thread_rng();
let (a, b, expected) = loop {
let a = BigInt::rand(&mut rng);
let b = BigInt::rand(&mut rng);

let mut expected = a.clone();
let underflow = expected.sub_with_borrow(&b);

// Break the loop if subtraction does not underflow
if !underflow {
break (a, b, expected);
}
};

let device = get_default_device();
let a_buf = create_buffer(&device, &a.to_limbs(num_limbs, log_limb_size));
let b_buf = create_buffer(&device, &b.to_limbs(num_limbs, log_limb_size));
let result_buf = create_empty_buffer(&device, num_limbs);

// perform a - b
let _borrow = a.sub_with_borrow(&b);
let expected_limbs = a.to_limbs(num_limbs, log_limb_size);

let command_queue = device.new_command_queue();
let command_buffer = command_queue.new_command_buffer();

Expand Down Expand Up @@ -81,46 +89,38 @@ pub fn test_bigint_sub() {
command_buffer.wait_until_completed();

let result_limbs: Vec<u32> = read_buffer(&result_buf, num_limbs);
let result = BigInt::from_limbs(&result_limbs, log_limb_size);
let expected_limbs = expected.to_limbs(num_limbs, log_limb_size);
assert_eq!(result_limbs, expected_limbs);

assert!(result_limbs.eq(&expected_limbs));
assert!(result.eq(&a));
let result = BigInt::from_limbs(&result_limbs, log_limb_size);
assert_eq!(result, expected);
}

#[test]
#[serial_test::serial]
fn test_bigint_sub_underflow() {
let device = Device::system_default().expect("no device found");
let num_limbs = 20;
let log_limb_size = 13;

// Create smaller number a and larger number b
let mut a = BigInt::from_u32(100);
let b = BigInt::from_u32(200);

let a_limbs = a.to_limbs(num_limbs, log_limb_size);
let b_limbs = b.to_limbs(num_limbs, log_limb_size);

let a_buf = device.new_buffer_with_data(
unsafe { std::mem::transmute(a_limbs.as_ptr()) },
(a_limbs.len() * std::mem::size_of::<u32>()) as u64,
MTLResourceOptions::StorageModeShared,
);

let b_buf = device.new_buffer_with_data(
unsafe { std::mem::transmute(b_limbs.as_ptr()) },
(b_limbs.len() * std::mem::size_of::<u32>()) as u64,
MTLResourceOptions::StorageModeShared,
);

let result_buf = device.new_buffer(
(num_limbs * std::mem::size_of::<u32>()) as u64,
MTLResourceOptions::StorageModeShared,
);
let num_limbs = 16;
let log_limb_size = 16;

// Create two test numbers that cause underflow
let mut rng = rand::thread_rng();
let (a, b, expected) = loop {
let a = BigInt::rand(&mut rng);
let b = BigInt::rand(&mut rng);

let mut expected = a.clone();
let underflow = expected.sub_with_borrow(&b);

// Break the loop if subtraction does not underflow
if underflow {
break (a, b, expected);
}
};

// Expected result is 2^256 - 100 (since we're doing a - b where b > a)
let _expected = a.sub_with_borrow(&b);
let expected_limbs = a.to_limbs(num_limbs, log_limb_size);
let device = get_default_device();
let a_buf = create_buffer(&device, &a.to_limbs(num_limbs, log_limb_size));
let b_buf = create_buffer(&device, &b.to_limbs(num_limbs, log_limb_size));
let result_buf = create_empty_buffer(&device, num_limbs);

let command_queue = device.new_command_queue();
let command_buffer = command_queue.new_command_buffer();
Expand Down Expand Up @@ -175,8 +175,9 @@ fn test_bigint_sub_underflow() {
command_buffer.wait_until_completed();

let result_limbs: Vec<u32> = read_buffer(&result_buf, num_limbs);
let result = BigInt::from_limbs(&result_limbs, log_limb_size);
let expected_limbs = expected.to_limbs(num_limbs, log_limb_size);
assert_eq!(result_limbs, expected_limbs);

// assert!(result_limbs.eq(&expected_limbs)); // TODO: leading limb is incorrect
assert!(result.eq(&a));
let result = BigInt::from_limbs(&result_limbs, log_limb_size);
assert_eq!(result, expected);
}

0 comments on commit 95b36ca

Please sign in to comment.