diff --git a/.drone.yml b/.drone.yml index 0905067..6f757f6 100644 --- a/.drone.yml +++ b/.drone.yml @@ -2,12 +2,22 @@ kind: pipeline name: build & release steps: -- name: fetch +- name: fetch tags image: docker:git commands: - git fetch --tags + when: + event: tag +- name: test + image: golang:1.14-alpine + commands: + - go test -v . + when: + event: + exclude: + - tag - name: release - image: golang + image: golang:1.14-alpine environment: GITEA_TOKEN: from_secret: goreleaser_gitea_token diff --git a/.goreleaser.yml b/.goreleaser.yml index d6eead2..ecd0dac 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -1,5 +1,5 @@ builds: -- main: main.go +- main: . env: - CGO_ENABLED=0 goos: diff --git a/README.md b/README.md index be2304d..6baa191 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,27 @@ With 8 threads on Ryzen 1700X while searching for `::` this program reaches: * 100 000 000 iterations in 25 minutes, 58 seconds * 500 000 000 iterations in 2 hours, 10 minutes +This program contains some modded code from Yggdrasil that aims to improve +performance. If you prefer to use original Yggdrasil code, set `-original` +flag. + +### Usage + +``` +% syg_go -help +Usage of syg_go: + -iter uint + per how many iterations to output status (default 100000) + -original + use original Yggdrasil code + -regex string + regex to match addresses against (default "::") + -threads int + how many threads to use for mining (default 16) + -version + display version +``` + ### License See [LICENSE](LICENSE). diff --git a/crypto.go b/crypto.go new file mode 100644 index 0000000..bf40398 --- /dev/null +++ b/crypto.go @@ -0,0 +1,52 @@ +package main + +import ( + "github.com/yggdrasil-network/yggdrasil-go/src/address" + "github.com/yggdrasil-network/yggdrasil-go/src/crypto" +) + +// custom function selectors, see crypto_xxx.go +var ( + addrForNodeID func(*crypto.NodeID) *address.Address +) + +// AddrForNodeID is a variant of Yggdrasil's src/address.AddrForNodeID that +// might be slightly optimized for performance. +// +// This function is a modded variant of address.AddrForNodeID from Yggdrasil. +// See src/address/address.go@78b5f88e4bb734d0dd6a138ff08d34ca39dcaea3 +func AddrForNodeID(nid *crypto.NodeID) *address.Address { + // 128 bit address, begins with GetPrefix(), with last bit set to 0 + // (indicates an address). Next 7 bits, interpreted as a uint, are the count + // of leading 1s in the NodeID. Leading 1s and first leading 0 of the NodeID + // are truncated off. The rest is appended to the IPv6 address (truncated to + // 128 bits total). + var addr address.Address + temp := make([]byte, 0, len(nid)) + done := false + ones := byte(0) + bits := byte(0) + nBits := 0 + for idx := 0; idx < 8*len(nid); idx++ { + bit := (nid[idx/8] & (0x80 >> byte(idx%8))) >> byte(7-(idx%8)) + if !done && bit != 0 { + ones++ + continue + } + if !done && bit == 0 { + done = true + continue + } + bits = (bits << 1) | bit + nBits++ + if nBits == 8 { + nBits = 0 + temp = append(temp, bits) + } + } + prefix := address.GetPrefix() + copy(addr[:], prefix[:]) + addr[len(prefix)] = ones + copy(addr[len(prefix)+1:], temp) + return &addr +} diff --git a/crypto_test.go b/crypto_test.go new file mode 100644 index 0000000..90aa4a0 --- /dev/null +++ b/crypto_test.go @@ -0,0 +1,69 @@ +package main + +import ( + "net" + "os" + "regexp" + "testing" + + "github.com/yggdrasil-network/yggdrasil-go/src/address" + "github.com/yggdrasil-network/yggdrasil-go/src/crypto" +) + +var ( + testAddr *address.Address + testPub *crypto.BoxPubKey + testNodeID *crypto.NodeID + testRegex *regexp.Regexp +) + +func TestAddrForNodeID(t *testing.T) { + for i := 20; i > 0; i-- { + pub, _ := crypto.NewBoxKeys() + id := crypto.GetNodeID(pub) + origIP := net.IP(address.AddrForNodeID(id)[:]) + modIP := net.IP(AddrForNodeID(id)[:]) + if !origIP.Equal(modIP) { + t.Errorf("got %s, expected %s", modIP, origIP) + } + } +} + +func TestMain(m *testing.M) { + testPub, _ = crypto.NewBoxKeys() + testNodeID = crypto.GetNodeID(testPub) + testRegex = regexp.MustCompile("::") + os.Exit(m.Run()) +} + +func BenchmarkOrigAddrForNodeID(b *testing.B) { + for i := 0; i < b.N; i++ { + testAddr = address.AddrForNodeID(testNodeID) + } +} + +func BenchmarkModdedAddrForNodeID(b *testing.B) { + for i := 0; i < b.N; i++ { + testAddr = AddrForNodeID(testNodeID) + } +} + +// measures overall performance of code from cmd/genkeys +func BenchmarkOrigLoop(b *testing.B) { + for i := 0; i < b.N; i++ { + pub, _ := crypto.NewBoxKeys() + id := crypto.GetNodeID(pub) + ip := net.IP(address.AddrForNodeID(id)[:]).String() + testRegex.MatchString(ip) + } +} + +// measures overall performance of functions we vendor +func BenchmarkModdedLoop(b *testing.B) { + for i := 0; i < b.N; i++ { + pub, _ := crypto.NewBoxKeys() + id := crypto.GetNodeID(pub) + ip := net.IP(AddrForNodeID(id)[:]).String() + testRegex.MatchString(ip) + } +} diff --git a/main.go b/main.go index d0519ed..54b96be 100644 --- a/main.go +++ b/main.go @@ -20,19 +20,28 @@ import ( "github.com/yggdrasil-network/yggdrasil-go/src/crypto" ) -var version = "v0.1.0" +var version = "v0.1.1" func main() { rxflag := flag.String("regex", "::", "regex to match addresses against") threads := flag.Int("threads", runtime.GOMAXPROCS(0), "how many threads to use for mining") iterationsPerOutput := flag.Uint("iter", 100000, "per how many iterations to output status") displayVersion := flag.Bool("version", false, "display version") + origCode := flag.Bool("original", false, "use original Yggdrasil code") flag.Parse() if *displayVersion { println("syg_go", version) return } + if *origCode { + log.Println("using unmodified Yggdrasil code") + addrForNodeID = address.AddrForNodeID + } else { + log.Println("using syg_go vendored code") + addrForNodeID = AddrForNodeID + } + regex, err := regexp.Compile(*rxflag) if err != nil { log.Printf("%v\n", err) @@ -74,7 +83,7 @@ func doBoxKeys(out chan<- keySet) { for { pub, priv := crypto.NewBoxKeys() id := crypto.GetNodeID(pub) - ip := net.IP(address.AddrForNodeID(id)[:]).String() + ip := net.IP(addrForNodeID(id)[:]).String() out <- keySet{priv[:], pub[:], id[:], ip} } }