cairo-vm icon indicating copy to clipboard operation
cairo-vm copied to clipboard

The ModBuiltins runner is not able to manage empty add or mul

Open ClementWalter opened this issue 1 year ago • 4 comments

Describe the bug

This simple cairo code

from starkware.cairo.common.cairo_builtins import UInt384, ModBuiltin
from starkware.cairo.common.modulo import run_mod_p_circuit
from starkware.cairo.lang.compiler.lib.registers import get_fp_and_pc

func add{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}(
    x: UInt384*, y: UInt384*, p: UInt384*
) -> UInt384* {
    let (_, pc) = get_fp_and_pc();

    pc_label:
    let add_mod_offsets_ptr = pc + (add_offsets - pc_label);
    let mul_mod_offsets_ptr = pc + (mul_offsets - pc_label);

    assert [range_check96_ptr + 0] = x.d0;
    assert [range_check96_ptr + 1] = x.d1;
    assert [range_check96_ptr + 2] = x.d2;
    assert [range_check96_ptr + 3] = x.d3;
    assert [range_check96_ptr + 4] = y.d0;
    assert [range_check96_ptr + 5] = y.d1;
    assert [range_check96_ptr + 6] = y.d2;
    assert [range_check96_ptr + 7] = y.d3;

    run_mod_p_circuit(
        p=[p],
        values_ptr=cast(range_check96_ptr, UInt384*),
        add_mod_offsets_ptr=add_mod_offsets_ptr,
        add_mod_n=1,
        mul_mod_offsets_ptr=mul_mod_offsets_ptr,
        mul_mod_n=0,
    );

    let range_check96_ptr = range_check96_ptr + 12;

    return cast(range_check96_ptr - 4, UInt384*);

    add_offsets:
    dw 0;
    dw 4;
    dw 8;

    mul_offsets:
}

will raise

Exception: /Users/clementwalter/Documents/sayajin-labs/keth/.venv/lib/python3.10/site-packages/starkware/cairo/common/modulo.cairo:98:5: Error at pc=0:41:
E       Got an exception while executing a hint: Unknown memory cell at address 4:4
E           %{

Address 4:4 is actually mul_mod_ptr:values_ptr which is empty since no mul is to be performed.

Updating the above snippet to do only mul and no add will raise the same error but in segment 3:4:

func mul{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}(
    x: UInt384*, y: UInt384*, p: UInt384*
) -> UInt384* {
    let (_, pc) = get_fp_and_pc();

    pc_label:
    let add_mod_offsets_ptr = pc + (add_offsets - pc_label);
    let mul_mod_offsets_ptr = pc + (mul_offsets - pc_label);

    assert [range_check96_ptr + 0] = x.d0;
    assert [range_check96_ptr + 1] = x.d1;
    assert [range_check96_ptr + 2] = x.d2;
    assert [range_check96_ptr + 3] = x.d3;
    assert [range_check96_ptr + 4] = y.d0;
    assert [range_check96_ptr + 5] = y.d1;
    assert [range_check96_ptr + 6] = y.d2;
    assert [range_check96_ptr + 7] = y.d3;

    run_mod_p_circuit(
        p=[p],
        values_ptr=cast(range_check96_ptr, UInt384*),
        add_mod_offsets_ptr=add_mod_offsets_ptr,
        add_mod_n=0,
        mul_mod_offsets_ptr=mul_mod_offsets_ptr,
        mul_mod_n=1,
    );

    let range_check96_ptr = range_check96_ptr + 12;

    return cast(range_check96_ptr - 4, UInt384*);

    add_offsets:

    mul_offsets:
    dw 0;
    dw 4;
    dw 8;
}

Putting both add and mul works

func inv{range_check96_ptr: felt*, add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}(
    x: UInt384*, p: UInt384*
) -> UInt384* {
    let (_, pc) = get_fp_and_pc();

    pc_label:
    let add_mod_offsets_ptr = pc + (add_offsets - pc_label);
    let mul_mod_offsets_ptr = pc + (mul_offsets - pc_label);

    assert [range_check96_ptr + 0] = 1;
    assert [range_check96_ptr + 1] = 0;
    assert [range_check96_ptr + 2] = 0;
    assert [range_check96_ptr + 3] = 0;
    assert [range_check96_ptr + 4] = 0;
    assert [range_check96_ptr + 5] = 0;
    assert [range_check96_ptr + 6] = 0;
    assert [range_check96_ptr + 7] = 0;

    assert [range_check96_ptr + 8] = x.d0;
    assert [range_check96_ptr + 9] = x.d1;
    assert [range_check96_ptr + 10] = x.d2;
    assert [range_check96_ptr + 11] = x.d3;

    run_mod_p_circuit(
        p=[p],
        values_ptr=cast(range_check96_ptr, UInt384*),
        add_mod_offsets_ptr=add_mod_offsets_ptr,
        add_mod_n=1,
        mul_mod_offsets_ptr=mul_mod_offsets_ptr,
        mul_mod_n=1,
    );

    let range_check96_ptr = range_check96_ptr + 20;

    return cast(range_check96_ptr - 4, UInt384*);

    add_offsets:
    dw 4;
    dw 0;
    dw 12;

    mul_offsets:
    dw 16;
    dw 8;
    dw 12;
}

It's worth noticing that the test program at https://github.com/lambdaclass/cairo-vm/blob/df12864e7a1ae5fe4aceb51954b03017ad508fb3/cairo_programs/mod_builtin_feature/common/modulo.cairo#L93-L124

slightly differs from the run_mod_p_circuit from the core lib because the assert are not being a if, see https://github.com/starkware-libs/cairo-lang/blob/8276ac35830148a397e1143389f23253c8b80e93/src/starkware/cairo/common/modulo.cairo#L12-L47

ClementWalter avatar Feb 04 '25 10:02 ClementWalter

Problem is most probably located https://github.com/lambdaclass/cairo-vm/blob/main/vm/src/vm/runners/builtin_runner/modulo.rs#L521-L534 where one missed the none overriding https://github.com/starkware-libs/cairo-lang/blob/8276ac35830148a397e1143389f23253c8b80e93/src/starkware/cairo/lang/builtins/modulo/mod_builtin_runner.py#L349-L352

ClementWalter avatar Feb 04 '25 10:02 ClementWalter

Let me handle this issue!

a-zmuth avatar Feb 06 '25 22:02 a-zmuth

Hi, @ClementWalter! What's the status of this issue?

gabrielbosio avatar Oct 17 '25 20:10 gabrielbosio

idle from my side, I don't use the cairo vm anymore. If you have not merged anything regarding it, the discrepancy probably persists, but I don't know if anyone apart us faced the issue

ClementWalter avatar Oct 20 '25 15:10 ClementWalter