tinygo icon indicating copy to clipboard operation
tinygo copied to clipboard

math/big: support for long arithmetic

Open tucnak opened this issue 4 years ago • 11 comments

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.

tucnak avatar Feb 04 '20 16:02 tucnak

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 avatar Feb 08 '20 18:02 aykevl

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

aykevl avatar Mar 03 '20 16:03 aykevl

@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?

tucnak avatar Mar 23 '20 09:03 tucnak

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

aykevl avatar Mar 24 '20 14:03 aykevl

Looks like this can be closed?

fgsch avatar Aug 08 '22 16:08 fgsch

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

tucnak avatar Aug 08 '22 16:08 tucnak

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

  • a lack of encoding/gob due to reflect issues.
  • runtime.MemStats missing TotalAlloc field
  • interp timeout building tests
  • lack of testing/quick support due to reflect issues

dgryski avatar Aug 09 '22 04:08 dgryski

@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!

tucnak avatar Aug 09 '22 05:08 tucnak

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

dankegel avatar Aug 10 '22 12:08 dankegel

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.

aykevl avatar Aug 31 '22 20:08 aykevl

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

dgryski avatar Aug 31 '22 20:08 dgryski