openvm-cuda-backend 2.0.0

OpenVM CUDA prover backend for the SWIRL proof system
/*
 * Source: https://github.com/scroll-tech/plonky3-gpu (private repo)
 * Status: BASED ON plonky3-gpu/gpu-backend/src/cuda/kernels/codec.h
 * Imported: 2025-01-25 by @gaxiom
 */

// A very simple custom codec for constraints wroten in the AIR/RAP frontend language.
#pragma once

#include <cstdint>

typedef struct {
    uint64_t low;
    uint64_t high;
} Rule;

typedef enum { OP_ADD, OP_SUB, OP_MUL, OP_NEG, OP_VAR, OP_INV } OperationType;

typedef enum {
    ENTRY_PREPROCESSED,
    ENTRY_MAIN,
    ENTRY_PUBLIC,
    ENTRY_CHALLENGE,
    SRC_INTERMEDIATE,
    SRC_CONSTANT,
    SRC_IS_FIRST,
    SRC_IS_LAST,
    SRC_IS_TRANSITION
} EntryType;

typedef struct {
    EntryType type;
    uint8_t part;
    uint8_t offset;
    uint32_t index;
} SourceInfo;

typedef struct {
    bool is_constraint;
    bool buffer_result;
    OperationType op;
    SourceInfo x;
    SourceInfo y;
    uint32_t z_index;
} DecodedRule;

// Lightweight header: only op, flags, and x (always needed).
// Use this for lazy decoding to reduce register pressure.
typedef struct {
    bool is_constraint;
    bool buffer_result;
    OperationType op;
    SourceInfo x;
} RuleHeader;

__host__ __device__ __forceinline__ SourceInfo decode_source(uint64_t encoded);
__host__ __device__ __forceinline__ DecodedRule decode_rule(Rule encoded);

// Lazy decoding functions - decode only what's needed
__host__ __device__ __forceinline__ RuleHeader decode_rule_header(Rule encoded);
__host__ __device__ __forceinline__ SourceInfo decode_y(Rule encoded);
__host__ __device__ __forceinline__ uint32_t decode_z_index(Rule encoded);

static const uint64_t ENTRY_SRC_MASK = 0xF;
static const uint64_t ENTRY_PART_SHIFT = 4;
static const uint64_t ENTRY_PART_MASK = 0xFF;
static const uint64_t ENTRY_OFFSET_SHIFT = 12;
static const uint64_t ENTRY_OFFSET_MASK = 0xF;
static const uint64_t ENTRY_INDEX_SHIFT = 16;
static const uint64_t ENTRY_INDEX_MASK = 0xFFFFFFFF;
static const uint64_t SOURCE_INTERMEDIATE_SHIFT = 4;
static const uint64_t SOURCE_INTERMEDIATE_MASK = 0xFFFFF;
static const uint64_t SOURCE_CONSTANT_SHIFT = 16;
static const uint64_t SOURCE_CONSTANT_MASK = 0xFFFFFFFF;
static const uint64_t LOW_48_BITS_MASK = 0xFFFFFFFFFFFF;
static const int Y_HIGH_SHIFT = 16;
static const uint64_t Y_HIGH_MASK = 0xFFFFFFFF;
static const int Z_LOW_SHIFT = 32;
static const uint64_t Z_LOW_MASK = 0xFFFFFF;
static const uint64_t OP_MASK = 0x3F;
static const int OP_SHIFT = 56;
static const uint64_t BUFFER_RESULT_MASK = 0x4000000000000000;
static const uint64_t IS_CONSTRAINT_MASK = 0x8000000000000000;

const uint64_t one = 1;
static_assert(LOW_48_BITS_MASK == (one << 48) - 1, "LOW_48_BITS_MASK must be (1 << 48) - 1");
static_assert(Y_HIGH_MASK == (one << 32) - 1, "Y_HIGH_MASK must be (1 << 32) - 1");
static_assert(Z_LOW_MASK == (one << 24) - 1, "Z_LOW_MASK must be (1 << 24) - 1");
static_assert(OP_MASK == (one << 6) - 1, "OP_MASK must be (1 << 6) - 1");
static_assert(BUFFER_RESULT_MASK == one << 62, "BUFFER_RESULT_MASK must be (1 << 62)");
static_assert(IS_CONSTRAINT_MASK == one << 63, "IS_CONSTRAINT_MASK must be (1 << 63)");

__host__ __device__ __forceinline__ SourceInfo decode_source(uint64_t encoded) {
    SourceInfo src;
    src.type = (EntryType)(encoded & ENTRY_SRC_MASK);
    src.part = (encoded >> ENTRY_PART_SHIFT) & ENTRY_PART_MASK;
    src.offset = (encoded >> ENTRY_OFFSET_SHIFT) & ENTRY_OFFSET_MASK;
    src.index = (encoded >> ENTRY_INDEX_SHIFT) & ENTRY_INDEX_MASK;

    if (src.type == SRC_INTERMEDIATE) {
        src.part = 0;
        src.offset = 0;
        src.index = (encoded >> SOURCE_INTERMEDIATE_SHIFT) & SOURCE_INTERMEDIATE_MASK;
    } else if (src.type == SRC_CONSTANT) {
        src.index = (encoded >> SOURCE_CONSTANT_SHIFT) & SOURCE_CONSTANT_MASK;
    }
    return src;
}

__host__ __device__ __forceinline__ DecodedRule decode_rule(Rule encoded) {
    DecodedRule rule;

    uint64_t x_encoded = (encoded.low & LOW_48_BITS_MASK);
    rule.x = decode_source(x_encoded);

    uint64_t y_encoded = ((encoded.low >> 48) | ((encoded.high & Y_HIGH_MASK) << Y_HIGH_SHIFT));
    rule.y = decode_source(y_encoded);

    uint64_t z_encoded = (encoded.high >> Z_LOW_SHIFT) & Z_LOW_MASK;
    rule.z_index = (z_encoded >> SOURCE_INTERMEDIATE_SHIFT) & SOURCE_INTERMEDIATE_MASK;

    rule.op = (OperationType)((encoded.high >> OP_SHIFT) & OP_MASK);

    rule.buffer_result = (encoded.high & BUFFER_RESULT_MASK) != 0;
    rule.is_constraint = (encoded.high & IS_CONSTRAINT_MASK) != 0;

    return rule;
}

// Decode only header (op, flags, x) - for lazy decoding pattern
__host__ __device__ __forceinline__ RuleHeader decode_rule_header(Rule encoded) {
    RuleHeader header;

    uint64_t x_encoded = (encoded.low & LOW_48_BITS_MASK);
    header.x = decode_source(x_encoded);

    header.op = (OperationType)((encoded.high >> OP_SHIFT) & OP_MASK);
    header.buffer_result = (encoded.high & BUFFER_RESULT_MASK) != 0;
    header.is_constraint = (encoded.high & IS_CONSTRAINT_MASK) != 0;

    return header;
}

// Decode y operand on demand (only needed for binary ops: ADD, SUB, MUL)
__host__ __device__ __forceinline__ SourceInfo decode_y(Rule encoded) {
    uint64_t y_encoded = ((encoded.low >> 48) | ((encoded.high & Y_HIGH_MASK) << Y_HIGH_SHIFT));
    return decode_source(y_encoded);
}

// Decode z_index on demand (only needed when buffer_result is true)
__host__ __device__ __forceinline__ uint32_t decode_z_index(Rule encoded) {
    uint64_t z_encoded = (encoded.high >> Z_LOW_SHIFT) & Z_LOW_MASK;
    return (z_encoded >> SOURCE_INTERMEDIATE_SHIFT) & SOURCE_INTERMEDIATE_MASK;
}