/ algorithms / cuda / src / lib.rs
lib.rs
  1  // Copyright (c) 2025-2026 ACDC Network
  2  // This file is part of the alphavm library.
  3  //
  4  // Alpha Chain | Delta Chain Protocol
  5  // International Monetary Graphite.
  6  //
  7  // Derived from Aleo (https://aleo.org) and ProvableHQ (https://provable.com).
  8  // They built world-class ZK infrastructure. We installed the EASY button.
  9  // Their cryptography: elegant. Our modifications: bureaucracy-compatible.
 10  // Original brilliance: theirs. Robert's Rules: ours. Bugs: definitely ours.
 11  //
 12  // Original Aleo/ProvableHQ code subject to Apache 2.0 https://www.apache.org/licenses/LICENSE-2.0
 13  // All modifications and new work: CC0 1.0 Universal Public Domain Dedication.
 14  // No rights reserved. No permission required. No warranty. No refunds.
 15  //
 16  // https://creativecommons.org/publicdomain/zero/1.0/
 17  // SPDX-License-Identifier: CC0-1.0
 18  
 19  #[allow(unused_imports)]
 20  use blst::*;
 21  
 22  use core::ffi::c_void;
 23  sppark::cuda_error!();
 24  
 25  #[repr(C)]
 26  pub enum NTTInputOutputOrder {
 27      NN = 0,
 28      NR = 1,
 29      RN = 2,
 30      RR = 3,
 31  }
 32  
 33  #[repr(C)]
 34  pub enum NTTDirection {
 35      Forward = 0,
 36      Inverse = 1,
 37  }
 38  
 39  #[repr(C)]
 40  pub enum NTTType {
 41      Standard = 0,
 42      Coset = 1,
 43  }
 44  
 45  extern "C" {
 46      fn alphavm_ntt(
 47          inout: *mut core::ffi::c_void,
 48          lg_domain_size: u32,
 49          ntt_order: NTTInputOutputOrder,
 50          ntt_direction: NTTDirection,
 51          ntt_type: NTTType,
 52      ) -> cuda::Error;
 53  
 54      fn alphavm_polymul(
 55          out: *mut core::ffi::c_void,
 56          pcount: usize,
 57          polynomials: *const core::ffi::c_void,
 58          plens: *const core::ffi::c_void,
 59          ecount: usize,
 60          evaluations: *const core::ffi::c_void,
 61          elens: *const core::ffi::c_void,
 62          lg_domain_size: u32,
 63      ) -> cuda::Error;
 64  
 65      fn alphavm_msm(
 66          out: *mut c_void,
 67          points_with_infinity: *const c_void,
 68          npoints: usize,
 69          scalars: *const c_void,
 70          ffi_affine_sz: usize,
 71      ) -> cuda::Error;
 72  }
 73  
 74  ///////////////////////////////////////////////////////////////////////////////
 75  // Rust functions
 76  ///////////////////////////////////////////////////////////////////////////////
 77  
 78  /// Compute an in-place NTT on the input data.
 79  #[allow(non_snake_case)]
 80  pub fn NTT<T>(
 81      domain_size: usize,
 82      inout: &mut [T],
 83      ntt_order: NTTInputOutputOrder,
 84      ntt_direction: NTTDirection,
 85      ntt_type: NTTType,
 86  ) -> Result<(), cuda::Error> {
 87      if (domain_size & (domain_size - 1)) != 0 {
 88          panic!("domain_size is not power of 2");
 89      }
 90      let lg_domain_size = domain_size.trailing_zeros();
 91  
 92      let err = unsafe {
 93          alphavm_ntt(inout.as_mut_ptr() as *mut core::ffi::c_void, lg_domain_size, ntt_order, ntt_direction, ntt_type)
 94      };
 95  
 96      if err.code != 0 {
 97          return Err(err);
 98      }
 99      Ok(())
100  }
101  
102  /// Compute a polynomial multiply
103  pub fn polymul<T: std::clone::Clone>(
104      domain: usize,
105      polynomials: &Vec<Vec<T>>,
106      evaluations: &Vec<Vec<T>>,
107      zero: &T,
108  ) -> Result<Vec<T>, cuda::Error> {
109      let initial_domain_size = domain;
110      if (initial_domain_size & (initial_domain_size - 1)) != 0 {
111          panic!("domain_size is not power of 2");
112      }
113  
114      let lg_domain_size = initial_domain_size.trailing_zeros();
115  
116      let mut pptrs = Vec::new();
117      let mut plens = Vec::new();
118      for polynomial in polynomials {
119          pptrs.push(polynomial.as_ptr() as *const core::ffi::c_void);
120          plens.push(polynomial.len());
121      }
122      let mut eptrs = Vec::new();
123      let mut elens = Vec::new();
124      for evaluation in evaluations {
125          eptrs.push(evaluation.as_ptr() as *const core::ffi::c_void);
126          elens.push(evaluation.len());
127      }
128  
129      let mut out = Vec::new();
130      out.resize(initial_domain_size, zero.clone());
131      let err = unsafe {
132          alphavm_polymul(
133              out.as_mut_ptr() as *mut core::ffi::c_void,
134              pptrs.len(),
135              pptrs.as_ptr() as *const core::ffi::c_void,
136              plens.as_ptr() as *const core::ffi::c_void,
137              eptrs.len(),
138              eptrs.as_ptr() as *const core::ffi::c_void,
139              elens.as_ptr() as *const core::ffi::c_void,
140              lg_domain_size,
141          )
142      };
143  
144      if err.code != 0 {
145          return Err(err);
146      }
147      Ok(out)
148  }
149  
150  /// Compute a multi-scalar multiplication
151  pub fn msm<Affine, Projective, Scalar>(points: &[Affine], scalars: &[Scalar]) -> Result<Projective, cuda::Error> {
152      let npoints = scalars.len();
153      if npoints > points.len() {
154          panic!("length mismatch {} points < {} scalars", npoints, scalars.len())
155      }
156      #[allow(clippy::uninit_assumed_init)]
157      let mut ret: Projective = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
158      let err = unsafe {
159          alphavm_msm(
160              &mut ret as *mut _ as *mut c_void,
161              points as *const _ as *const c_void,
162              npoints,
163              scalars as *const _ as *const c_void,
164              std::mem::size_of::<Affine>(),
165          )
166      };
167      if err.code != 0 {
168          return Err(err);
169      }
170      Ok(ret)
171  }