tinygo-org / tinygo

Go compiler for small places. Microcontrollers, WebAssembly (WASM/WASI), and command-line tools. Based on LLVM.
https://tinygo.org
Other
15.17k stars 890 forks source link

math/big: support for long arithmetic #890

Open tucnak opened 4 years ago

tucnak commented 4 years ago

Hello again,

According to language support page, much of the crypto functionality of Go is currently unavailable, and math/big seems to be the culprit.

Packages like crypto/tls also rely on net, which I belive won't be trivial to get right due to concurrency, but the elliptic crypto packages, as well as encoding/asn1 among others, are not accessible exclusively due to one math/big bug:

# math/big
../../../../../../../usr/local/Cellar/go/1.13.7/libexec/src/math/big/float.go:559:4: interp: branch on a non-constant

I've pulled the relevant code, but I'm yet to realise what's the branch in question. Look:

func (z *Float) SetFloat64(x float64) *Float {
    if z.prec == 0 {
        z.prec = 53
    }
    if math.IsNaN(x) {
        panic(ErrNaN{"Float.SetFloat64(NaN)"})
    }
    z.acc = Exact
    z.neg = math.Signbit(x) // handle -0, -Inf correctly
    if x == 0 {
        z.form = zero
        return z
    }
    if math.IsInf(x, 0) {
        z.form = inf
        return z
    }

    // normalized x != 0

/*-->*/ z.form = finite // line 559

    fmant, exp := math.Frexp(x) // get normalized mantissa
    z.mant = z.mant.setUint64(1<<63 | math.Float64bits(fmant)<<11)
    z.exp = int32(exp) // always fits
    if z.prec < 53 {
        z.round(0)
    }
    return z
}

I've only gone as far as to check finite, only to realise it's a const form iota, which is a byte-sized description of some internal representation. This code looks totally regular. Any ideas why this could go wrong? I desperately need small wasm binaries for my crypto stuff, and would love to figure this one out, but at this moment of time it's well out of my expertise.

aykevl commented 4 years ago

The problem here is rather subtle and lies deep in the compiler. Last time I looked at it, I discovered that it was likely a problem with the runtime.isnil mechanism that was needed previously (but is currently not needed anymore in LLVM 9). Also see #437.

aykevl commented 4 years ago

It looks like this is going to be a blocker for Go 1.14 support. I get this error after modifying the error printer slightly while running go test:

main.go:693: # math/rand
main.go:695: interp: branch on a non-constant
tucnak commented 4 years ago

@aykevl What is the timetable on Go 1.14 support? What would you do if you were unfamiliar with the project (me, basically) and very passionate about having this resolved ASAP?

aykevl commented 4 years ago

@tucnak take a look at #901. The issue with math/rand has been solved with #983, but there are a few other things left.

fgsch commented 2 years ago

Looks like this can be closed?

tucnak commented 2 years ago

As long as math/big can be built...?

dgryski commented 2 years ago

I believe math/big can build and works but the tests can't run for a number of reasons:

tucnak commented 2 years ago

@dgryski Now, I did a quick search around the tracker and it seems none of these issues are currently triaged. Perhaps this issue could be a reference point to get them resolved? I.e. the milestone of having full math/big support, including (fuzzy) testing among other things. BTW, what's the maintainer's stance on fuzzing, is it fully supported tooling-wise? This is probably single most important addition to Go language since race detector! And especially important for crypto-oriented code, with much of it natively revolving around math/big for long/modulus arithmetic. However, all the while it may be somewhat trivial to work around, what's about reflect if you don't mind me asking? Ref. to the relevant issues should help, too!

dankegel commented 2 years ago

I think https://github.com/tinygo-org/tinygo/pull/2640 is a draft of the next step in reflect support.

aykevl commented 2 years ago

BTW, what's the maintainer's stance on fuzzing, is it fully supported tooling-wise? This is probably single most important addition to Go language since race detector! And especially important for crypto-oriented code, with much of it natively revolving around math/big for long/modulus arithmetic.

I have not yet looked into it. I guess you could simply use the go toolchain for the fuzzing, after all, if you write portable code it should work in both TinyGo and regular Go.

dgryski commented 2 years ago

Full fuzzing integration is a bunch of compiler work, not only getting the bits of of the testing package ported over. I have a very minimal randomized testing package I've used with tinygo, but note that there's no coverage guided logic or corpus support.

https://github.com/dgryski/go-tinyfuzz