openvm-cuda-backend 2.0.0

OpenVM CUDA prover backend for the SWIRL proof system
#pragma once

#include "fp.h"
#include <cstdint>

constexpr uint32_t LOG_WARP_SIZE = 5;

/// Compute x^{2^power_log} by repeated squaring.
__device__ __forceinline__ Fp exp_power_of_2(Fp x, uint32_t power_log) {
    Fp res = x;
    while (power_log--) {
        res.sqr();
    }
    return res;
}

// Given x and 2^n, computes 1/2^n * (1 + x + ... + x^{2^n - 1}).
__device__ __forceinline__ Fp avg_gp(Fp x, uint32_t n) {
#ifdef CUDA_DEBUG
    assert(n && !(n & (n - 1)));
#endif
    Fp res = Fp::one();
    for (uint32_t i = 1; i < n; i <<= 1) {
        res *= Fp::one() + x;
        res = res.halve();
        x *= x;
    }
    return res;
}

/// Assuming `x` is a `len`-bit number, reverses its `len` bits.
__device__ __forceinline__ uint32_t rev_len(uint32_t x, uint32_t len) {
    return len ? (__brev(x) >> (32 - len)) : 0;
}

__device__ __forceinline__ uint32_t with_rev_bits(uint32_t x, uint32_t buf_size) { return x; }

/// Given an index and the buffer size (must be a power of two), turns on some last bits as provided.
/// Example: with_rev_bits(0b110, 32, 1, 0) == 0b10110.
template <typename... Bool>
__device__ __forceinline__ uint32_t
with_rev_bits(uint32_t x, uint32_t buf_size, bool first, Bool &&...others) {
    buf_size >>= 1;
    return with_rev_bits(x | (first * buf_size), buf_size, others...);
}

#define DISPATCH_BOOL(func, b1, ...) ((b1) ? func<true>(__VA_ARGS__) : func<false>(__VA_ARGS__))

// Dispatch helper for two bool template parameters
#define DISPATCH_BOOL_PAIR(func, b1, b2, ...)                                                      \
    ((b1) ? ((b2) ? func<true, true>(__VA_ARGS__) : func<true, false>(__VA_ARGS__))                \
          : ((b2) ? func<false, true>(__VA_ARGS__) : func<false, false>(__VA_ARGS__)))

// Generic dispatcher for <uint32_t N, bool B1, bool B2> template functions.
// Generates recursive template to dispatch runtime n (1..MAX_N) to compile-time N.
// Usage: DEFINE_DISPATCH_N_B1_B2(dispatcher_name, target_func, MAX_N)
// Then call: dispatcher_name(n, b1, b2, args...)
#define DEFINE_DISPATCH_N_B1_B2(name, func, max_n)                                                 \
    template <uint32_t N, typename... Args>                                                        \
    inline int name##_impl(uint32_t n, bool b1, bool b2, Args &&...args) {                         \
        if (n == N) {                                                                              \
            if (b1) {                                                                              \
                return b2 ? func<N, true, true>(std::forward<Args>(args)...)                       \
                          : func<N, true, false>(std::forward<Args>(args)...);                     \
            } else {                                                                               \
                return b2 ? func<N, false, true>(std::forward<Args>(args)...)                      \
                          : func<N, false, false>(std::forward<Args>(args)...);                    \
            }                                                                                      \
        } else if constexpr (N == 1) {                                                             \
            return cudaErrorInvalidValue;                                                          \
        } else {                                                                                   \
            return name##_impl<N - 1>(n, b1, b2, std::forward<Args>(args)...);                     \
        }                                                                                          \
    }                                                                                              \
    template <typename... Args> inline int name(uint32_t n, bool b1, bool b2, Args &&...args) {    \
        return name##_impl<max_n>(n, b1, b2, std::forward<Args>(args)...);                         \
    }