Skip to content

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

Open
@ClementWalter

Description

@ClementWalter

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

func run_mod_p_circuit{add_mod_ptr: ModBuiltin*, mul_mod_ptr: ModBuiltin*}(
p: UInt384,
values_ptr: UInt384*,
add_mod_offsets_ptr: felt*,
add_mod_n: felt,
mul_mod_offsets_ptr: felt*,
mul_mod_n: felt,
) {
assert add_mod_ptr[0] = ModBuiltin(
p=p, values_ptr=values_ptr, offsets_ptr=add_mod_offsets_ptr, n=add_mod_n
);
assert mul_mod_ptr[0] = ModBuiltin(
p=p, values_ptr=values_ptr, offsets_ptr=mul_mod_offsets_ptr, n=mul_mod_n
);
%{
from starkware.cairo.lang.builtins.modulo.mod_builtin_runner import ModBuiltinRunner
assert builtin_runners["add_mod_builtin"].instance_def.batch_size == 1
assert builtin_runners["mul_mod_builtin"].instance_def.batch_size == 1
ModBuiltinRunner.fill_memory(
memory=memory,
add_mod=(ids.add_mod_ptr.address_, builtin_runners["add_mod_builtin"], ids.add_mod_n),
mul_mod=(ids.mul_mod_ptr.address_, builtin_runners["mul_mod_builtin"], ids.mul_mod_n),
)
%}
let add_mod_ptr = &add_mod_ptr[add_mod_n];
let mul_mod_ptr = &mul_mod_ptr[mul_mod_n];
return ();
}

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions