RIPEMD160
fails if (length of calldata) % 64
is in the range of 55 to 63
#21
Labels
2 (Med Risk)
Assets not at direct risk, but function/availability of the protocol could be impacted or leak value
bug
Something isn't working
downgraded by judge
Judge downgraded the risk level of this issue
duplicate-120
edited-by-warden
🤖_primary
AI based primary recommendation
🤖_48_group
AI based duplicate group recommendation
satisfactory
satisfies C4 submission criteria; eligible for awards
sponsor confirmed
Sponsor agrees this is a problem and intends to fix it (OK to use w/ "disagree with severity")
sufficient quality report
This report is of sufficient quality
Lines of code
https://github.com/kkrt-labs/kakarot/blob/7411a5520e8a00be6f5243a50c160e66ad285563/src/kakarot/precompiles/ripemd160.cairo#L477
Vulnerability details
Impact
Consider the ripemd160.cairo::finish which is called while calculating RIPEMD160 ( interpreter.cairo::exec_opcode -> precompiles.cairo::exec_precompile -> ripemd160.cairo::run -> ripemd160.cairo::finish ):
The last third line
default_dict_finalize(start, x, 0);
will throw error as thestart
was initialized on third line for different memory segmentx
. And this line will be executed if(length of calldata) % 64
is in the range of 55 to 63.Proof of Concept
Consider the following code:
Save the above code in a file name
precompile.huff
( You can refer Installing Huff, if you don't have huff installed ).The above code will call the precompile
ripemd160
with calldata length of0x37
or55
bytes ( as 55 % 64 = 55 ).The above code can be converted to bytecode using the following command:
The output will be:
The runtime code is ( after removing the first few bytes which are responsible for deployment ):
Add the following cairo file named
test_kakarot_precompile.cairo
in kakarot/tests/src/kakarot folder:Also add the following python test file named
test_kakarot_precompile.py
in the same folder i.e kakarot/tests/src/kakarot folder:Now run the test using the following command:
The test will fail due
Can only subtract two relocatable values of the same segment (235 != 232)
error.Tools Used
Python test suite
Recommended Mitigation Steps
It can be fixed by updating the ripemd160.cairo::finish function as follows:
// puts bytes from data into X and pad out; appends length // and finally, compresses the last block(s) // note: length in bits == 8 * (dsize + 2^32 mswlen). // note: there are (dsize mod 64) bytes left in data. func finish{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}( buf: felt*, bufsize: felt, data: felt*, dsize: felt, mswlen: felt ) -> (res: felt*, rsize: felt) { alloc_locals; let (x) = default_dict_new(0); tempvar start = x; // put data into x. let (local len) = uint32_and(dsize, 63); absorb_data{dict_ptr=x}(data, len, 0); // append the bit m_n == 1. let (index_4, _) = unsigned_div_rem(dsize, 4); let (local index) = uint32_and(index_4, 15); let (old_val) = dict_read{dict_ptr=x}(index); let (local ba_3) = uint32_and(dsize, 3); let (factor) = uint32_add(8 * ba_3, 7); let (tmp) = pow2(factor); let (local val) = uint32_xor(old_val, tmp); dict_write{dict_ptr=x}(index, val); // length goes to next block. let (val) = uint32_mul(dsize, 8); let (pow2_29) = pow2(29); let (factor, _) = unsigned_div_rem(dsize, pow2_29); let len_8 = mswlen * 8; let (val_15) = uint32_or(factor, len_8); let next_block = is_nn_le(55, len); if (next_block == FALSE) { dict_write{dict_ptr=x}(14, val); dict_write{dict_ptr=x}(15, val_15); let (local arr_x: felt*) = alloc(); dict_to_array{dict_ptr=x}(arr_x, 16); default_dict_finalize(start, x, 0); let (res, rsize) = compress(buf, bufsize, arr_x, 16); return (res=res, rsize=rsize); } let (local arr_x: felt*) = alloc(); dict_to_array{dict_ptr=x}(arr_x, 16); let (buf, bufsize) = compress(buf, bufsize, arr_x, 16); // reset dict to all 0. let (x) = default_dict_new(0); + tempvar start = x; dict_write{dict_ptr=x}(14, val); dict_write{dict_ptr=x}(15, val_15); let (local arr_x: felt*) = alloc(); dict_to_array{dict_ptr=x}(arr_x, 16); default_dict_finalize(start, x, 0); let (res, rsize) = compress(buf, bufsize, arr_x, 16); return (res=res, rsize=rsize); }
Assessed type
Error
The text was updated successfully, but these errors were encountered: