Skip to content

Commit

Permalink
Merge branch 'main' into feat/diff-testing
Browse files Browse the repository at this point in the history
  • Loading branch information
zmalatrax authored Jun 10, 2024
2 parents 8ec3d81 + 4cd72f2 commit 5c6f51f
Show file tree
Hide file tree
Showing 13 changed files with 200 additions and 1 deletion.
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
CAIRO_0_PATH=cairo_programs/cairo_0
CAIRO_0_FILES:=$(wildcard $(CAIRO_0_PATH)/*.cairo)
CAIRO_0_FILES:=$(shell find $(CAIRO_0_PATH) -name '*.cairo')
COMPILED_CAIRO_0_FILES:=$(CAIRO_0_FILES:%.cairo=%.json)

compile: $(COMPILED_CAIRO_0_FILES)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
%builtins range_check96

func main{range_check96_ptr: felt*}() {
assert [range_check96_ptr] = 2 ** 96;
let range_check96_ptr = range_check96_ptr + 1;
return ();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
%builtins range_check

func main{range_check_ptr: felt*}() {
assert [range_check_ptr] = -1;
let range_check_ptr = range_check_ptr + 1;
return ();
}
1 change: 1 addition & 0 deletions cairo_programs/cairo_0/keccak_builtin.cairo
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
%builtins keccak

from starkware.cairo.common.cairo_builtins import KeccakBuiltin
from starkware.cairo.common.keccak_state import KeccakBuiltinState

Expand Down
1 change: 1 addition & 0 deletions cairo_programs/cairo_0/keccak_builtin_seed.cairo
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
%builtins keccak

from starkware.cairo.common.cairo_builtins import KeccakBuiltin
from starkware.cairo.common.keccak_state import KeccakBuiltinState

Expand Down
1 change: 1 addition & 0 deletions cairo_programs/cairo_0/poseidon_builtin.cairo
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
%builtins poseidon

from starkware.cairo.common.cairo_builtins import PoseidonBuiltin
from starkware.cairo.common.poseidon_state import PoseidonBuiltinState

Expand Down
7 changes: 7 additions & 0 deletions cairo_programs/cairo_0/range_check96_builtin.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
%builtins range_check96

func main{range_check96_ptr: felt*}() {
assert [range_check96_ptr] = 2 ** 96 - 1;
let range_check96_ptr = range_check96_ptr + 1;
return ();
}
7 changes: 7 additions & 0 deletions cairo_programs/cairo_0/range_check_builtin.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
%builtins range_check

func main{range_check_ptr: felt*}() {
assert [range_check_ptr] = 2 ** 128 - 1;
let range_check_ptr = range_check_ptr + 1;
return ();
}
3 changes: 3 additions & 0 deletions src/builtins/builtin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { pedersenHandler } from './pedersen';
import { poseidonHandler } from './poseidon';
import { keccakHandler } from './keccak';
import { outputHandler } from './output';
import { rangeCheckHandler } from './rangeCheck';

/** Proxy handler to abstract validation & deduction rules off the VM */
export type BuiltinHandler = ProxyHandler<Array<SegmentValue>>;
Expand All @@ -32,6 +33,8 @@ const BUILTIN_HANDLER: {
pedersen: pedersenHandler,
poseidon: poseidonHandler,
keccak: keccakHandler,
range_check: rangeCheckHandler(128n),
range_check96: rangeCheckHandler(96n),
};

/** Getter of the object `BUILTIN_HANDLER` */
Expand Down
64 changes: 64 additions & 0 deletions src/builtins/rangeCheck.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { describe, expect, test } from 'bun:test';

import { Relocatable } from 'primitives/relocatable';
import { Memory } from 'memory/memory';
import { rangeCheckHandler } from './rangeCheck';
import { Felt } from 'primitives/felt';

describe('range check', () => {
test.each([new Felt(0n), new Felt((1n << 128n) - 1n)])(
'should properly assert values inferior to 2 ** 128 in range check segment',
(value) => {
const memory = new Memory();
const { segmentId } = memory.addSegment(rangeCheckHandler(128n));

const offset = 0;
const address = new Relocatable(segmentId, offset);

expect(() => memory.assertEq(address, value)).not.toThrow();
expect(memory.segments[segmentId][offset]).toEqual(value);
}
);

test.each([new Felt(0n), new Felt((1n << 96n) - 1n)])(
'should properly assert values inferior to 2 ** 96 in range check96 segment',
(value) => {
const memory = new Memory();
const { segmentId } = memory.addSegment(rangeCheckHandler(96n));

const offset = 0;
const address = new Relocatable(segmentId, offset);

expect(() => memory.assertEq(address, value)).not.toThrow();
expect(memory.segments[segmentId][offset]).toEqual(value);
}
);

test.each([new Felt(1n << 128n), new Felt(-1n)])(
'should throw when trying to assert values equal or superior to 2 ** 128 in range check segment',
(value) => {
const memory = new Memory();
const { segmentId } = memory.addSegment(rangeCheckHandler(128n));

const offset = 0;
const address = new Relocatable(segmentId, offset);

expect(() => memory.assertEq(address, value)).toThrow();
expect(memory.segments[segmentId][offset]).toBeUndefined();
}
);

test.each([new Felt(1n << 96n), new Felt(-1n)])(
'should throw when trying to assert values equal or superior to 2 ** 96 in range check96 segment',
(value) => {
const memory = new Memory();
const { segmentId } = memory.addSegment(rangeCheckHandler(96n));

const offset = 0;
const address = new Relocatable(segmentId, offset);

expect(() => memory.assertEq(address, value)).toThrow();
expect(memory.segments[segmentId][offset]).toBeUndefined();
}
);
});
20 changes: 20 additions & 0 deletions src/builtins/rangeCheck.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { ExpectedOffset, RangeCheckOutOfBounds } from 'errors/builtins';
import { BuiltinHandler } from './builtin';
import { isFelt } from 'primitives/segmentValue';
import { ExpectedFelt } from 'errors/virtualMachine';

export const rangeCheckHandler = (boundExponent: bigint): BuiltinHandler => {
return {
set(target, prop, newValue): boolean {
if (isNaN(Number(prop))) throw new ExpectedOffset();

const offset = Number(prop);
if (!isFelt(newValue)) throw new ExpectedFelt();
if (newValue.toBigInt() >> boundExponent !== 0n)
throw new RangeCheckOutOfBounds();

target[offset] = newValue;
return true;
},
};
};
3 changes: 3 additions & 0 deletions src/errors/builtins.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ export class UndefinedValue extends BuiltinError {
}
}

/** Value is above Range Check upper bound */
export class RangeCheckOutOfBounds extends BuiltinError {}

/** ECDSA signature cannot be retrived from dictionnary at `offset` */
export class UndefinedECDSASignature extends BuiltinError {
constructor(readonly offset: number) {
Expand Down
78 changes: 78 additions & 0 deletions src/runners/cairoRunner.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Felt } from 'primitives/felt';
import { Relocatable } from 'primitives/relocatable';
import { parseProgram } from 'vm/program';
import { CairoRunner, RunOptions } from './cairoRunner';
import { RangeCheckOutOfBounds } from 'errors/builtins';

const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'cairo-vm-ts-'));

Expand Down Expand Up @@ -55,6 +56,26 @@ const BITWISE_OUTPUT_PROGRAM_STRING = fs.readFileSync(
'utf8'
);

const RANGE_CHECK_PROGRAM_STRING = fs.readFileSync(
'cairo_programs/cairo_0/range_check_builtin.json',
'utf8'
);

const RANGE_CHECK96_PROGRAM_STRING = fs.readFileSync(
'cairo_programs/cairo_0/range_check96_builtin.json',
'utf8'
);

const BAD_RANGE_CHECK_PROGRAM_STRING = fs.readFileSync(
'cairo_programs/cairo_0/bad_programs/bad_range_check_builtin.json',
'utf8'
);

const BAD_RANGE_CHECK96_PROGRAM_STRING = fs.readFileSync(
'cairo_programs/cairo_0/bad_programs/bad_range_check96_builtin.json',
'utf8'
);

const FIBONACCI_PROGRAM = parseProgram(FIBONACCI_PROGRAM_STRING);
const BITWISE_PROGRAM = parseProgram(BITWISE_PROGRAM_STRING);
const EC_OP_PROGRAM = parseProgram(EC_OP_PROGRAM_STRING);
Expand All @@ -64,6 +85,13 @@ const KECCAK_SEED_PROGRAM = parseProgram(KECCAK_SEED_PROGRAM_STRING);
const KECCAK_PROGRAM = parseProgram(KECCAK_PROGRAM_STRING);
const JMP_PROGRAM = parseProgram(JMP_PROGRAM_STRING);
const BITWISE_OUTPUT_PROGRAM = parseProgram(BITWISE_OUTPUT_PROGRAM_STRING);
const RANGE_CHECK_PROGRAM = parseProgram(RANGE_CHECK_PROGRAM_STRING);
const RANGE_CHECK96_PROGRAM = parseProgram(RANGE_CHECK96_PROGRAM_STRING);

const BAD_RANGE_CHECK_PROGRAM = parseProgram(BAD_RANGE_CHECK_PROGRAM_STRING);
const BAD_RANGE_CHECK96_PROGRAM = parseProgram(
BAD_RANGE_CHECK96_PROGRAM_STRING
);

describe('cairoRunner', () => {
describe('constructor', () => {
Expand Down Expand Up @@ -333,6 +361,56 @@ describe('cairoRunner', () => {
expect(output[0]).toEqual(new Felt(0n));
});
});

describe('range_check', () => {
test('should properly write 2 ** 128 - 1 to the range check segment', () => {
const runner = new CairoRunner(RANGE_CHECK_PROGRAM);
const config: RunOptions = {
relocate: true,
relocateOffset: 1,
};
runner.run(config);
const executionSize = runner.vm.memory.getSegmentSize(1);
const executionEnd = runner.executionBase.add(executionSize);
expect(runner.vm.memory.get(executionEnd.sub(2))).toEqual(
new Felt((1n << 128n) - 1n)
);
});

test('should crash the VM when trying to assert -1 to the range check segment', () => {
const runner = new CairoRunner(BAD_RANGE_CHECK_PROGRAM);
const config: RunOptions = {
relocate: true,
relocateOffset: 1,
};
expect(() => runner.run(config)).toThrow(new RangeCheckOutOfBounds());
});
});

describe('range_check96', () => {
test('should properly write 2 ** 96 - 1 to the range check segment', () => {
const runner = new CairoRunner(RANGE_CHECK96_PROGRAM);
const config: RunOptions = {
relocate: true,
relocateOffset: 1,
};
runner.run(config);
const executionSize = runner.vm.memory.getSegmentSize(1);
const executionEnd = runner.executionBase.add(executionSize);
expect(runner.vm.memory.get(executionEnd.sub(2))).toEqual(
new Felt((1n << 96n) - 1n)
);
});

test('should crash the VM when trying to assert 2 ** 96 to the range check segment', () => {
const runner = new CairoRunner(BAD_RANGE_CHECK96_PROGRAM);
const config: RunOptions = {
relocate: true,
relocateOffset: 1,
};
expect(() => runner.run(config)).toThrow(new RangeCheckOutOfBounds());
});
});
});

describe('diff testing', () => {
Expand Down

0 comments on commit 5c6f51f

Please sign in to comment.