Skip to content

Commit

Permalink
Added safemath i128
Browse files Browse the repository at this point in the history
  • Loading branch information
BlobMaster41 committed Jan 21, 2025
1 parent 628a58e commit 248ad49
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 1 deletion.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@btc-vision/btc-runtime",
"version": "1.4.3",
"version": "1.4.4",
"description": "Bitcoin Smart Contract Runtime",
"main": "btc/index.ts",
"scripts": {
Expand Down
1 change: 1 addition & 0 deletions runtime/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export * from './lang/Definitions';
export * from './types/Address';
export * from './types/Revert';
export * from './types/SafeMath';
export * from './types/SafeMathI128';

/** Math */
export * from './math/abi';
Expand Down
146 changes: 146 additions & 0 deletions runtime/types/SafeMathI128.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import { i128 } from '@btc-vision/as-bignum/assembly';

export class SafeMathI128 {
public static readonly ZERO: i128 = i128.fromI32(0);
public static readonly ONE: i128 = i128.fromI32(1);
public static readonly NEG_ONE: i128 = i128.fromI32(-1);

public static readonly MIN: i128 = i128.Min;
public static readonly MAX: i128 = i128.Max;

/**
* Safe addition for i128.
* Throws if (a + b) overflows or underflows the signed 128-bit range.
*/
public static add(a: i128, b: i128): i128 {
let c = i128.add(a, b);

// Overflow check for 2's complement:
// If a and b have the same sign, but c differs, overflow occurred.
// We can detect sign mismatch using ((a ^ c) & (b ^ c)) < 0
// (i.e., the sign bit is set in that expression).
if (((a ^ c) & (b ^ c)).isNeg()) {
throw new Error('SafeMathI128: addition overflow');
}

return c;
}

/**
* Safe subtraction for i128.
* Throws if (a - b) overflows or underflows the signed 128-bit range.
*/
public static sub(a: i128, b: i128): i128 {
let c = i128.sub(a, b);

// Subtraction is (a + (-b)). We can do a direct check like:
// If (a ^ b) & (a ^ c) has sign bit set => overflow.
if (((a ^ b) & (a ^ c)).isNeg()) {
throw new Error('SafeMathI128: subtraction overflow');
}

return c;
}

/*public static mul(a: i128, b: i128): i128 {
// Quick check: if either is ZERO, product is ZERO => no overflow
if (a == SafeMathI128.ZERO || b == SafeMathI128.ZERO) {
return SafeMathI128.ZERO;
}
let c = i128.mul(a, b);
// Check overflow: c / b should be exactly a (if b != 0).
// Also watch for the i128 edge case: MIN * -1 => possible overflow if not representable.
// We'll rely on the division check:
if (b != SafeMathI128.ZERO) {
let divCheck = i128.div(c, b);
if (divCheck != a) {
throw new Error('SafeMathI128: multiplication overflow');
}
}
return c;
}*/

/*public static div(a: i128, b: i128): i128 {
if (b == SafeMathI128.ZERO) {
throw new Error('SafeMathI128: division by zero');
}
// Check i128 edge case: MIN / -1 => possible overflow if no corresponding positive.
if (a == SafeMathI128.MIN && b == SafeMathI128.NEG_ONE) {
throw new Error('SafeMathI128: division overflow (MIN / -1)');
}
return i128.div(a, b);
}*/

/*public static mod(a: i128, b: i128): i128 {
if (b == SafeMathI128.ZERO) {
throw new Error('SafeMathI128: modulo by zero');
}
// Similar edge case as division:
if (a == SafeMathI128.MIN && b == SafeMathI128.NEG_ONE) {
// Some implementations might treat MIN % -1 == 0,
// but if the library doesn't, you may handle it similarly to division.
// We'll assume we throw to be safe:
throw new Error('SafeMathI128: modulo overflow (MIN % -1)');
}
// Use i128.rem, i128.mod, or the operator as appropriate.
return i128.rem(a, b);
}*/

/**
* Increment an i128 by 1 with overflow check.
*/
public static inc(value: i128): i128 {
return SafeMathI128.add(value, SafeMathI128.ONE);
}

/**
* Decrement an i128 by 1 with underflow check.
*/
public static dec(value: i128): i128 {
return SafeMathI128.sub(value, SafeMathI128.ONE);
}

/**
* Return the absolute value of x, throwing if x == MIN (since |MIN| might not be representable).
*/
public static abs(x: i128): i128 {
if (x.isNeg()) {
// If x == MIN, -x can overflow.
if (x == SafeMathI128.MIN) {
throw new Error('SafeMathI128: abs overflow on MIN');
}
return x.neg();
}
return x;
}

/**
* Return the negation of x, throwing if x == MIN.
*/
public static neg(x: i128): i128 {
if (x == SafeMathI128.MIN) {
throw new Error('SafeMathI128: neg overflow on MIN');
}
return x.neg();
}

/**
* Returns the smaller of two i128s.
*/
public static min(a: i128, b: i128): i128 {
return i128.lt(a, b) ? a : b;
}

/**
* Returns the larger of two i128s.
*/
public static max(a: i128, b: i128): i128 {
return i128.gt(a, b) ? a : b;
}
}

0 comments on commit 248ad49

Please sign in to comment.