Code Monkey home page Code Monkey logo

uint256's Introduction

Fixed size 256-bit math library

This is a library specialized at replacing the big.Int library for math based on 256-bit types, used by both go-ethereum and erigon.

Go Reference codecov DeepSource

Benchmarks

Current benchmarks, with tests ending with big being the standard big.Int library, and uint256 being this library.

Current status

  • As of 2020-03-18, uint256 wins over math/big in every single case, often with orders of magnitude.
  • And as of release 0.1.0, the uint256 library is alloc-free.
  • With the 1.0.0 release, it also has 100% test coverage.

Bitwise

benchmark u256 time/op big time/op time diff u256 B/op big B/op B diff u256 allocs/op big allocs/op allocs diff
And/single 2.03ns 8.46ns -76.04% 0 0 ~ 0 0 ~
Or/single 2.03ns 10.98ns -81.51% 0 0 ~ 0 0 ~
Xor/single 2.03ns 12.19ns -83.34% 0 0 ~ 0 0 ~
Rsh/n_eq_0 5.00ns 48.11ns -89.61% 0 64 -100.00% 0 1 -100.00%
Rsh/n_gt_0 10.42ns 48.41ns -78.48% 0 64 -100.00% 0 1 -100.00%
Rsh/n_gt_64 6.94ns 52.39ns -86.76% 0 64 -100.00% 0 1 -100.00%
Rsh/n_gt_128 5.49ns 44.21ns -87.59% 0 48 -100.00% 0 1 -100.00%
Rsh/n_gt_192 3.43ns 28.71ns -88.04% 0 8 -100.00% 0 1 -100.00%
Lsh/n_eq_0 4.89ns 40.49ns -87.92% 0 64 -100.00% 0 1 -100.00%
Lsh/n_gt_0 10.14ns 53.25ns -80.96% 0 80 -100.00% 0 1 -100.00%
Lsh/n_gt_64 7.50ns 53.92ns -86.08% 0 80 -100.00% 0 1 -100.00%
Lsh/n_gt_128 5.39ns 56.86ns -90.52% 0 96 -100.00% 0 1 -100.00%
Lsh/n_gt_192 3.90ns 57.61ns -93.23% 0 96 -100.00% 0 1 -100.00%

Conversions

benchmark u256 time/op big time/op time diff u256 B/op big B/op B diff u256 allocs/op big allocs/op allocs diff
FromHexString 116.70ns 861.30ns -86.45% 32 88 -63.64% 1 3 -66.67%
FromDecimalString 7973.00ns 32850.00ns -75.73% 0 2464 -100.00% 0 77 -100.00%
Float64/Float64 2366.00ns 28483.00ns -91.69% 0 23424 -100.00% 0 510 -100.00%
EncodeHex/large 95.26ns 184.30ns -48.31% 80 140 -42.86% 1 2 -50.00%
Decimal/ToDecimal 67384.00ns 83431.00ns -19.23% 11344 31920 -64.46% 248 594 -58.25%
Decimal/ToPrettyDecimal 84208.00ns 123953.00ns -32.06% 14720 61376 -76.02% 251 1100 -77.18%

Math

benchmark u256 time/op big time/op time diff u256 B/op big B/op B diff u256 allocs/op big allocs/op allocs diff
Add/single 1.99ns 18.11ns -89.02% 0 0 ~ 0 0 ~
Sub/single 2.00ns 17.19ns -88.35% 0 0 ~ 0 0 ~
Mul/single 12.10ns 57.69ns -79.03% 0 0 ~ 0 0 ~
SDiv/large 94.64ns 642.10ns -85.26% 0 312 -100.00% 0 6 -100.00%
Sqrt/single 594.90ns 1844.00ns -67.74% 0 528 -100.00% 0 7 -100.00%
Square/single 12.49ns 56.10ns -77.74% 0 0 ~ 0 0 ~
Cmp/single 4.78ns 12.79ns -62.61% 0 0 ~ 0 0 ~
Div/small 12.91ns 48.31ns -73.28% 0 8 -100.00% 0 1 -100.00%
Div/mod64 65.77ns 111.20ns -40.85% 0 8 -100.00% 0 1 -100.00%
Div/mod128 93.67ns 301.40ns -68.92% 0 80 -100.00% 0 1 -100.00%
Div/mod192 86.52ns 263.80ns -67.20% 0 80 -100.00% 0 1 -100.00%
Div/mod256 77.17ns 252.80ns -69.47% 0 80 -100.00% 0 1 -100.00%
AddMod/small 13.84ns 48.16ns -71.26% 0 4 -100.00% 0 0 ~
AddMod/mod64 22.83ns 57.58ns -60.35% 0 11 -100.00% 0 0 ~
AddMod/mod128 48.31ns 145.00ns -66.68% 0 12 -100.00% 0 0 ~
AddMod/mod192 47.26ns 160.00ns -70.46% 0 12 -100.00% 0 0 ~
AddMod/mod256 14.44ns 143.20ns -89.92% 0 12 -100.00% 0 0 ~
MulMod/small 40.81ns 63.14ns -35.37% 0 8 -100.00% 0 1 -100.00%
MulMod/mod64 91.66ns 112.60ns -18.60% 0 48 -100.00% 0 1 -100.00%
MulMod/mod128 136.00ns 362.70ns -62.50% 0 128 -100.00% 0 2 -100.00%
MulMod/mod192 151.70ns 421.20ns -63.98% 0 144 -100.00% 0 2 -100.00%
MulMod/mod256 188.80ns 489.20ns -61.41% 0 176 -100.00% 0 2 -100.00%
Exp/small 433.70ns 7490.00ns -94.21% 0 7392 -100.00% 0 77 -100.00%
Exp/large 5145.00ns 23043.00ns -77.67% 0 18144 -100.00% 0 189 -100.00%
Mod/mod64 70.94ns 118.90ns -40.34% 0 64 -100.00% 0 1 -100.00%
Mod/small 14.82ns 46.27ns -67.97% 0 8 -100.00% 0 1 -100.00%
Mod/mod128 99.58ns 286.90ns -65.29% 0 64 -100.00% 0 1 -100.00%
Mod/mod192 95.31ns 269.30ns -64.61% 0 48 -100.00% 0 1 -100.00%
Mod/mod256 84.13ns 222.90ns -62.26% 0 8 -100.00% 0 1 -100.00%
MulOverflow/single 27.68ns 57.52ns -51.88% 0 0 ~ 0 0 ~
MulDivOverflow/small 2.83ns 22.97ns -87.69% 0 0 ~ 0 0 ~
MulDivOverflow/div64 2.85ns 23.13ns -87.66% 0 0 ~ 0 0 ~
MulDivOverflow/div128 3.14ns 31.29ns -89.96% 0 2 -100.00% 0 0 ~
MulDivOverflow/div192 3.17ns 30.28ns -89.54% 0 2 -100.00% 0 0 ~
MulDivOverflow/div256 3.54ns 35.56ns -90.06% 0 5 -100.00% 0 0 ~
Lt/small 3.12ns 10.43ns -70.06% 0 0 ~ 0 0 ~
Lt/large 3.49ns 10.32ns -66.18% 0 0 ~ 0 0 ~

Other

benchmark u256 time/op u256 B/op u256 allocs/op
SetBytes/generic 104.30ns 0 0
Sub/single/uint256_of 1.99ns 0 0
SetFromBig/overflow 3.57ns 0 0
ToBig/2words 73.84ns 64 2
SetBytes/specific 45.81ns 0 0
ScanScientific 674.10ns 0 0
SetFromBig/4words 3.82ns 0 0
ToBig/4words 68.82ns 64 2
RLPEncoding 11917.00ns 11911 255
SetFromBig/1word 2.99ns 0 0
SetFromBig/3words 4.12ns 0 0
ToBig/3words 70.12ns 64 2
ToBig/1word 75.38ns 64 2
MulMod/mod256/uint256r 77.11ns 0 0
HashTreeRoot 11.27ns 0 0
SetFromBig/2words 3.90ns 0 0

Helping out

If you're interested in low-level algorithms and/or doing optimizations for shaving off nanoseconds, then this is certainly for you!

Implementation work

Choose an operation, and optimize the s**t out of it!

A few rules, though, to help your PR get approved:

  • Do not optimize for 'best-case'/'most common case' at the expense of worst-case.
  • We'll hold off on go assembly for a while, until the algos and interfaces are finished in a 'good enough' first version. After that, it's assembly time.

Doing benchmarks

To do a simple benchmark for everything, do

go test -run - -bench . -benchmem

To see the difference between a branch and master, for a particular benchmark, do

git checkout master
go test -run - -bench Benchmark_Lsh -benchmem -count=10 > old.txt

git checkout opt_branch
go test -run - -bench Benchmark_Lsh -benchmem -count=10 > new.txt

benchstat old.txt new.txt

uint256's People

Contributors

aaronchen0 avatar chfast avatar daosvik avatar decanus avatar deepsourcebot avatar elee1766 avatar fyfyrchik avatar fyrchik avatar gballet avatar holiman avatar jwasinger avatar karalabe avatar kubuxu avatar planxnx avatar terencechain avatar yaozengzeng avatar yperbasis avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

uint256's Issues

Create DIV based on Knuth Algorithm D

Task

Implement integer division based on Knuth's algorithm D. The algo is described in the book "Hackers Delight", and is implemented in a lot of places over the internet.
The golang int lib uses it internally, with asm backing.

One implementation: https://deamentiaemundi.wordpress.com/2014/10/01/multiprecision-long-division-knuths-algorithm-d/
64/32 bit: http://www.hackersdelight.org/hdcodetxt/divmnu64.c.txt
Golang impl: https://golang.org/src/math/big/nat.go#L611

The task requires

  • Implementing it in pure go (no asm)
  • The implementation must work on both big-endian and little-endian systems

uint512

Extend this library for 512-bit types

1.0 roadmap

  1. Full test coverage: https://codecov.io/gh/holiman/uint256
  2. Inspect Exp() implementation (constant time, but gas cost proportional to exponent size).
  3. Remove unneeded public functions.
  4. Fix SDiv(), SMod() - they modify arguments.
  5. Review decision to return zero on division by zero. #62 #64
  6. Test arm architecture?
  7. Test any big-endian architecture? #60
  8. Unify names: Sub64() vs LtUint64(). #65
  9. Run benchmarks against 0.1 version.

[ Bug ] Bytes32 does not marshal Int into little-endian byte array

When calling Bytes32() on an Int [4]uint64{uint64(0), uint64(0), uint64(0), uint64(1)} (according to directions here https://github.com/holiman/uint256/blob/master/uint256.go#L40 where Int[3] is most significant), I get the following bytes:

[0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]

There are a few issues with the above:

If I call Bytes32() on an Int [4]uint64{uint64(1), uint64(0), uint64(0), uint64(0)} (where the input is in little-endian order, with most significant at Int[0]), I get the following output:

[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1]

The output above is in big-endian order which contradicts the description here: https://github.com/holiman/uint256/blob/master/uint256.go#L99

Expected behavior:

Input of [4]uint64{uint64(1), uint64(0), uint64(0), uint64(0)} marshals to []byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} when Bytes32() is called on Input.

New Release

hi @holiman, could you make a new tag / release? There are so many improvements / additions since the last tag.

Allow Cmp to big.Int without converting big.Int

Feature
func (*uint256.Int) CmpBig(big.Int) int
Motivation

Generally uint256.Int is superior and should replace big.Int everywhere. But in forked or in sufficiently large codebases it may not be practical or necessary to replace all instances. At the boundaries, this function could circumvent an explicit conversion.

I didn't find this feature when I looked for it so please close this if it already exists.

uint256.FromHex() with leading zeroes is inconsistent

Hi,

We have a problem converting hash values into uint256 as uint256.FromHex() does not accept hex values with leading zeroes. Is there a particular reason for this?
Why do I think this behavior is inconsistent? I can easily convert byte array with leading zeroes to uint256:

uint256.NewInt(0).SetBytes([]byte{0x00, 0x01})

It would be nice to be able to covert using FromHex() directly without intermediate manipulations.
Thanks

The 1.2.0 release is not API compatible with 1.1.1, breaking SemVer assumptions

The 1.2.0 release broke the API, and thus should have been 2.0.0
The breaking change came in b323bdc
Where NewInt() changed to NewInt(val uint64).

This breaks MVS, and thus all libraries depending on your library, like go-ethereum where currently new developers importing go-ethereum will get the latest compatible version of uint256 (the latest in version 1 which is 1.2.0) but is not actually compatible.
The result is new developers not being able to build their projects.

The steps to rectify this is:

Publish with permissive license

Hi, I would like to ask if it would be possible to license this code under a more permissive license. GPL is viral and LGPL is hard to apply to Golang as there are no shared libraries.

MIT or Apache-2 would work best the projects I would like to use it for (libp2p/ipfs).

I fully understand any objections against it.

Implement `Dec()` and `PrettyDec()` properly

When printing ints in logs or console, it's usually better to print as a decimal vs hex. But there's no way to flatten a uint256 Int currently into a decimal string. It feels a bit wonky to do uint256.Int.ToBig().String()

RLP decoding woes

We now have rlp encoding, and can encode RLP. However, RLP decoding requires to implement this interface: https://github.com/ethereum/go-ethereum/blob/44b41641f8220fe79e43461356c147cc3cc72380/rlp/decode.go#L64

I.e,

type Decoder interface {
	DecodeRLP(*Stream) error
}

Where *Stream is this struct from the same package.

If we want uint256.Int to implement that, it would require adding rlp as a dependency :( .

@fjl any ideas to get us out of this? Seems quirky, from API-perspective, to have Encoder interface be implementable without rlp-dependency, but have the Decoder interface depend on package rlp.

Unexpected overflows

We are getting overflow errors in go-ethereum from the uint256.FromBig method.

R, ok = uint256.FromBig((*big.Int)(dec.R))

Here are the logs with the values that cause the overflow error (dec.R.String()).

INFO   [0007] (tx-listener.session.ethereum.hook): block processed  block_number=5263607 chain=4b0aed40-c2da-44b1-9396-50233910590e owner_id= tenant_id=_
'r' value overflows uint256: 0xb75685b724028d4cc66bd8ff0aa46b6e4721842ac1f7f4880563b581dcfb2ee
's' value overflows uint256: 0x4cdd5a8417fa2c49aa472b8e079e01f276120089ea0c7b27df4533193876abed
'v' value overflows uint256: 0x1
'r' value overflows uint256: 0x241bff69a5506e1a26543b97b22854ec556f822b71627a3136f245e05b98fda9
's' value overflows uint256: 0x7a8ee9210af64eee6e3a15b331ea7d491d3d983f93d52b06f97282a050a9e973
'v' value overflows uint256: 0x1

That does not seem right. What is going wrong here?

Thanks for cheking!

Value change after uint256.FromBig and then ToBig

Negative value change after uint256.FromBig and then ToBig:

func TestReverse(t *testing.T) {
	a, _ := big.NewInt(0).SetString("-1", 10)
	u, _ := uint256.FromBig(a)
	areverse := u.ToBig()
	fmt.Println(areverse, areverse.Sign(), a.Sign())
	// areverse:  115792089237316195423570985008687907853269984665640564039457584007913129639935 1 -1
}

Optimize ExtendSign()

The current implementation is done by bits manipulation on whole 256-bit values (as you would do it for architecture native integers). There exists more efficient implementation which handles each of 4 64-bit words separately. This has been implemented in evmone in ethereum/evmone#390.

SetHex or SetString equivalent

Hey,

it would be nice to have a math/big.Int SetString equivalent so that we can re-use Int objects without releasing to GC. Maybe just expose (z *Int) fromHex(hex string)?

Thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.