[Go 1.20 was released](https://go.dev/blog/go1.20) on February 1, 2023. That means it's time for the final part of this three part look at [**What’s New in Go 1.20**](/post/2023/golang-120-language-changes/). In this part, we'll look at some of the relatively minor changes to the standard library. Before we begin, here are two changes I won't write about because someone else did. The first is the new [context.WithCancelCause](https://pkg.go.dev/context#WithCancelCause) API. [Joseph Woodward wrote a great summary](https://josephwoodward.co.uk/2023/01/context-cancellation-cause-with-cancel-cause) of the issue, so please read that. Second, Filippo Valsorda wrote a complete look at [Go 1.20 cryptography changes](https://words.filippo.io/dispatches/go-1-20-cryptography/), including the new [crypto/ecdh](https://pkg.go.dev/crypto/ecdh@go1.20) package. So, check that out for more details on those changes, including the secret [crypto/internal/bigmod](https://pkg.go.dev/crypto/internal/bigmod) package 🤫. - - - - Speaking of cryptography, I will briefly call out one cryptography-related change. The crypto/subtle package gains a [XORBytes](https://pkg.go.dev/crypto/subtle@go1.20#XORBytes) function. If you've ever tried the [Cryptopals challenges](https://www.cryptopals.com), it's literally [the second challenge](https://www.cryptopals.com/sets/1/challenges/2), before any of the actually hard crypto stuff starts. It's nice to have a built-in version in the standard library now. - - - - In Go 1.20, the math/random package has one change and also one crypto-adjacent non-change. The Go team have been aware of flaws in the math/rand package for years. All the way back in 2017, [Rob Pike wrote](https://github.com/golang/go/issues/21835): > Changing `math/rand` to use [a different algorithm] is strictly incompatible, but not in a way that the Go 1 decree actually prohibits. A soft breakage at this level would be an excellent step on the way to understanding what it takes to roll out a breaking change for Go 2. After this was written, it was decided that ["Go 2" would be backwards compatible to the furthest extent possible](https://www.youtube.com/watch?v=kNHo788oO5Y), but that still leaves the Go team with the question of what to do with packages like math/rand that probably really do need breaking changes. One change made in Go 1.20 is that math/rand is now random by default. Before it always began by using a set sequence until you called [RANDOMIZE TIMER](http://www.antonis.de/qbebooks/gwbasman/randomize.html) [rand.Seed](https://pkg.go.dev/math/rand#Seed). Seeding math/rand by default is sort of a breaking change, but in a weird kind of way. It only breaks code that a) depends on having a consistent sequence from math/rand, but b) does not use its own `*rand.Rand` to specify a source with a known initial seed. On the one hand, it's certain that [this will break someone's code out there](https://www.hyrumslaw.com). On the other hand, it's hard to say that they weren't warned. The package is named "rand", so one might reasonably expect [random behavior](https://xkcd.com/221/) from it. If this new behavior breaks your code and you cannot rewrite it to work correctly, you can use `GODEBUG=randautoseed=0` to disable it for now. The non-change to the math/rand package is now [rand.Read](https://pkg.go.dev/math/rand#Seed) is officially deprecated. (Note that because of the [Go 1 guarantee](https://go.dev/doc/go1compat), deprecated functions aren't ever actually removed from the standard library. They just produce warnings in various tools.) There basically was never a good reason to use `rand.Read`. It fills a buffer with some random bits, but if you're doing that, you're probably doing crypto, in which case, you should use [crypto/rand.Read](https://pkg.go.dev/crypto/rand#Read) instead. The sequences produced by math/rand are only pseudorandom. A dedicated hacker can possibly reverse them, so it must never be used for cryptography. The formal deprecation of `math/rand.Read` doesn't actually change anything, but it does emphasize publicly something that people with knowledge of the Go standard library have already known for years. - - - - The path/filepath package got a handy new function called [IsLocal](https://pkg.go.dev/path/filepath#IsLocal). "Localness" is a property that didn't have a good name until now. If you have a path that begins with a "/", that's an "absolute" path. If you have a path like "./file" or "../dir", that's a "relative" path. But what do you call the idea that once all the relative directories are evaluated, the resulting directory path does not go up into a parent directory, like "nothingtosee/../../../../etc/passwd"? Well, now that concept has a name, and it's a called "IsLocal". `filepath.IsLocal` also tests for special names on Windows, like NUL. It's particularly handy if you want to use a path with an [fs.FS](https://pkg.go.dev/io/fs#FS), since `fs.FS` expects all paths to be local. - - - - In Go 1.20, users of [httputil.ReverseProxy](https://go.dev/pkg/net/http/httputil/#ReverseProxy) will now have a little more control of exactly what fields are forwarded to the destination server. Traditionally, advanced users of the `httputil.ReverseProxy` used the `Director` field to modify a single request before it was forwarded. This was a little bit clunky and [led to some security issues](https://github.com/golang/go/issues/50580) with fields being accidentally forwarded when they should or shouldn't be. The new `Rewrite` field separates the incoming request from the outgoing request and adds a few helper methods to make it easier to write a secure forwarding proxy. - - - - Finally, if you have ever written this code: ```go if strings.HasPrefix(s, "something/") { s = strings.TrimPrefix(s, "something/") // do something with short s } else { // do something else with long s } ``` You can now use [strings.CutPrefix](https://pkg.go.dev/strings#CutPrefix) to type slightly less: ```go s, ok := strings.CutPrefix(s, "something/") if ok { // do something with short s } else { // do something else with long s } ``` There is also a [strings.CutSuffix](https://pkg.go.dev/strings#CutSuffix), and there are new [bytes](https://pkg.go.dev/bytes) versions of both. - - - - These are just a handful of [the many minor additions in Go 1.20](https://go.dev/doc/go1.20#minor_library_changes). There is still a lot more for someone to blog about like [Profiler Guided Optimization](https://go.dev/doc/pgo) or [runtime coverage testing](https://go.dev/testing/coverage/#running) and the usual compile time and garbage collection improvements, but whatever your favorite features are, all around it's a very solid release with a lot of substantive improvements.