当前位置: 首页 > 工具软件 > Cairo > 使用案例 >

分析cairo builtins

娄振
2023-12-01

基本知识

builtin是cairo的一种预先写好的常用函数,包括 range-checks, Pedersen hash, ECDSA等。这种一般都是连续占用一段内存。比如像z=pedersen_hash(x,y)就要占用x,y,z三块,需要如下代码

// Write the value of x to [p + 0].
x = [p];
// Write the value of y to [p + 1].
y = [p + 1];
// The builtin enforces that [p + 2] == hash([p + 0], [p + 1]).
z = [p + 2];

因为cairo中,所有内存都是只读的,因而都是要在当前指针后面添加builtin,然后更新指针,所以就需要每次调用传入指针和要用的builtin,指针根据builtin的size更新。

from starkware.cairo.common.cairo_builtins import HashBuiltin

func hash2(hash_ptr: HashBuiltin*, x, y) -> (
    hash_ptr: HashBuiltin*, z: felt
) {
    let hash = hash_ptr;
    // Invoke the hash function.
    hash.x = x;
    hash.y = y;
    // Return the updated pointer (increased by 3 memory cells)
    // and the result of the hash.
    return (hash_ptr=hash_ptr + HashBuiltin.SIZE, z=hash.result);
}

易犯错误

但是在implicit用的时候,更新后的指针可能会被扔掉,导致错误,所以需要明确更新,或者用alloc_locals

from starkware.cairo.common.cairo_builtins import HashBuiltin
from starkware.cairo.common.hash import hash2

func foo(n) {
    if (n == 0) {
        return ();
    }
    foo(n=n - 1);
    return ();
}

func bar{hash_ptr: HashBuiltin*}() {
    alloc_locals;
    hash2(1, 2);
    // You can skip the line below, and the compiler will add
    // it automatically, because of the alloc_locals keyword.
    local hash_ptr: HashBuiltin* = hash_ptr; // 明确更新
    foo(3);
    hash2(3, 4);
    return ();
}

另外就是if-else的时候,容易漏掉一个分支的更新,也会导致错误

if (x == 0) {
        hash2(1, 2);
        tempvar hash_ptr = hash_ptr;
    } else {
        tempvar hash_ptr = hash_ptr; //else 也有更新
    }

与layout的关系

cairo的layout,假如采用默认的plain layout,那么有可能不够某些builtin所要求的行数,这时候需要加入padding来凑够。

div实例

官方还给了个例子,用range check做除法,因为要保证x=q*y+r中的x,y都在[0, 2^64]

func div{range_check_ptr}(x, y) -> (q: felt, r: felt) {
    alloc_locals;
    local q;
    local r;
    %{ ids.q, ids.r = ids.x // ids.y, ids.x % ids.y %}

    // Check that 0 <= x < 2**64.
    [range_check_ptr] = x;
    assert [range_check_ptr + 1] = 2 ** 64 - 1 - x; //x的check,调用了range_check_ptr

    // Check that 0 <= y < 2**64.
    [range_check_ptr + 2] = y;
    assert [range_check_ptr + 3] = 2 ** 64 - 1 - y;

    // Check that 0 <= q < 2**64.
    [range_check_ptr + 4] = q;
    assert [range_check_ptr + 5] = 2 ** 64 - 1 - q;

    // Check that 0 <= r < y.
    [range_check_ptr + 6] = r;
    assert [range_check_ptr + 7] = y - 1 - r;

    // Verify that x = q * y + r.
    assert x = q * y + r;

    let range_check_ptr = range_check_ptr + 8;
    return (q=q, r=r);
}
 类似资料: