pub fn multiexp<G>(
        &mut self,
        bases: &[G],
        exps: &[<<G::Engine as ScalarEngine>::Fr as PrimeField>::Repr],
        n: usize,
        jack_windows_size: usize,
    ) -> GPUResult<<G as CurveAffine>::Projective>
    where
        G: CurveAffine,
    {
        if locks::PriorityLock::should_break(self.priority) {
            return Err(GPUError::GPUTaken);
        }

        let exp_bits = exp_size::<E>() * 8;
        // let window_size = calc_window_size(n as usize, exp_bits, self.core_count);
        let window_size = jack_windows_size;
        let num_windows = ((exp_bits as f64) / (window_size as f64)).ceil() as usize;
        let num_groups = calc_num_groups(self.core_count, num_windows);
        let bucket_len = 1 << window_size;

        info!("bucket_len is :{}",  bucket_len);

        // Each group will have `num_windows` threads and as there are `num_groups` groups, there will
        // be `num_groups` * `num_windows` threads in total.
        // Each thread will use `num_groups` * `num_windows` * `bucket_len` buckets.
        let size1 = std::mem::size_of::<G>();
        let size2 = std::mem::size_of::<<<G::Engine as ScalarEngine>::Fr as PrimeField>::Repr>();
        let size3 = std::mem::size_of::<<G as CurveAffine>::Projective>();
        let mem1 = size1 * n;
        let mem2 = size2 * n;
        let mem3 = size3 * 2 * self.core_count * bucket_len;
        let mem4 = size3 * 2 * self.core_count;
        info!("GABEDEBUG: <G> size:{}, <PrimeField> size:{}, <Projective> size:{}", size1, size2, size3);
        info!("GABEDEBUG: GPU mem need:{}byte, {}Mbyte", mem1 + mem2 + mem3 + mem4, (mem1 + mem2 + mem3 + mem4)/(1024*1024));

        let mut base_buffer = self.program.create_buffer::<G>(n)?;
        base_buffer.write_from(0, bases)?;
        let mut exp_buffer = self
            .program
            .create_buffer::<<<G::Engine as ScalarEngine>::Fr as PrimeField>::Repr>(n)?;
        exp_buffer.write_from(0, exps)?;

        let bucket_buffer = self
            .program
            .create_buffer::<<G as CurveAffine>::Projective>(2 * self.core_count * bucket_len)?;
        let result_buffer = self
            .program
            .create_buffer::<<G as CurveAffine>::Projective>(2 * self.core_count)?;

        // Make global work size divisible by `LOCAL_WORK_SIZE`
        let mut global_work_size = num_windows * num_groups;
        global_work_size +=
            (LOCAL_WORK_SIZE - (global_work_size % LOCAL_WORK_SIZE)) % LOCAL_WORK_SIZE;

        let kernel = self.program.create_kernel(
            if TypeId::of::<G>() == TypeId::of::<E::G1Affine>() {
                "G1_bellman_multiexp"
            } else if TypeId::of::<G>() == TypeId::of::<E::G2Affine>() {
                "G2_bellman_multiexp"
            } else {
                return Err(GPUError::Simple("Only E::G1 and E::G2 are supported!"));
            },
            global_work_size,
            None,
        );

        kernel
            .arg(&base_buffer)
            .arg(&bucket_buffer)
            .arg(&result_buffer)
            .arg(&exp_buffer)
            .arg(n as u32)
            .arg(num_groups as u32)
            .arg(num_windows as u32)
            .arg(window_size as u32)
            .run()?;

        let mut results = vec![<G as CurveAffine>::Projective::zero(); num_groups * num_windows];
        result_buffer.read_into(0, &mut results)?;

        // Using the algorithm below, we can calculate the final result by accumulating the results
        // of those `NUM_GROUPS` * `NUM_WINDOWS` threads.
        let mut acc = <G as CurveAffine>::Projective::zero();
        let mut bits = 0;
        for i in 0..num_windows {
            let w = std::cmp::min(window_size, exp_bits - bits);
            for _ in 0..w {
                acc.double();
            }
            for g in 0..num_groups {
                acc.add_assign(&results[g * num_windows + i]);
            }
            bits += w; // Process the next window
        }

        Ok(acc)
    }
// Modified by jackoelv for C2 20210330
Modified by jackoelv for C2 20210330
Modified by jackoelv for C2 20210330
pub fn multiexp<G>(
        &mut self,
        bases: &[G],
        exps: &[<<G::Engine as ScalarEngine>::Fr as PrimeField>::Repr],
        n: usize,
        jack_windows_size: usize,
    ) -> GPUResult<<G as CurveAffine>::Projective>
    where
        G: CurveAffine,
    {
        if locks::PriorityLock::should_break(self.priority) {
            return Err(GPUError::GPUTaken);
        }
        let exp_bits = exp_size::<E>() * 8;
        // let window_size = calc_window_size(n as usize, exp_bits, self.core_count);
        let window_size = jack_windows_size;
        let num_windows = ((exp_bits as f64) / (window_size as f64)).ceil() as usize;
        let num_groups = calc_num_groups(self.core_count, num_windows);
        let bucket_len = 1 << window_size;
        info!("bucket_len is :{}",  bucket_len);
        // Each group will have `num_windows` threads and as there are `num_groups` groups, there will
        // be `num_groups` * `num_windows` threads in total.
        // Each thread will use `num_groups` * `num_windows` * `bucket_len` buckets.
        let size1 = std::mem::size_of::<G>();
        let size2 = std::mem::size_of::<<<G::Engine as ScalarEngine>::Fr as PrimeField>::Repr>();
        let size3 = std::mem::size_of::<<G as CurveAffine>::Projective>();
        let mem1 = size1 * n;
        let mem2 = size2 * n;
        let mem3 = size3 * 2 * self.core_count * bucket_len;
        let mem4 = size3 * 2 * self.core_count;
        info!("GABEDEBUG: <G> size:{}, <PrimeField> size:{}, <Projective> size:{}", size1, size2, size3);
        info!("GABEDEBUG: GPU mem need:{}byte, {}Mbyte", mem1 + mem2 + mem3 + mem4, (mem1 + mem2 + mem3 + mem4)/(1024*1024));
        let mut base_buffer = self.program.create_buffer::<G>(n)?;
        base_buffer.write_from(0, bases)?;
        let mut exp_buffer = self
            .program
            .create_buffer::<<<G::Engine as ScalarEngine>::Fr as PrimeField>::Repr>(n)?;
        exp_buffer.write_from(0, exps)?;
        let bucket_buffer = self
            .program
            .create_buffer::<<G as CurveAffine>::Projective>(2 * self.core_count * bucket_len)?;
        let result_buffer = self
            .program
            .create_buffer::<<G as CurveAffine>::Projective>(2 * self.core_count)?;
        // Make global work size divisible by `LOCAL_WORK_SIZE`
        let mut global_work_size = num_windows * num_groups;
        global_work_size +=
            (LOCAL_WORK_SIZE - (global_work_size % LOCAL_WORK_SIZE)) % LOCAL_WORK_SIZE;
        let kernel = self.program.create_kernel(
            if TypeId::of::<G>() == TypeId::of::<E::G1Affine>() {
                "G1_bellman_multiexp"
            } else if TypeId::of::<G>() == TypeId::of::<E::G2Affine>() {
                "G2_bellman_multiexp"
            } else {
                return Err(GPUError::Simple("Only E::G1 and E::G2 are supported!"));
            },
            global_work_size,
            None,
        );
        kernel
            .arg(&base_buffer)
            .arg(&bucket_buffer)
            .arg(&result_buffer)
            .arg(&exp_buffer)
            .arg(n as u32)
            .arg(num_groups as u32)
            .arg(num_windows as u32)
            .arg(window_size as u32)
            .run()?;
        let mut results = vec![<G as CurveAffine>::Projective::zero(); num_groups * num_windows];
        result_buffer.read_into(0, &mut results)?;
        // Using the algorithm below, we can calculate the final result by accumulating the results
        // of those `NUM_GROUPS` * `NUM_WINDOWS` threads.
        let mut acc = <G as CurveAffine>::Projective::zero();
        let mut bits = 0;
        for i in 0..num_windows {
            let w = std::cmp::min(window_size, exp_bits - bits);
            for _ in 0..w {
                acc.double();
            }
            for g in 0..num_groups {
                acc.add_assign(&results[g * num_windows + i]);
            }
            bits += w; // Process the next window
        }
        Ok(acc)
    }
pub fn multiexp < G > ( & mut self , bases : & [ G ] , exps : & [ < < G :: Engine as ScalarEngine > :: Fr as PrimeField > :: Repr ] , n : usize , jack_windows_size : usize , ) -> GPUResult < < G as CurveAffine > :: Projective > where G : CurveAffine , { if locks :: PriorityLock :: should_break ( self . priority ) { return Err ( GPUError :: GPUTaken ) ; } let exp_bits = exp_size :: < E > ( ) * 8 ; // let window_size = calc_window_size(n as usize, exp_bits, self.core_count); let window_size = jack_windows_size ; let num_windows = ( ( exp_bits as f64 ) / ( window_size as f64 ) ) . ceil ( ) as usize ; let num_groups = calc_num_groups ( self . core_count , num_windows ) ; let bucket_len = 1 << window_size ; info ! ( " " bucket_len ) ; // Each group will have `num_windows` threads and as there are `num_groups` groups, there will // be `num_groups` * `num_windows` threads in total. // Each thread will use `num_groups` * `num_windows` * `bucket_len` buckets. let size1 = std :: mem :: size_of :: < G > ( ) ; let size2 = std :: mem :: size_of :: < < < G :: Engine as ScalarEngine > :: Fr as PrimeField > :: Repr > ( ) ; let size3 = std :: mem :: size_of :: < < G as CurveAffine > :: Projective > ( ) ; let mem1 = size1 * n ; let mem2 = size2 * n ; let mem3 = size3 * 2 * self . core_count * bucket_len ; let mem4 = size3 * 2 * self . core_count ; info ! ( " " size1 size2 size3 ) ; info ! ( " " mem1 mem2 mem3 mem4 ( mem1 mem2 mem3 mem4 ) ( 1024 1024 ) ) ; let mut base_buffer = self . program . create_buffer :: < G > ( n ) ? ; base_buffer . write_from ( 0 , bases ) ? ; let mut exp_buffer = self . program . create_buffer :: < < < G :: Engine as ScalarEngine > :: Fr as PrimeField > :: Repr > ( n ) ? ; exp_buffer . write_from ( 0 , exps ) ? ; let bucket_buffer = self . program . create_buffer :: < < G as CurveAffine > :: Projective > ( 2 * self . core_count * bucket_len ) ? ; let result_buffer = self . program . create_buffer :: < < G as CurveAffine > :: Projective > ( 2 * self . core_count ) ? ; // Make global work size divisible by `LOCAL_WORK_SIZE` let mut global_work_size = num_windows * num_groups ; global_work_size += ( LOCAL_WORK_SIZE - ( global_work_size % LOCAL_WORK_SIZE ) ) % LOCAL_WORK_SIZE ; let kernel = self . program . create_kernel ( if TypeId :: of :: < G > ( ) == TypeId :: of :: < E :: G1Affine > ( ) { " " } else if TypeId :: of :: < G > ( ) == TypeId :: of :: < E :: G2Affine > ( ) { " " } else { return Err ( GPUError :: Simple ( " " ) ) ; } , global_work_size , None , ) ; kernel . arg ( & base_buffer ) . arg ( & bucket_buffer ) . arg ( & result_buffer ) . arg ( & exp_buffer ) . arg ( n as u32 ) . arg ( num_groups as u32 ) . arg ( num_windows as u32 ) . arg ( window_size as u32 ) . run ( ) ? ; let mut results = vec ! [ G as CurveAffine Projective zero ( ) num_groups num_windows ] ; result_buffer . read_into ( 0 , & mut results ) ? ; // Using the algorithm below, we can calculate the final result by accumulating the results // of those `NUM_GROUPS` * `NUM_WINDOWS` threads. let mut acc = < G as CurveAffine > :: Projective :: zero ( ) ; let mut bits = 0 ; for i in 0 .. num_windows { let w = std :: cmp :: min ( window_size , exp_bits - bits ) ; for _ in 0 .. w { acc . double ( ) ; } for g in 0 .. num_groups { acc . add_assign ( & results [ g * num_windows + i ] ) ; } bits += w ; // Process the next window } Ok ( acc ) }
Modified by jackoelv for C2 20210330
Modified by jackoelv for C2 20210330
&mut self
bases
&[G]
exps
&[<<G::Engine as ScalarEngine>::Fr as PrimeField>::Repr]
n
usize
jack_windows_size
usize