Skip to content

Commit 95b36ca

Browse files
authored
Test/metal/bigint (#26)
* 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
1 parent b71011f commit 95b36ca

File tree

6 files changed

+125
-128
lines changed

6 files changed

+125
-128
lines changed

mopro-msm/.gitignore

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,4 @@ src/msm/metal_msm/shader/**/*.ir
2424
src/msm/metal_msm/shader/**/*.lib
2525

2626
# Metal shader constants file
27-
src/msm/metal_msm/shader/**/constants.metal
27+
src/msm/metal_msm/shader/constants.metal
Binary file not shown.

mopro-msm/src/msm/metal_msm/shader/constants.metal

-8
This file was deleted.

mopro-msm/src/msm/metal_msm/tests/bigint/bigint_add_unsafe.rs

+24-20
Original file line numberDiff line numberDiff line change
@@ -5,29 +5,31 @@ use crate::msm::metal_msm::host::gpu::{
55
};
66
use crate::msm::metal_msm::host::shader::{compile_metal, write_constants};
77
use crate::msm::metal_msm::utils::limbs_conversion::{FromLimbs, ToLimbs};
8-
use ark_ff::{BigInt, BigInteger};
8+
use ark_ff::{BigInt, BigInteger, UniformRand};
9+
use ark_std::rand;
910
use metal::*;
1011

1112
#[test]
1213
#[serial_test::serial]
1314
pub fn test_bigint_add_unsafe() {
14-
let log_limb_size = 13;
15-
let num_limbs = 20;
16-
17-
// Create two test numbers (equivalent to the previous hex values)
18-
let a = BigInt::new([
19-
0x0000000100000001,
20-
0x0000000000000000,
21-
0x1800a1101800a110,
22-
0x0000000d0000000d,
23-
]);
24-
let b = a.clone(); // Same value as a for this test
25-
26-
let mut expected = a.clone();
27-
let overflow = expected.add_with_carry(&b);
28-
29-
// We are testing add_unsafe, so the sum should not overflow
30-
assert!(!overflow);
15+
// adjusted by bn254 scalar bits and mont_mul cios optimal limb size
16+
let log_limb_size = 16;
17+
let num_limbs = 16;
18+
19+
// Create two test numbers that do not cause overflow
20+
let mut rng = rand::thread_rng();
21+
let (a, b, expected) = loop {
22+
let a = BigInt::rand(&mut rng);
23+
let b = BigInt::rand(&mut rng);
24+
25+
let mut expected = a.clone();
26+
let overflow = expected.add_with_carry(&b);
27+
28+
// Break the loop if addition does not overflow
29+
if !overflow {
30+
break (a, b, expected);
31+
}
32+
};
3133

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

8991
let result_limbs: Vec<u32> = read_buffer(&result_buf, num_limbs);
90-
let result = BigInt::from_limbs(&result_limbs, log_limb_size);
92+
let expected_limbs = expected.to_limbs(num_limbs, log_limb_size);
93+
assert_eq!(result_limbs, expected_limbs);
9194

92-
assert!(result.eq(&expected));
95+
let result = BigInt::from_limbs(&result_limbs, log_limb_size);
96+
assert_eq!(result, expected);
9397
}

mopro-msm/src/msm/metal_msm/tests/bigint/bigint_add_wide.rs

+50-50
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,31 @@ use crate::msm::metal_msm::host::gpu::{
55
};
66
use crate::msm::metal_msm::host::shader::{compile_metal, write_constants};
77
use crate::msm::metal_msm::utils::limbs_conversion::{FromLimbs, ToLimbs};
8-
use ark_ff::{BigInt, BigInteger};
8+
use ark_ff::{BigInt, BigInteger, UniformRand};
9+
use ark_std::rand;
910
use metal::*;
1011

1112
#[test]
1213
#[serial_test::serial]
13-
pub fn test_bigint_add() {
14-
let log_limb_size = 13;
15-
let num_limbs = 20;
16-
17-
// Create two large numbers that will overflow when added
18-
let a = BigInt::new([
19-
0xffffffffffffffff,
20-
0xffffffffffffffff,
21-
0xffffffffffffffff,
22-
0xffffffffffffffff,
23-
]);
24-
let b = BigInt::new([
25-
0x1000000000000000,
26-
0x0000000000000000,
27-
0x0000000000000000,
28-
0x0000000000000000,
29-
]);
30-
31-
let mut expected = a.clone();
32-
33-
let overflow = expected.add_with_carry(&b);
34-
assert!(overflow);
14+
pub fn test_bigint_add_no_overflow() {
15+
// adjusted by bn254 scalar bits and mont_mul cios optimal limb size
16+
let log_limb_size = 16;
17+
let num_limbs = 16;
18+
19+
// Create two test numbers that do not cause overflow
20+
let mut rng = rand::thread_rng();
21+
let (a, b, expected) = loop {
22+
let a = BigInt::rand(&mut rng);
23+
let b = BigInt::rand(&mut rng);
24+
25+
let mut expected = a.clone();
26+
let overflow = expected.add_with_carry(&b);
27+
28+
// Break the loop if addition does not overflow
29+
if !overflow {
30+
break (a, b, expected);
31+
}
32+
};
3533

3634
let device = get_default_device();
3735
let a_buf = create_buffer(&device, &a.to_limbs(num_limbs, log_limb_size));
@@ -91,35 +89,35 @@ pub fn test_bigint_add() {
9189
command_buffer.commit();
9290
command_buffer.wait_until_completed();
9391

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

97-
assert!(result.eq(&expected));
96+
let result = BigInt::from_limbs(&result_limbs, log_limb_size);
97+
assert_eq!(result, expected);
9898
}
9999

100100
#[test]
101101
#[serial_test::serial]
102-
pub fn test_bigint_add_no_overflow() {
103-
let log_limb_size = 13;
104-
let num_limbs = 20;
105-
106-
// Create two numbers that won't overflow when added
107-
let a = BigInt::new([
108-
0x0000000000000000,
109-
0x0000000000000000,
110-
0x0000000000000000,
111-
0x0000000000000001,
112-
]);
113-
let b = BigInt::new([
114-
0x0000000000000000,
115-
0x0000000000000000,
116-
0x0000000000000000,
117-
0x0000000000000002,
118-
]);
119-
120-
let mut expected = a.clone();
121-
let overflow = expected.add_with_carry(&b);
122-
assert!(!overflow);
102+
pub fn test_bigint_add_overflow() {
103+
// adjusted by bn254 scalar bits and mont_mul cios optimal limb size
104+
let log_limb_size = 16;
105+
let num_limbs = 16;
106+
107+
// Create two test numbers that cause overflow
108+
let mut rng = rand::thread_rng();
109+
let (a, b, expected) = loop {
110+
let a = BigInt::rand(&mut rng);
111+
let b = BigInt::rand(&mut rng);
112+
113+
let mut expected = a.clone();
114+
let overflow = expected.add_with_carry(&b);
115+
116+
// Break the loop if addition overflow
117+
if overflow {
118+
break (a, b, expected);
119+
}
120+
};
123121

124122
let device = get_default_device();
125123
let a_buf = create_buffer(&device, &a.to_limbs(num_limbs, log_limb_size));
@@ -179,8 +177,10 @@ pub fn test_bigint_add_no_overflow() {
179177
command_buffer.commit();
180178
command_buffer.wait_until_completed();
181179

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

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

mopro-msm/src/msm/metal_msm/tests/bigint/bigint_sub.rs

+50-49
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,41 @@
11
// adapted from: https://github.com/geometryxyz/msl-secp256k1
22

3-
use core::borrow;
4-
53
use crate::msm::metal_msm::host::gpu::{
64
create_buffer, create_empty_buffer, get_default_device, read_buffer,
75
};
86
use crate::msm::metal_msm::host::shader::{compile_metal, write_constants};
97
use crate::msm::metal_msm::utils::limbs_conversion::{FromLimbs, ToLimbs};
10-
use ark_ff::{BigInt, BigInteger};
8+
use ark_ff::{BigInt, BigInteger, UniformRand};
9+
use ark_std::rand;
1110
use metal::*;
1211

1312
#[test]
1413
#[serial_test::serial]
15-
pub fn test_bigint_sub() {
16-
let log_limb_size = 13;
17-
let num_limbs = 20;
18-
19-
let mut a = BigInt::new([0xf09f8fb3, 0xefb88fe2, 0x808df09f, 0x8c880010]);
20-
let b = BigInt::new([0xf09f8fb3, 0xefb88fe2, 0x808df09f, 0x8c880001]);
14+
pub fn test_bigint_sub_no_underflow() {
15+
// adjusted by bn254 scalar bits and mont_mul cios optimal limb size
16+
let log_limb_size = 16;
17+
let num_limbs = 16;
18+
19+
// Create two test numbers that do not cause underflow
20+
let mut rng = rand::thread_rng();
21+
let (a, b, expected) = loop {
22+
let a = BigInt::rand(&mut rng);
23+
let b = BigInt::rand(&mut rng);
24+
25+
let mut expected = a.clone();
26+
let underflow = expected.sub_with_borrow(&b);
27+
28+
// Break the loop if subtraction does not underflow
29+
if !underflow {
30+
break (a, b, expected);
31+
}
32+
};
2133

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

27-
// perform a - b
28-
let _borrow = a.sub_with_borrow(&b);
29-
let expected_limbs = a.to_limbs(num_limbs, log_limb_size);
30-
3139
let command_queue = device.new_command_queue();
3240
let command_buffer = command_queue.new_command_buffer();
3341

@@ -81,46 +89,38 @@ pub fn test_bigint_sub() {
8189
command_buffer.wait_until_completed();
8290

8391
let result_limbs: Vec<u32> = read_buffer(&result_buf, num_limbs);
84-
let result = BigInt::from_limbs(&result_limbs, log_limb_size);
92+
let expected_limbs = expected.to_limbs(num_limbs, log_limb_size);
93+
assert_eq!(result_limbs, expected_limbs);
8594

86-
assert!(result_limbs.eq(&expected_limbs));
87-
assert!(result.eq(&a));
95+
let result = BigInt::from_limbs(&result_limbs, log_limb_size);
96+
assert_eq!(result, expected);
8897
}
8998

9099
#[test]
91100
#[serial_test::serial]
92101
fn test_bigint_sub_underflow() {
93-
let device = Device::system_default().expect("no device found");
94-
let num_limbs = 20;
95-
let log_limb_size = 13;
96-
97-
// Create smaller number a and larger number b
98-
let mut a = BigInt::from_u32(100);
99-
let b = BigInt::from_u32(200);
100-
101-
let a_limbs = a.to_limbs(num_limbs, log_limb_size);
102-
let b_limbs = b.to_limbs(num_limbs, log_limb_size);
103-
104-
let a_buf = device.new_buffer_with_data(
105-
unsafe { std::mem::transmute(a_limbs.as_ptr()) },
106-
(a_limbs.len() * std::mem::size_of::<u32>()) as u64,
107-
MTLResourceOptions::StorageModeShared,
108-
);
109-
110-
let b_buf = device.new_buffer_with_data(
111-
unsafe { std::mem::transmute(b_limbs.as_ptr()) },
112-
(b_limbs.len() * std::mem::size_of::<u32>()) as u64,
113-
MTLResourceOptions::StorageModeShared,
114-
);
115-
116-
let result_buf = device.new_buffer(
117-
(num_limbs * std::mem::size_of::<u32>()) as u64,
118-
MTLResourceOptions::StorageModeShared,
119-
);
102+
let num_limbs = 16;
103+
let log_limb_size = 16;
104+
105+
// Create two test numbers that cause underflow
106+
let mut rng = rand::thread_rng();
107+
let (a, b, expected) = loop {
108+
let a = BigInt::rand(&mut rng);
109+
let b = BigInt::rand(&mut rng);
110+
111+
let mut expected = a.clone();
112+
let underflow = expected.sub_with_borrow(&b);
113+
114+
// Break the loop if subtraction does not underflow
115+
if underflow {
116+
break (a, b, expected);
117+
}
118+
};
120119

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

125125
let command_queue = device.new_command_queue();
126126
let command_buffer = command_queue.new_command_buffer();
@@ -175,8 +175,9 @@ fn test_bigint_sub_underflow() {
175175
command_buffer.wait_until_completed();
176176

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

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

0 commit comments

Comments
 (0)