Skip to content

Commit

Permalink
Feat: Add lessThanOrEqualAddress cairo hint (#132)
Browse files Browse the repository at this point in the history
* feat: add lessThanOrEqualAdress hint

* fix: fix typo in comment

* fix: fix typos, tests and methods documentation

* fix: fix tests

* style: run trunk

* doc: improve JSDocs

* refactor: rename cairo programs

* style: format
  • Loading branch information
renzobanegass authored Oct 7, 2024
1 parent 41f3337 commit be4c9d0
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 1 deletion.
4 changes: 4 additions & 0 deletions cairo_programs/cairo/hints/span_multi_pop_back.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
fn main() {
let mut span = array![1, 2, 3].span();
let _ = span.multi_pop_back::<2>();
}
4 changes: 4 additions & 0 deletions cairo_programs/cairo/hints/span_multi_pop_front.cairo
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
fn main() {
let mut span = array![1, 2, 3].span();
let _ = span.multi_pop_front::<2>();
}
8 changes: 8 additions & 0 deletions src/hints/hintHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ import {
} from './dict/shouldSkipSquashLoop';
import { TestLessThan, testLessThan } from './math/testLessThan';
import { DivMod, divMod } from './math/divMod';
import {
TestLessThanOrEqualAddress,
testLessThanOrEqualAddress,
} from './math/testLessThanOrEqualAddress';

/**
* Map hint names to the function executing their logic.
Expand Down Expand Up @@ -130,4 +134,8 @@ export const handlers: HintHandler = {
const h = hint as DivMod;
divMod(vm, h.lhs, h.rhs, h.quotient, h.remainder);
},
[HintName.TestLessThanOrEqualAddress]: (vm, hint) => {
const h = hint as TestLessThanOrEqualAddress;
testLessThanOrEqualAddress(vm, h.lhs, h.rhs, h.dst);
},
};
1 change: 1 addition & 0 deletions src/hints/hintName.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,5 @@ export enum HintName {
ShouldSkipSquashLoop = 'ShouldSkipSquashLoop',
TestLessThan = 'TestLessThan',
DivMod = 'DivMod',
TestLessThanOrEqualAddress = 'TestLessThanOrEqualAddress',
}
2 changes: 2 additions & 0 deletions src/hints/hintSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { shouldContinueSquashLoopParser } from './dict/shouldContinueSquashLoop'
import { shouldSkipSquashLoopParser } from './dict/shouldSkipSquashLoop';
import { testLessThanParser } from './math/testLessThan';
import { divModParser } from './math/divMod';
import { testLessThanOrEqualAddressParser } from './math/testLessThanOrEqualAddress';

/** Zod object to parse any implemented hints */
const hint = z.union([
Expand All @@ -35,6 +36,7 @@ const hint = z.union([
shouldSkipSquashLoopParser,
testLessThanParser,
divModParser,
testLessThanOrEqualAddressParser,
]);

/** Zod object to parse an array of hints grouped on a given PC */
Expand Down
2 changes: 1 addition & 1 deletion src/hints/math/testLessThan.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export const testLessThanParser = z
/**
* TestLessThan hint
*
* Store true at `dst` if value at `lhs` is stricty inferior to value at `rhs`.
* Store true at `dst` if value at `lhs` is strictly inferior to value at `rhs`.
* Store false otherwise
*/
export type TestLessThan = z.infer<typeof testLessThanParser>;
Expand Down
85 changes: 85 additions & 0 deletions src/hints/math/testLessThanOrEqualAddress.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import { describe, expect, test } from 'bun:test';

import { Felt } from 'primitives/felt';
import { Register } from 'vm/instruction';
import { VirtualMachine } from 'vm/virtualMachine';

import { OpType } from 'hints/hintParamsSchema';
import { HintName } from 'hints/hintName';
import { testLessThanOrEqualAddressParser } from './testLessThanOrEqualAddress';
import { Relocatable } from 'primitives/relocatable';

const TEST_LESS_THAN_OR_EQUAL_ADDRESS = {
TestLessThanOrEqualAddress: {
lhs: {
Deref: {
register: 'AP',
offset: 0,
},
},
rhs: {
Deref: {
register: 'AP',
offset: 1,
},
},
dst: {
register: 'AP',
offset: 2,
},
},
};

describe('TestLessThanOrEqualAddress', () => {
test('should properly parse TestLessThanOrEqualAddress hint', () => {
const hint = testLessThanOrEqualAddressParser.parse(
TEST_LESS_THAN_OR_EQUAL_ADDRESS
);

expect(hint).toEqual({
type: HintName.TestLessThanOrEqualAddress,
lhs: {
type: OpType.Deref,
cell: {
register: Register.Ap,
offset: 0,
},
},
rhs: {
type: OpType.Deref,
cell: {
register: Register.Ap,
offset: 1,
},
},
dst: {
register: Register.Ap,
offset: 2,
},
});
});

test.each([
[new Relocatable(1, 0), new Relocatable(1, 1), new Felt(1n)],
[new Relocatable(1, 1), new Relocatable(1, 0), new Felt(0n)],
[new Relocatable(1, 1), new Relocatable(1, 1), new Felt(1n)],
[new Relocatable(0, 0), new Relocatable(1, 0), new Felt(1n)],
])(
'should properly execute TestLessThanOrEqualAddress hint',
(lhs, rhs, expected) => {
const hint = testLessThanOrEqualAddressParser.parse(
TEST_LESS_THAN_OR_EQUAL_ADDRESS
);
const vm = new VirtualMachine();
vm.memory.addSegment();
vm.memory.addSegment();
vm.memory.assertEq(vm.ap, lhs);
vm.memory.assertEq(vm.ap.add(1), rhs);

vm.executeHint(hint);
expect(vm.memory.get(vm.cellRefToRelocatable(hint.dst))).toEqual(
expected
);
}
);
});
63 changes: 63 additions & 0 deletions src/hints/math/testLessThanOrEqualAddress.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { z } from 'zod';

import { Felt } from 'primitives/felt';
import { VirtualMachine } from 'vm/virtualMachine';

import { HintName } from 'hints/hintName';
import {
cellRef,
resOperand,
CellRef,
ResOperand,
} from 'hints/hintParamsSchema';

/** Zod object to parse TestLessThanOrEqualAddress hint */
export const testLessThanOrEqualAddressParser = z
.object({
TestLessThanOrEqualAddress: z.object({
lhs: resOperand,
rhs: resOperand,
dst: cellRef,
}),
})
.transform(({ TestLessThanOrEqualAddress: { lhs, rhs, dst } }) => ({
type: HintName.TestLessThanOrEqualAddress,
lhs,
rhs,
dst,
}));

/**
* TestLessThanOrEqualAddress hint
*
* Check whether the Relocatable value at `lhs` is inferior or equal to the value at `rhs`
*/
export type TestLessThanOrEqualAddress = z.infer<
typeof testLessThanOrEqualAddressParser
>;

/**
* TestLessThanOrEqualAddress hint
*
* Check whether the Relocatable value at `lhs` is inferior or equal to the value at `rhs`
*
* @param {VirtualMachine} vm - The virtual machine instance.
* @param {ResOperand} lhs - The left-hand side operand.
* @param {ResOperand} rhs - The right-hand side operand.
* @param {CellRef} dst - The address where the result of the comparison will be stored.
*/
export const testLessThanOrEqualAddress = (
vm: VirtualMachine,
lhs: ResOperand,
rhs: ResOperand,
dst: CellRef
) => {
const lhsValue = vm.getResOperandRelocatable(lhs);
const rhsValue = vm.getResOperandRelocatable(rhs);

const isLessThanOrEqual = lhsValue <= rhsValue;

const result = new Felt(isLessThanOrEqual ? 1n : 0n);

vm.memory.assertEq(vm.cellRefToRelocatable(dst), result);
};

0 comments on commit be4c9d0

Please sign in to comment.