-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add WideMul128 hint #126
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great overall :)
Put the file wideMul128.ts
in the math
folder pls
Feel free to join the telegram group of the Cairo VM ts: https://t.me/cairovmts
src/hints/hintSchema.ts
Outdated
@@ -33,6 +33,7 @@ const hint = z.union([ | |||
shouldContinueSquashLoopParser, | |||
shouldSkipSquashLoopParser, | |||
testLessThanParser, | |||
wideMul128, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The hint
object expects the zod object you've defined to parse the hint from the compilation artifacts: wideMul128Parser
src/hints/wideMul128.ts
Outdated
lhs: lhs, | ||
rhs: rhs, | ||
high: high, | ||
low: low |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As the property names are unchanged, you can directly use the variable:
lhs: lhs, | |
rhs: rhs, | |
high: high, | |
low: low | |
lhs, | |
rhs, | |
high, | |
low |
src/hints/wideMul128.ts
Outdated
low: CellRef | ||
): void => { | ||
try { | ||
const mask128 = (BigInt(1) << BigInt(128)) - BigInt(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use mask
rather than mask128
Use the short notation for Bigint when possible, it is more readable: 128n
instead of BigInt(128)
const mask128 = (BigInt(1) << BigInt(128)) - BigInt(1); | |
const mask = (1n << 128n) - 1n |
src/hints/wideMul128.ts
Outdated
try { | ||
const mask128 = (BigInt(1) << BigInt(128)) - BigInt(1); | ||
|
||
//Gets the operands' values |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to add comments, the code is self-explanatory here (same // Do multiplication) etc.
src/hints/wideMul128.ts
Outdated
import { resOperand, ResOperand } from 'hints/hintParamsSchema'; | ||
import { VirtualMachine } from 'vm/virtualMachine'; | ||
import { Felt } from 'primitives/felt'; | ||
export const wideMul128Parser = z. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add JSDoc
src/hints/wideMul128.ts
Outdated
low: low | ||
})); | ||
|
||
export const wideMul128 = ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add a well-formatted JSDoc, take example on the AllocFelt252Dict
one
src/hints/wideMul128.ts
Outdated
const highVal = prod >> BigInt(128); | ||
const highRef = vm.cellRefToRelocatable(high); | ||
vm.memory.assertEq(highRef, new Felt(highVal)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Directly create highVal
as a Felt
No need to declare a variable for the address (i.e. highRef
), directly call cellRefToRelocatable
in assertEq()
src/hints/wideMul128.ts
Outdated
} catch (error: any) { | ||
throw new Error(error.message); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't wrap the function in a try catch statement
@D240021 You're not signing your commits |
src/hints/math/wideMul128.test.ts
Outdated
}, | ||
rhs: { | ||
type: OpType.Immediate, | ||
value: new Felt(BigInt('0x2')), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can be simplified as new Felt(2n)
src/hints/math/wideMul128.test.ts
Outdated
|
||
test.each([ | ||
[new Felt(1n), new Felt(0n), new Felt(2n)], | ||
[new Felt(BigInt('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF')), new Felt(1n), new Felt(BigInt('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE'))], // max 128-bit value * 2 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hexadecimal is a bit hard to read with 128 bits, I'd rather compute it:
BigInt(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
--> (1n << 128n) - 1
BigInt(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE)
--> (1n << 128n) - 2
src/hints/math/wideMul128.test.ts
Outdated
const vm = new VirtualMachine(); | ||
vm.memory.addSegment(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The VirtualMachine instance comes with an empty memory: without any segment. Segments are 0-indexed
The AP register points to the segment 1, a.k.a the 2nd segment of the memory, you've got to call vm.memory.addSegment()
twice
src/hints/math/wideMul128.test.ts
Outdated
const hint = wideMul128Parser.parse(WIDE_MUL_128); | ||
const vm = new VirtualMachine(); | ||
vm.memory.addSegment(); | ||
vm.ap = vm.ap.add(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need to increment ap for this test
vm.ap = vm.ap.add(1); |
src/hints/math/wideMul128.ts
Outdated
export type WideMul128 = z.infer< | ||
typeof wideMul128Parser | ||
>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Export the type directly after wideMul128Parser
(before wideMul128()
)
src/hints/math/wideMul128.ts
Outdated
const highVal = prod >> BigInt(128); | ||
vm.memory.assertEq(vm.cellRefToRelocatable(high), new Felt(highVal)); | ||
|
||
const lowVal = prod & mask; | ||
const lowRef = vm.cellRefToRelocatable(low); | ||
vm.memory.assertEq(lowRef, new Felt(lowVal)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use 128n
instead of BigInt(128)
Directly instantiate highVal
and lowVal
as Felt
Group the computation and the memory assertion together: first compute highVal and lowVal
Then make assertEq
calls.
Inline highRef
and lowRef
in the assertEq
package-lock.json
Outdated
{ | ||
"name": "cairo-vm-ts", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this file
Also bun.lockb
shouldn't be modified
Hi @zmalatrax, I've been correcting what you told me. Also, I added the cairo file for the integration test, I'm not very sure about it. I would appreciate if you could review it and give me feedback. |
.trunk/trunk.yaml
Outdated
disabled: | ||
- prettier |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You shouldn't modify the Trunk configuration
let lhs: felt = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; | ||
let rhs: felt = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF; | ||
|
||
let product = lhs * rhs; | ||
|
||
let low = product & ((1 << 128) - 1); | ||
let high = product >> 128; | ||
|
||
return (); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're making a multiplication of two 128 bits, stored on two limbs low
and high
but you're not actually using the WideMul128 hint.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to find a Corelib function that makes use of the WideMul128
hint:
- Look at libfuncs defined in the cairo-lang-sierra-to-casm that uses the
WideMul128
hint in their implementation
By searching on the cairo-lang-sierra-to-casm crate of the Cairo compiler, you can see that it is used in the u256 divmod, u512 divmod by u256 and the u128 multiplication libfuncs
The easiest libfunc directly using this hint is the u128 multiplication: build_u128_guarantee_mul which creates the u128_guarantee_mul - Search the u128_guaranteed_mul function in the Cairo corelib
Now you need to write a Cairo program that uses the function u128_guarantee_mul()
, look at the function signature and do appropriately, something like this can be enough, as the U128 type operators have been overloaded:
fn main() {
let _ = 0x123456_u128 * 0xFEDCBA_u128;
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When you're not sure about your program using a particular hint, compile it and look at the JSON compilation artifacts, go to the hints
property and see if the wanted hint is part of it
src/hints/hintSchema.ts
Outdated
import { wideMul128, wideMul128Parser } from './math/wideMul128'; | ||
/** Zod object to parse any implemented hints */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing blank line
src/hints/math/wideMul128.ts
Outdated
* This function calculates the product of two 128-bit operands, splits the result into high and low 128-bit parts, | ||
* and stores them in the specified memory locations within the virtual machine. | ||
* | ||
* @param {VirtualMachine} vm - The virtual machine instance where the operation is executed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* @param {VirtualMachine} vm - The virtual machine instance where the operation is executed. | |
* @param {VirtualMachine} vm - The virtual machine instance. |
Closing as the implementation has been moved to #137 |
Hi, I've made some progress with the hint. I haven't tested it yet but I wanted to see if you could give me some feedback.
Changes made