From 46821d379ddca7ec6064d0b49140789e97703bd6 Mon Sep 17 00:00:00 2001 From: Artem Yurchenko <44875844+murcake@users.noreply.github.com> Date: Thu, 8 Jun 2023 13:50:47 -0400 Subject: [PATCH] translate int conversions to Cairo 1 (#1084) Instead of generating Cairo functions, we use generic capabilities of Cairo 1 to write a single static function in warplib. Additionally we remove some usages of old functions, but not all of them, since they are tied to much into some subsystems, like calldata and storage. This will be finished in future work. --- .gitignore | 4 - .../calldata/calldataToStorage.ts | 5 +- .../storage/storageToCalldata.ts | 8 +- src/passes/cairoUtilImporter.ts | 22 ++- src/utils/errors.ts | 10 ++ src/utils/importFuncGenerator.ts | 1 + src/utils/importPaths.ts | 4 + src/warplib/generateWarplib.ts | 12 +- .../implementations/conversions/int.ts | 126 +++--------------- tests/compilation/compilation.test.ts | 1 + .../contracts/address/7/256Address.sol | 14 +- .../contracts/address/8/256Address.sol | 14 +- .../typeConversion/explicitIntConversion.sol | 16 +++ tests/compilation/passingContracts.ts | 1 + .../src/conversions/integer_conversions.cairo | 50 ++++--- warplib/src/integer.cairo | 83 ++++++++++++ warplib/src/lib.cairo | 1 + 17 files changed, 220 insertions(+), 152 deletions(-) create mode 100644 tests/compilation/contracts/typeConversion/explicitIntConversion.sol create mode 100644 warplib/src/integer.cairo diff --git a/.gitignore b/.gitignore index 0943d85c9..5198f6f85 100644 --- a/.gitignore +++ b/.gitignore @@ -210,9 +210,6 @@ warplib/src/maths/lt_signed.cairo # bitwise_or - handwritten warplib/src/maths/bitwise_not.cairo -# ---conversions--- -warplib/src/conversions/int_conversions.cairo - # ---external-input-input-checks--- warplib/src/external_input_check/external_input_check_ints.cairo # external_input_check_address.cairo - handwritten @@ -226,4 +223,3 @@ warplib/src/warp_memory/bytes.cairo tests/cli/starknet_open_zeppelin_accounts.json tests/cli/starknet_open_zeppelin_accounts.json.backup - diff --git a/src/cairoUtilFuncGen/calldata/calldataToStorage.ts b/src/cairoUtilFuncGen/calldata/calldataToStorage.ts index 1f4387e15..1740f7106 100644 --- a/src/cairoUtilFuncGen/calldata/calldataToStorage.ts +++ b/src/cairoUtilFuncGen/calldata/calldataToStorage.ts @@ -19,7 +19,6 @@ import { printTypeNode } from '../../utils/astPrinter'; import { CairoDynArray, CairoType, TypeConversionContext } from '../../utils/cairoTypeSystem'; import { NotSupportedYetError } from '../../utils/errors'; import { createCairoGeneratedFunction, createCallToFunction } from '../../utils/functionGeneration'; -import { WARP_UINT256 } from '../../utils/importPaths'; import { getElementType, safeGetNodeType } from '../../utils/nodeTypeProcessing'; import { mapRange, narrowBigIntSafe, typeNameFromTypeNode } from '../../utils/utils'; import { add, delegateBasedOnType, GeneratedFunctionInfo, StringIndexedFuncGen } from '../base'; @@ -179,7 +178,7 @@ export class CalldataToStorageGen extends StringIndexedFuncGen { } } - func ${funcName}(loc : felt, dyn_array_struct : ${structDef.name}) -> (loc : felt){ + func ${funcName}(loc : felt, dyn_array_struct : ${structDef.name}) -> (loc : felt){ alloc_locals; let (len_uint256) = warp_uint256(dyn_array_struct.len); ${lenName}.write(loc, len_uint256); @@ -191,7 +190,7 @@ export class CalldataToStorageGen extends StringIndexedFuncGen { return { name: funcName, code: code, - functionsCalled: [this.requireImport(...WARP_UINT256), dynArray, dynArrayLength, writeDef], + functionsCalled: [dynArray, dynArrayLength, writeDef], }; } diff --git a/src/cairoUtilFuncGen/storage/storageToCalldata.ts b/src/cairoUtilFuncGen/storage/storageToCalldata.ts index e6017bbc8..509a45fb9 100644 --- a/src/cairoUtilFuncGen/storage/storageToCalldata.ts +++ b/src/cairoUtilFuncGen/storage/storageToCalldata.ts @@ -18,7 +18,7 @@ import { printTypeNode } from '../../utils/astPrinter'; import { CairoDynArray, CairoType, TypeConversionContext } from '../../utils/cairoTypeSystem'; import { NotSupportedYetError } from '../../utils/errors'; import { createCairoGeneratedFunction, createCallToFunction } from '../../utils/functionGeneration'; -import { ALLOC, U128_FROM_FELT, WARP_UINT256 } from '../../utils/importPaths'; +import { ALLOC, U128_FROM_FELT } from '../../utils/importPaths'; import { getElementType, safeGetNodeType } from '../../utils/nodeTypeProcessing'; import { mapRange, narrowBigIntSafe, typeNameFromTypeNode } from '../../utils/utils'; import { add, delegateBasedOnType, GeneratedFunctionInfo, StringIndexedFuncGen } from '../base'; @@ -188,11 +188,7 @@ export class StorageToCalldataGen extends StringIndexedFuncGen { } `; - const importedFuncs = [ - this.requireImport(...WARP_UINT256), - this.requireImport(...U128_FROM_FELT), - this.requireImport(...ALLOC), - ]; + const importedFuncs = [this.requireImport(...U128_FROM_FELT), this.requireImport(...ALLOC)]; const funcInfo: GeneratedFunctionInfo = { name: funcName, diff --git a/src/passes/cairoUtilImporter.ts b/src/passes/cairoUtilImporter.ts index 4bc6476a3..838c320d8 100644 --- a/src/passes/cairoUtilImporter.ts +++ b/src/passes/cairoUtilImporter.ts @@ -1,6 +1,7 @@ import { AddressType, ElementaryTypeName, + FunctionCall, IntType, Literal, MemberAccess, @@ -11,8 +12,16 @@ import { } from 'solc-typed-ast'; import { AST } from '../ast/ast'; import { ASTMapper } from '../ast/mapper'; +import { requireNonNullish } from '../export'; import { createImport } from '../utils/importFuncGenerator'; -import { INTO, U256_FROM_FELTS, U128_FROM_FELT, CONTRACT_ADDRESS } from '../utils/importPaths'; +import { + INTO, + U256_FROM_FELTS, + U128_FROM_FELT, + CONTRACT_ADDRESS, + CUTOFF_DOWNCAST, + WARPLIB_INTEGER, +} from '../utils/importPaths'; import { safeGetNodeType } from '../utils/nodeTypeProcessing'; import { getContainingSourceUnit, primitiveTypeToCairo } from '../utils/utils'; @@ -41,6 +50,17 @@ export class CairoUtilImporter extends ASTMapper { } } + visitFunctionCall(node: FunctionCall, ast: AST): void { + // FIXME: remove when BitAnd is available for integer types in + // corelib + if (node.vFunctionName === CUTOFF_DOWNCAST[1]) { + const path = WARPLIB_INTEGER.slice(0, -1); + const name = requireNonNullish(WARPLIB_INTEGER.at(-1)); + createImport(path, name, this.dummySourceUnit ?? node, ast); + } + super.visitFunctionCall(node, ast); + } + visitLiteral(node: Literal, ast: AST): void { const type = safeGetNodeType(node, ast.inference); if (type instanceof IntType && type.nBits > 251) { diff --git a/src/utils/errors.ts b/src/utils/errors.ts index aabb89998..c91442e6c 100644 --- a/src/utils/errors.ts +++ b/src/utils/errors.ts @@ -82,3 +82,13 @@ export interface ExecSyncError { export function instanceOfExecSyncError(object: any): object is ExecSyncError { return 'stderr' in object; } + +export function requireNonNullish(x: T | null | undefined): T { + if (x === null) { + throw new Error('Unexpected null'); + } + if (x === undefined) { + throw new Error('Unexpected undefined'); + } + return x as T; +} diff --git a/src/utils/importFuncGenerator.ts b/src/utils/importFuncGenerator.ts index 2e6cf7ba3..9c20fc4f0 100644 --- a/src/utils/importFuncGenerator.ts +++ b/src/utils/importFuncGenerator.ts @@ -85,6 +85,7 @@ const FUNCTION_IMPORTS = [ Paths.U240_TO_FELT, Paths.U248_TO_FELT, Paths.U256_FROM_FELTS, + Paths.UPCAST, Paths.ARRAY, Paths.ARRAY_TRAIT, Paths.BOOL_INTO_FELT252, diff --git a/src/utils/importPaths.ts b/src/utils/importPaths.ts index a2e45d6c5..fd0f67711 100644 --- a/src/utils/importPaths.ts +++ b/src/utils/importPaths.ts @@ -298,3 +298,7 @@ export const WM_CREATE: [string[], string] = [ACCESSOR_TRAIT, 'warp_memory.creat export const WM_TO_FELT_ARRAY: [string[], string] = [['not set yet'], 'wm_to_felt_array']; export const SUPER: string[] = ['super']; + +export const SIGNED_UPCAST: [string[], string] = [INTEGER_CONVERSIONS, 'signed_upcast']; +export const UPCAST: [string[], string] = [['integer'], 'upcast']; +export const CUTOFF_DOWNCAST: [string[], string] = [INTEGER_CONVERSIONS, 'cutoff_downcast']; diff --git a/src/warplib/generateWarplib.ts b/src/warplib/generateWarplib.ts index 45a6fe8de..9d10b4fda 100644 --- a/src/warplib/generateWarplib.ts +++ b/src/warplib/generateWarplib.ts @@ -1,5 +1,4 @@ import { generateFile, PATH_TO_WARPLIB, WarplibFunctionInfo } from './utils'; -import { int_conversions } from './implementations/conversions/int'; import { add, add_unsafe, add_signed, add_signed_unsafe } from './implementations/maths/add'; import { div_signed, div_signed_unsafe } from './implementations/maths/div'; import { exp, exp_signed, exp_signed_unsafe, exp_unsafe } from './implementations/maths/exp'; @@ -66,7 +65,6 @@ const mathWarplibFunctions: WarplibFunctionInfo[] = [ // bitwise_or - handwritten bitwise_not(), ]; -const conversionWarplibFunctions: WarplibFunctionInfo[] = [int_conversions()]; const inputCheckWarplibFunctions: WarplibFunctionInfo[] = [ external_input_check_ints(), // external_input_check_address - handwritten @@ -74,16 +72,16 @@ const inputCheckWarplibFunctions: WarplibFunctionInfo[] = [ const warplibTypes: WarplibFunctionInfo[] = [fixed_bytes_types()]; const warp_memory: WarplibFunctionInfo[] = [warp_memory_fixed_bytes()]; -generateWarplibFor('maths', mathWarplibFunctions, true); -generateWarplibFor('conversions', conversionWarplibFunctions, true); -generateWarplibFor('external_input_check', inputCheckWarplibFunctions, true); -generateWarplibFor('types', warplibTypes, true); +generateWarplibFor('maths', mathWarplibFunctions); +generateWarplibFor('conversions', []); +generateWarplibFor('external_input_check', inputCheckWarplibFunctions); +generateWarplibFor('types', warplibTypes); generateWarplibFor('warp_memory', warp_memory, false); function generateWarplibFor( folderName: string, functions: WarplibFunctionInfo[], - writeExportFile: boolean, + writeExportFile = true, ) { functions.forEach((warpFunc: WarplibFunctionInfo) => generateFile(warpFunc, folderName)); if (writeExportFile) { diff --git a/src/warplib/implementations/conversions/int.ts b/src/warplib/implementations/conversions/int.ts index 6ecd0be13..fb9fb2745 100644 --- a/src/warplib/implementations/conversions/int.ts +++ b/src/warplib/implementations/conversions/int.ts @@ -1,103 +1,12 @@ import assert from 'assert'; import { FunctionCall, generalizeType, IntType } from 'solc-typed-ast'; import { AST } from '../../../ast/ast'; +import { createCallToFunction, createNumberTypeName, requireNonNullish } from '../../../export'; import { printNode, printTypeNode } from '../../../utils/astPrinter'; +import { CUTOFF_DOWNCAST, SIGNED_UPCAST, UPCAST } from '../../../utils/importPaths'; import { safeGetNodeType } from '../../../utils/nodeTypeProcessing'; -import { - bound, - forAllWidths, - IntFunction, - mask, - msb, - uint256, - WarplibFunctionInfo, -} from '../../utils'; -export function int_conversions(): WarplibFunctionInfo { - return { - fileName: 'int_conversions', - imports: [ - 'from starkware.cairo.common.bitwise import bitwise_and', - 'from starkware.cairo.common.cairo_builtins import BitwiseBuiltin', - 'from starkware.cairo.common.math import split_felt', - 'from starkware.cairo.common.uint256 import Uint256, uint256_add', - ], - functions: [ - ...forAllWidths((from) => { - const x = forAllWidths((to) => { - if (from < to) { - if (to === 256) { - return [ - `func warp_int${from}_to_int256{range_check_ptr, bitwise_ptr: BitwiseBuiltin*}(op : felt) -> (res : Uint256){`, - ` let (msb) = bitwise_and(op, ${msb(from)});`, - ` let (high, low) = split_felt(op);`, - ` let naiveExtension = Uint256(low, high);`, - ` if (msb == 0){`, - ` return (naiveExtension,);`, - ` }else{`, - ` let (res, _) = uint256_add(naiveExtension, ${uint256( - sign_extend_value(from, to), - )});`, - ` return (res,);`, - ` }`, - '}', - ]; - } else { - return [ - `func warp_int${from}_to_int${to}{bitwise_ptr: BitwiseBuiltin*}(op : felt) -> (res : felt){`, - ` let (msb) = bitwise_and(op, ${msb(from)});`, - ` if (msb == 0){`, - ` return (op,);`, - ` }else{`, - ` return (op + 0x${sign_extend_value(from, to).toString(16)},);`, - ` }`, - '}', - ]; - } - } else if (from === to) { - return []; - } else { - if (from === 256) { - if (to > 128) { - return [ - `func warp_int${from}_to_int${to}{bitwise_ptr: BitwiseBuiltin*}(op : Uint256) -> (res : felt){`, - ` let (high) = bitwise_and(op.high,${mask(to - 128)});`, - ` return (op.low + ${bound(128)} * high,);`, - `}`, - ]; - } else { - return [ - `func warp_int${from}_to_int${to}{bitwise_ptr: BitwiseBuiltin*}(op : Uint256) -> (res : felt){`, - ` let (res) = bitwise_and(op.low, ${mask(to)});`, - ` return (res,);`, - `}`, - ]; - } - } else { - return [ - `func warp_int${from}_to_int${to}{bitwise_ptr : BitwiseBuiltin*}(op : felt) -> (res : felt){`, - ` let (res) = bitwise_and(op, ${mask(to)});`, - ` return (res,);`, - `}`, - ]; - } - } - }); - return x.map((f) => f.join('\n')).join('\n'); - }), - [ - 'func warp_uint256{range_check_ptr}(op : felt) -> (res : Uint256){', - ' let split = split_felt(op);', - ' return (Uint256(low=split.low, high=split.high),);', - '}', - ].join('\n'), - ], - }; -} - -function sign_extend_value(from: number, to: number): bigint { - return 2n ** BigInt(to) - 2n ** BigInt(from); -} +const cairoWidths = [8, 16, 32, 64, 128, 256]; export function functionaliseIntConversion(conversion: FunctionCall, ast: AST): void { const arg = conversion.vArguments[0]; @@ -116,19 +25,24 @@ export function functionaliseIntConversion(conversion: FunctionCall, ast: AST): )}`, ); - if (fromType.nBits < 256 && toType.nBits === 256 && !fromType.signed && !toType.signed) { - IntFunction(conversion, conversion.vArguments[0], 'uint', 'int_conversions', ast); - return; - } else if ( - fromType.nBits === toType.nBits || - (fromType.nBits < toType.nBits && !fromType.signed && !toType.signed) - ) { - arg.typeString = conversion.typeString; - ast.replaceNode(conversion, arg); + const fromCairoWidth = requireNonNullish(cairoWidths.find((x) => x >= fromType.nBits)); + const toCairoWidth = requireNonNullish(cairoWidths.find((x) => x >= toType.nBits)); + + if (fromCairoWidth === toCairoWidth) { return; + } + let functionPath: [string[], string]; + if (fromCairoWidth < toCairoWidth) { + functionPath = fromType.signed ? SIGNED_UPCAST : UPCAST; } else { - const name = `${fromType.pp().startsWith('u') ? fromType.pp().slice(1) : fromType.pp()}_to_int`; - IntFunction(conversion, conversion.vArguments[0], name, 'int_conversions', ast); - return; + functionPath = CUTOFF_DOWNCAST; } + const functionDef = ast.registerImport( + conversion, + ...functionPath, + [['from', createNumberTypeName(fromType.nBits, fromType.signed, ast)]], + [['to', createNumberTypeName(toType.nBits, toType.signed, ast)]], + ); + const functionCall = createCallToFunction(functionDef, conversion.vArguments, ast); + ast.replaceNode(conversion, functionCall); } diff --git a/tests/compilation/compilation.test.ts b/tests/compilation/compilation.test.ts index 863780083..63079e962 100644 --- a/tests/compilation/compilation.test.ts +++ b/tests/compilation/compilation.test.ts @@ -165,6 +165,7 @@ const expectedResults = new Map( ['tryCatch.sol', 'WillNotSupport'], ['tupleAssignment7.sol', 'Success'], ['tupleAssignment8.sol', 'SolCompileFailed'], + ['typeConversion/explicitIntConversion.sol', 'Success'], ['typeConversion/explicitTypeConversion.sol', 'Success'], ['typeConversion/implicitReturnConversion.sol', 'Success'], ['typeConversion/implicitTypeConv.sol', 'Success'], diff --git a/tests/compilation/contracts/address/7/256Address.sol b/tests/compilation/contracts/address/7/256Address.sol index 9f0529a18..9be5a3d5c 100644 --- a/tests/compilation/contracts/address/7/256Address.sol +++ b/tests/compilation/contracts/address/7/256Address.sol @@ -2,12 +2,16 @@ pragma solidity ^0.7.6; contract WARP { - function test160(uint160 me) public view { - address x = address(uint256(me)); + function test160(uint160 n1, bytes20 n2) public view { + address a1 = address(uint256(n1)); + address a2 = address(bytes32(n2)); } - function test256(uint256 me) public view { - address x = address(me); - uint256 y = uint256(x); + function test256(uint256 n1, bytes32 n2) public view { + address a1 = address(n1); + address a2 = address(n2); + + uint256 m1 = uint256(a1); + bytes32 m2 = bytes32(a2); } } diff --git a/tests/compilation/contracts/address/8/256Address.sol b/tests/compilation/contracts/address/8/256Address.sol index 5922fc3fa..19e2c24b3 100644 --- a/tests/compilation/contracts/address/8/256Address.sol +++ b/tests/compilation/contracts/address/8/256Address.sol @@ -2,12 +2,16 @@ pragma solidity ^0.8.6; contract WARP { - function test160(uint160 me) public view { - address x = address(uint256(me)); + function test160(uint160 n1, bytes20 n2) public view { + address a1 = address(uint256(n1)); + address a2 = address(bytes32(n2)); } - function test256(uint256 me) public view { - address x = address(me); - uint256 y = uint256(x); + function test256(uint256 n1, bytes32 n2) public view { + address a1 = address(n1); + address a2 = address(n2); + + uint256 m1 = uint256(a1); + bytes32 m2 = bytes32(a2); } } diff --git a/tests/compilation/contracts/typeConversion/explicitIntConversion.sol b/tests/compilation/contracts/typeConversion/explicitIntConversion.sol new file mode 100644 index 000000000..41e7721d3 --- /dev/null +++ b/tests/compilation/contracts/typeConversion/explicitIntConversion.sol @@ -0,0 +1,16 @@ +pragma solidity ^0.7.6; + +contract WARP { + + function conversions() public pure { + uint8 x1 = 1; + uint16 x2 = uint16(x1); + int32 x3 = int32(x2); + int64 x4 = int64(x3); + uint128 x5 = uint128(x4); + uint64 x6 = uint64(x5); + int32 x7 = int32(x6); + int16 x8 = int16(x7); + uint8 x9 = uint8(x8); + } +} diff --git a/tests/compilation/passingContracts.ts b/tests/compilation/passingContracts.ts index ae3dfc197..8b373c8d1 100644 --- a/tests/compilation/passingContracts.ts +++ b/tests/compilation/passingContracts.ts @@ -161,6 +161,7 @@ export const passingContracts = [ // 'tests/compilation/contracts/tryCatch.sol', // 'tests/compilation/contracts/tupleAssignment7.sol', // 'tests/compilation/contracts/tupleAssignment8.sol', + 'tests/compilation/contracts/typeConversion/explicitIntConversion.sol', 'tests/compilation/contracts/typeConversion/explicitTypeConversion.sol', // 'tests/compilation/contracts/typeConversion/implicitReturnConversion.sol', // 'tests/compilation/contracts/typeConversion/implicitTypeConv.sol', diff --git a/warplib/src/conversions/integer_conversions.cairo b/warplib/src/conversions/integer_conversions.cairo index f45270727..fd78b5649 100644 --- a/warplib/src/conversions/integer_conversions.cairo +++ b/warplib/src/conversions/integer_conversions.cairo @@ -1,12 +1,10 @@ -use integer::u128_try_from_felt252; -use integer::u256_from_felt252; -use integer::u128_to_felt252; use array::ArrayImpl; +use integer::{downcast, upcast, u128_try_from_felt252, BoundedInt}; use option::OptionTrait; -use option::OptionTraitImpl; use starknet::ContractAddress; -use traits::Into; -use traits::TryInto; +use traits::{Into, TryInto}; + +use warplib::integer::{bitnot, Integer}; fn u256_from_felts(low_felt: felt252, high_felt: felt252) -> u256 { let low_u128: u128 = get_u128_try_from_felt_result(low_felt); @@ -14,15 +12,6 @@ fn u256_from_felts(low_felt: felt252, high_felt: felt252) -> u256 { return u256 { low: low_u128, high: high_u128 }; } -fn try_u256_to_felt252(x: u256) -> felt252 { - let MAX_FELT = u256_from_felt252(-1); - if x > MAX_FELT { - panic_with_felt252('Overflow in u256_to_felt252') - } - // hex is 2**128 - u128_to_felt252(x.low) + 0x100000000000000000000000000000000 * u128_to_felt252(x.high) -} - fn get_u128_try_from_felt_result(value: felt252) -> u128 { let resp = u128_try_from_felt252(value); assert(resp.is_some(), 'Felts too large for u256'); @@ -82,3 +71,34 @@ fn unsafe_contract_address_from_u256(x: u256) -> ContractAddress { Option::None(_) => panic_with_felt252('the u256 does not fit in felt'), } } + +// FIXME: Should have been possible without our special Integer trait, +// but NumericLiteral doesn't quite work yet. Without being able to +// create constants of our generic type, we can't do anything. +fn signed_upcast< + FromType, + impl IntegerFrom: Integer, + impl BoundedIntFrom: BoundedInt, + impl SubFrom: Sub, + impl PartialOrdFrom: PartialOrd, + impl CopyFrom: Copy, + impl DropFrom: Drop, + ToType, + impl BoundedIntTo: BoundedInt, + impl SubTo: Sub, +>(x: FromType) -> ToType { + if x < Integer::signed_upper_bound() { + upcast(x) + } else { + bitnot(upcast(bitnot(x))) + } +} + +fn cutoff_downcast< + FromType, + impl BitAndFrom: BitAnd, + ToType, + impl BoundedIntTo: BoundedInt, +>(x: FromType) -> ToType { + downcast(x & upcast(BoundedInt::::max())).unwrap() +} diff --git a/warplib/src/integer.cairo b/warplib/src/integer.cairo new file mode 100644 index 000000000..46900cf43 --- /dev/null +++ b/warplib/src/integer.cairo @@ -0,0 +1,83 @@ +// FIXME: merge imports using "use bla::{foo, bar}" syntax, when +// updated to Cairo 1.1 +use integer::BoundedInt; +use integer::downcast; +use integer::u256; +use integer::upcast; +use option::OptionTrait; + +trait Integer { + // basically, 2^(width - 1), but precomputed, because there is no + // way to compute that efficiently at the moment + fn signed_upper_bound() -> T; +} + +impl Integer8 of Integer { + fn signed_upper_bound() -> u8 { + 0x80 + } +} + +impl Integer16 of Integer { + fn signed_upper_bound() -> u16 { + 0x8000 + } +} + +impl Integer32 of Integer { + fn signed_upper_bound() -> u32 { + 0x80000000 + } +} + +impl Integer64 of Integer { + fn signed_upper_bound() -> u64 { + 0x8000000000000000 + } +} + +impl Integer128 of Integer { + fn signed_upper_bound() -> u128 { + 0x80000000000000000000000000000000 + } +} + +impl Integer256 of Integer { + fn signed_upper_bound() -> u256 { + u256 { low: 0, high: Integer::signed_upper_bound() } + } +} + +// FIXME: remove, when we update to Cairo 1.1, use builtin BitNot instead +fn bitnot, impl SubT: Sub>(x: T) -> T { + BoundedInt::max() - x +} + +// FIXME: remove, when core implementations are available +impl U8BitAnd of BitAnd { + #[inline(always)] + fn bitand(lhs: u8, rhs: u8) -> u8 { + downcast(upcast::(lhs) & upcast(rhs)).unwrap() + } +} + +impl U16BitAnd of BitAnd { + #[inline(always)] + fn bitand(lhs: u16, rhs: u16) -> u16 { + downcast(upcast::(lhs) & upcast(rhs)).unwrap() + } +} + +impl U32BitAnd of BitAnd { + #[inline(always)] + fn bitand(lhs: u32, rhs: u32) -> u32 { + downcast(upcast::(lhs) & upcast(rhs)).unwrap() + } +} + +impl U64BitAnd of BitAnd { + #[inline(always)] + fn bitand(lhs: u64, rhs: u64) -> u64 { + downcast(upcast::(lhs) & upcast(rhs)).unwrap() + } +} diff --git a/warplib/src/lib.cairo b/warplib/src/lib.cairo index 08becbd1d..03b373572 100644 --- a/warplib/src/lib.cairo +++ b/warplib/src/lib.cairo @@ -1,6 +1,7 @@ // Add here modules ready to use in Cairo1; mod conversions; mod external_input_check; +mod integer; mod maths; mod warp_memory; mod types;