Skip to content

Commit

Permalink
Merge pull request #13 from web3p/add-to-bn
Browse files Browse the repository at this point in the history
Add toBn
  • Loading branch information
sc0Vu authored Dec 18, 2022
2 parents 77a860f + 0fdf38b commit 9a01f53
Show file tree
Hide file tree
Showing 3 changed files with 192 additions and 5 deletions.
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"require": {
"PHP": "^7.1 | ^8.0",
"kornrunner/keccak": "~1",
"simplito/elliptic-php": "~1.0.6"
"simplito/elliptic-php": "~1.0.6",
"phpseclib/phpseclib": "~2.0"
}
}
95 changes: 91 additions & 4 deletions src/Util.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
use InvalidArgumentException;
use RuntimeException;
use kornrunner\Keccak;
use phpseclib\Math\BigInteger as BigNumber;
use Elliptic\EC;
use Elliptic\EC\KeyPair;
use Elliptic\EC\Signature;
Expand Down Expand Up @@ -65,24 +66,23 @@ public function __get($name)
*
* @param string $name
* @param mixed $value
* @return mixed
* @return void
*/
public function __set($name, $value)
{
$method = 'set' . ucfirst($name);

if (method_exists($this, $method)) {
return call_user_func_array([$this, $method], [$value]);
call_user_func_array([$this, $method], [$value]);
}
return false;
}

/**
* sha3
* keccak256
*
* @param string $value
* @return string
* @return null|string
*/
public function sha3(string $value)
{
Expand Down Expand Up @@ -135,6 +135,7 @@ public function isHex(string $value)
* publicKeyToAddress
*
* @param string $publicKey
* @throws InvalidArgumentException
* @return string
*/
public function publicKeyToAddress(string $publicKey)
Expand All @@ -154,6 +155,7 @@ public function publicKeyToAddress(string $publicKey)
* privateKeyToPublicKey
*
* @param string $privateKey
* @throws InvalidArgumentException
* @return string
*/
public function privateKeyToPublicKey(string $privateKey)
Expand All @@ -179,6 +181,7 @@ public function privateKeyToPublicKey(string $privateKey)
* @param string $r
* @param string $s
* @param int $v
* @throws InvalidArgumentException
* @return string
*/
public function recoverPublicKey(string $hash, string $r, string $s, int $v)
Expand Down Expand Up @@ -211,6 +214,7 @@ public function recoverPublicKey(string $hash, string $r, string $s, int $v)
*
* @param string $privateKey
* @param string $message
* @throws InvalidArgumentException
* @return \Elliptic\EC\Signature
*/
public function ecsign(string $privateKey, string $message)
Expand Down Expand Up @@ -246,4 +250,87 @@ public function hashPersonalMessage(string $message)
$prefix = sprintf("\x19Ethereum Signed Message:\n%d", mb_strlen($message));
return $this->sha3($prefix . $message);
}

/**
* isNegative
*
* @param string
* @throws InvalidArgumentException
* @return bool
*/
public function isNegative(string $value)
{
if (!is_string($value)) {
throw new InvalidArgumentException('The value to isNegative function must be string.');
}
return (strpos($value, '-') === 0);
}

/**
* toBn
* Change number or number string to bignumber.
*
* @param BigNumber|string|int $number
* @throws InvalidArgumentException
* @return array|\phpseclib\Math\BigInteger
*/
public function toBn($number)
{
if ($number instanceof BigNumber){
$bn = $number;
} elseif (is_int($number)) {
$bn = new BigNumber($number);
} elseif (is_numeric($number)) {
$number = (string) $number;

if ($this->isNegative($number)) {
$count = 1;
$number = str_replace('-', '', $number, $count);
$negative1 = new BigNumber(-1);
}
if (strpos($number, '.') > 0) {
$comps = explode('.', $number);

if (count($comps) > 2) {
throw new InvalidArgumentException('toBn number must be a valid number.');
}
$whole = $comps[0];
$fraction = $comps[1];

return [
new BigNumber($whole),
new BigNumber($fraction),
strlen($comps[1]),
isset($negative1) ? $negative1 : false
];
} else {
$bn = new BigNumber($number);
}
if (isset($negative1)) {
$bn = $bn->multiply($negative1);
}
} elseif (is_string($number)) {
$number = mb_strtolower($number);

if ($this->isNegative($number)) {
$count = 1;
$number = str_replace('-', '', $number, $count);
$negative1 = new BigNumber(-1);
}
if (empty($number)) {
$bn = new BigNumber(0);
} else if ($this->isZeroPrefixed($number) || $this->isHex($number)) {
$number = $this->stripZero($number);
$bn = new BigNumber($number, 16);
} else {
throw new InvalidArgumentException('toBn number must be valid hex string.');
}
if (isset($negative1)) {
$bn = $bn->multiply($negative1);
}
} else {
throw new InvalidArgumentException('toBn number must be BigNumber, string or int.');
}
return $bn;
}
}
99 changes: 99 additions & 0 deletions test/unit/UtilTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

use Test\TestCase;
use Web3p\EthereumUtil\Util;
use phpseclib\Math\BigInteger as BigNumber;
use InvalidArgumentException;
use stdClass;

class UtilTest extends TestCase
{
Expand Down Expand Up @@ -127,4 +130,100 @@ public function testHashPersonalMessage()

$this->assertEquals('8144a6fa26be252b86456491fbcd43c1de7e022241845ffea1c3df066f7cfede', $hashedMessage);
}

/**
* testIsNegative
*
* @return void
*/
public function testIsNegative()
{
$util = new Util;
$isNegative = $util->isNegative('-1');
$this->assertTrue($isNegative);

$isNegative = $util->isNegative('1');
$this->assertFalse($isNegative);
}

/**
* testToBn
*
* @return void
*/
public function testToBn()
{
$util = new Util;
$bn = $util->toBn('');
$this->assertEquals($bn->toString(), '0');

$bn = $util->toBn(11);
$this->assertEquals($bn->toString(), '11');

$bn = $util->toBn('0x12');
$this->assertEquals($bn->toString(), '18');

$bn = $util->toBn('-0x12');
$this->assertEquals($bn->toString(), '-18');

$bn = $util->toBn(0x12);
$this->assertEquals($bn->toString(), '18');

$bn = $util->toBn('ae');
$this->assertEquals($bn->toString(), '174');

$bn = $util->toBn('-ae');
$this->assertEquals($bn->toString(), '-174');

$bn = $util->toBn('-1');
$this->assertEquals($bn->toString(), '-1');

$bn = $util->toBn('-0.1');
$this->assertEquals(count($bn), 4);
$this->assertEquals($bn[0]->toString(), '0');
$this->assertEquals($bn[1]->toString(), '1');
$this->assertEquals($bn[2], 1);
$this->assertEquals($bn[3]->toString(), '-1');

$bn = $util->toBn(-0.1);
$this->assertEquals(count($bn), 4);
$this->assertEquals($bn[0]->toString(), '0');
$this->assertEquals($bn[1]->toString(), '1');
$this->assertEquals($bn[2], 1);
$this->assertEquals($bn[3]->toString(), '-1');

$bn = $util->toBn('0.1');
$this->assertEquals(count($bn), 4);
$this->assertEquals($bn[0]->toString(), '0');
$this->assertEquals($bn[1]->toString(), '1');
$this->assertEquals($bn[2], 1);
$this->assertEquals($bn[3], false);

$bn = $util->toBn('-1.69');
$this->assertEquals(count($bn), 4);
$this->assertEquals($bn[0]->toString(), '1');
$this->assertEquals($bn[1]->toString(), '69');
$this->assertEquals($bn[2], 2);
$this->assertEquals($bn[3]->toString(), '-1');

$bn = $util->toBn(-1.69);
$this->assertEquals($bn[0]->toString(), '1');
$this->assertEquals($bn[1]->toString(), '69');
$this->assertEquals($bn[2], 2);
$this->assertEquals($bn[3]->toString(), '-1');

$bn = $util->toBn('1.69');
$this->assertEquals(count($bn), 4);
$this->assertEquals($bn[0]->toString(), '1');
$this->assertEquals($bn[1]->toString(), '69');
$this->assertEquals($bn[2], 2);
$this->assertEquals($bn[3], false);

$bn = $util->toBn(new BigNumber(1));
$this->assertEquals($bn->toString(), '1');
$util->toBn(new BigNumber(1));

$this->expectException(InvalidArgumentException::class);
$bn = $util->toBn(new stdClass);
}
}

0 comments on commit 9a01f53

Please sign in to comment.