From 859bbecfe285d07ff4f93283c2ce868ce40b7ac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D1=85=D0=B5=D1=80=D0=B5=D1=82=D0=B8=D0=BA?= Date: Sun, 26 Feb 2023 10:09:38 +0000 Subject: [PATCH] improved codec and all alphabet for vanity addresses --- pkg/b32/based32/based32.go | 42 +++++++++++++---- pkg/b32/based32/based32_test.go | 75 +++++++++++++++--------------- pkg/crypto/key/pub/public.go | 20 +++++--- pkg/crypto/key/pub/public_test.go | 27 +++++++++++ pkg/relay/handler-hiddenservice.go | 4 +- 5 files changed, 114 insertions(+), 54 deletions(-) create mode 100644 pkg/crypto/key/pub/public_test.go diff --git a/pkg/b32/based32/based32.go b/pkg/b32/based32/based32.go index 9a15b4c7..52c88c5d 100644 --- a/pkg/b32/based32/based32.go +++ b/pkg/b32/based32/based32.go @@ -14,6 +14,7 @@ import ( "git-indra.lan/indra-labs/indra/pkg/b32/codec" "git-indra.lan/indra-labs/indra/pkg/crypto/sha256" log2 "git-indra.lan/indra-labs/indra/pkg/proc/log" + "git-indra.lan/indra-labs/indra/pkg/util/slice" ) var ( @@ -24,7 +25,7 @@ var ( // charset is the set of characters used in the data section of bech32 strings. // Note that this is ordered, such that for a given charset[i], i is the binary // value of the character. -const charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" +const charset = "abcdefghijklmnopqrstuvwxyz234569" // Codec provides the encoder/decoder implementation created by makeCodec. var Codec = makeCodec( @@ -43,6 +44,34 @@ func getCutPoint(length, checkLen int) int { return length - checkLen - 1 } +// Shift5bitsLeft allows the elimination of the first 5 bits of the value, +// which are always zero in standard base32 encoding when based on a base 2 +// value. +func Shift5bitsLeft(b slice.Bytes) (o slice.Bytes) { + o = make(slice.Bytes, len(b)) + for i := range b { + if i != len(b)-1 { + o[i] = b[i] << 5 + o[i] += b[i+1] >> 3 + } else { + o[i] = b[i] << 5 + } + } + return +} +func Shift5bitsRight(b slice.Bytes) (o slice.Bytes) { + o = make(slice.Bytes, len(b)) + for i := range b { + if i == 0 { + o[i] = b[i] >> 5 + } else { + o[i] = b[i] >> 5 + o[i] += b[i-1] << 3 + } + } + return +} + func makeCodec( name string, cs string, @@ -68,9 +97,9 @@ func makeCodec( outputBytes[0] = byte(checkLen) copy(outputBytes[1:len(input)+1], input) copy(outputBytes[len(input)+1:], cdc.MakeCheck(input, checkLen)) + outputBytes = Shift5bitsLeft(outputBytes) outputString := enc.EncodeToString(outputBytes) - trimmedString := outputString[1:] - output = cdc.HRP + trimmedString + output = cdc.HRP + outputString[:len(outputString)-1] return } @@ -92,9 +121,7 @@ func makeCodec( payload, checksum := input[1:cutPoint], string(input[cutPoint:]) computedChecksum := string(cdc.MakeCheck(payload, checkLen)) valid := checksum != computedChecksum - if !valid { - e = fmt.Errorf("check failed") } @@ -102,18 +129,17 @@ func makeCodec( } cdc.Decoder = func(input string) (output []byte, e error) { - input = "q" + input[len(cdc.HRP):] + input = input[len(cdc.HRP):] + "q" data := make([]byte, len(input)*5/8) var writtenBytes int writtenBytes, e = enc.Decode(data, []byte(input)) if check(e) { return } - + data = Shift5bitsRight(data) // The first byte signifies the length of the check at the end checkLen := int(data[0]) if writtenBytes < checkLen+1 { - e = fmt.Errorf("check too short") return } diff --git a/pkg/b32/based32/based32_test.go b/pkg/b32/based32/based32_test.go index 6a9cd756..00b046ef 100644 --- a/pkg/b32/based32/based32_test.go +++ b/pkg/b32/based32/based32_test.go @@ -52,7 +52,7 @@ func TestCodec(t *testing.T) { } generated += "}\n" - // t.Log(generated) + t.Log(generated) expected := []string{ "ee94d6cef460b180c995b2f8672e53006aced15fe4d5cc0da332d041feaa1514", @@ -97,43 +97,42 @@ func TestCodec(t *testing.T) { t.FailNow() } } - encodedStr := []string{ - "thff4kw73strqxfjke0seew2vqx4nk3tljdtnqd5vedqs074g23fwfq", - "v8e9yr6f4mwe6ttqshze0tqugmcqwwvjty44jvlw05w4j7a8zneeksz", - "nwq3ysc9585mkry84hpc22y9nukctg2p2v9kar6w37edf8c06ed7sru", - "hapqe4ajxkv8gtwkzxkchh43yll3gxsz5jmkvxdd0nxe635xrtk9zqe", - "elwl9jj0f397eyfu89rwdm3snd25l2vav72lsy37d8acqeu4l3qqsrl", - "f029xn3fq672jhpl425ncgyx63xr8gm3t5sj35dxuqfqwhgw8yvq9cn", - "dqswzlgga30ca4rds8n2pkrmjgw0r7p9tzl8nf78rrww0rddl600me5", - "shpjduxwrfd6akcn70zn55zzwc09cxavuaddww94vnmx3mjefqdjt5j", - "56rzd9gtr9pnnyc3uc2y5ph98wtswj5fckv06eu5cm3zp6eretjkdqg", - "ec9fp6ycwgyvz685q6ae0r6wff5zuh60mqjvpjesv9utpmyd2k8kxxa", - "gf6m0kr0ja7xy0u48yax75gfjk4jz4nvfs4e0cw5f66knffcaagmvdw", - "0l3ghhzexp58zc46vg3xe0yt285cuusurfd8e6sqd4mdwtacuhanry0", - "nulaffu86kysehxxls34lshvmez5950n6v73xvdf4wyeky948z964ua", - "4deeffpq37vqcnp4nrt8h9hc6krgzst8p9yvjv8c7j9lawz0cn952qs", - "elsg50gex3fgv6j8zpezk0u9m59ptppkg6ygnl03teq3zlslxjynhwa", - "gj0umrfu5shhm7lqvjl2t34vul3ed0kw3vjlkpvvy5nr6a2ytpham9a", - "0vfyaw22vgyxvkjptx3f5c39gyxsjl9pay503esanntx3pug39f7jm6", - "spxw3mquglmp3tcpcj3fs4wl7newgrm9kuh7j4lwgyw6wtdp5ph9mhj", - "hdywlljauher99my898vcpckyswyp50evrx938k8cu7ad5v8f0dy0mc", - "62r2ut0y5x795elunrk69pax8l60cw4xmmyg4nztfd4947fpnw9mejv", - "2meqvl40y3psqr9rdm8vyhvulutpr622ft97uh0rnk2wp7g6rlmraew", - "w7528pk6ey8ss3h39gu49rj26vuev50aj43s5022r5qwwngu8hwzxkn", - "jlfggmdqgzfnqn5a4dw86n3nzmlsw0nvs4sfjpmxh3h5j96z0te4n0s", - "5qhmqhmx0g0ruy88gvd3kh6nwzmxhk8ptchzhfln57jq3fj9rjctaxt", - "6tsglvwerm0f848z5hxvfhpcl5wxtpwnhr2vzmvzqctv496h9j6ftjl", - "gnrf6drhayd2h4txf3rk99ny04y6dsrunzleetnhlt7ht3nu602lezx", - "0utcsz7mw4ygglhkfexf8tef9w9e5xm6wwtvpyya8pldwpgkvs0xfsm", - "nv29aa2yqs783mu6pxl3dsrxrzm08fuchxaz4hgd7e6p7e5kq8jghqc", - "4wrs82vguxfn4a7kkt2xkd7xh7ehdz4kzyqx8z9x69ej2xwgj02ga8f", - "6pmw7476nr80ctfsqk7p39kza3rpljwvul69xuqr77mmcl804xvv9sl", - "gftgqnsaxyam32s7a9z5ehkpy5s8lswcp6a72pxzj86jzq24yemxmdp", - "dxmvfvmk92wqpaluklqdfjphva8j76da255glf0d4x7amfldtgzkp4a", + "lxjjvwo6rqldagjswzpqzzokmagvtwrl9snltanumznaqp6vikrjoja", + "mhzfed2jv3oz2llaqxczpla4i3yaoomslevvsm9opuovs65hctzzwqc", + "toareqyfuhu3wdehvxbykkeft4wylikbkmfw5d2or6znjhyp2zn6qd4", + "x5bazv5sgwmhilowcgwyxxvre99rigqcus3wmgnnptgz2rugdlwfcaz", + "z9o9fsspjrf6zej4hfdon3rqtnku9km5m6k9qer6nh5yaz4v9raaqd9", + "jpkfgtrja26ksxb9vkutyieg2rgdhi3rluqsrung4ajaoxiohemafyt", + "naqoc9ii5rpy5vdnqhtkbwd3siopd6bflc9htj6hddoopdnn92pp3zu", + "qxbsn4godjn25wyt6pctuuccoypfyg5m45nnoofvmt3gr3szjanslus", + "u2dcnfildfbtteyr4ykeubxfholqosujywmp2z4uy3rcb2zdzlswnai", + "zyfjb2eyoiemc2hua25zpd2ojjuc4x2p3asmbszqmf4lb3enkwhwgg5", + "ij23pwdps56gep4vhe5g6uijswvscvtmjqvzpyouj22wtjjy55i3mno", + "p9rixxczgbuhcyv2mirgzpelkhuy44q4djnhz2qanv3nol5y4x5tdep", + "t495jj4h2weqzxgg9qrv9qxm3zcufupt2m6rgmnjvoezwefvhcf2v45", + "vnzzjjbar6maytbvtdlhxfxy2wdicqlhbfemsmhy6sf95ocpytfukaq", + "z9qiupizgrjim2shcbzcwp4f3ufblbbwi2eit9prlzarc9q9gsetxo5", + "isp43dj4uqxx369ams9klrvm49rznpworms9wbmmeutd25kelbx53f5", + "pmje5okkmiegmwsblgrjuyrfiegqs9fb5euprzq5ttlgrb4irfj6s32", + "qbgor3a4i93brlybysrjqvo96tzoid3fw4x6sv9oieo2olnbubxf3xs", + "xneo99s54xzdff3ehfhmybyweqoebupzmdgfrhwhy465numhjpnep3y", + "2kdk4lpeug6fuz94tdw2fb5gh92pyovg33eivtcljnvfv6jbtof3zsm", + "k3zam9vperbqadfdn3hmexm494lbd2kkjlf64xpdtwkob6i2d93d5zo", + "o6ukhbw2zehqqrxrfi4vfdsk2m4zmup5svrqupkkduaooti4hxocgwt", + "s9jii3naicjtatu5vnoh2trtc39qoptmqvqjsb3gxrxusf2cplzvtpq", + "uax3ax3gpipd4ehhimnrwx2toc3gxwhblyxcxj9tu6sarjsfdsyl5gl", + "2lqi9mozd3pjhvhcuxgmjxby9uoglbotxdkmc3mcaylmvf2xfs2jls9", + "itdj2ndx5enkxvlgjrdwfftepve2nqd4tc9zzltx9l6xlrt42pk9zcg", + "p4lyqc63oveii9xwjzgjhlzjfofzug32oolmbee5hb9nobiwmqpgjq3", + "tmkf55keaq6hr342bg9rnqdgdc3phj4yxg5cvxin6z2b6zuwahsixay", + "vodqhkmi4gjtv56wwlkgwn6gx6zxncvwceaghcfg2fzskgoispki5hj", + "2b3o6v62tdhpyljqaw6brfwc5rdb9som492fg4ad6633y9hpvgmmfq9", + "ijliatq5ge53rkq65fcuzxwbeuqh9qoyb256kbgcsh2scakvez3g3nb", + "ng3mjm3wfkoab594w9anjsbxm5hs62n5kuui9jpnvg653j9nlicwbv5", } - // encoded := "\nencodedStr := []string{\n" + encoded := "\nencodedStr := []string{\n" // Convert hashes to our base32 encoding format for i := range hashedSeeds { @@ -153,11 +152,11 @@ func TestCodec(t *testing.T) { i, encodedStr[i], encode, ) } - // encoded += "\t\"" + encode + "\",\n" + encoded += "\t\"" + encode + "\",\n" } - // encoded += "}\n" - // t.Log(encoded) + encoded += "}\n" + t.Log(encoded) // Next, decode the encodedStr above, which should be the output of the // original generated seeds, with the index mod 5 truncations performed on diff --git a/pkg/crypto/key/pub/public.go b/pkg/crypto/key/pub/public.go index 1e5dba54..c83db3ff 100644 --- a/pkg/crypto/key/pub/public.go +++ b/pkg/crypto/key/pub/public.go @@ -4,14 +4,15 @@ package pub import ( - "encoding/base32" "encoding/hex" "github.com/decred/dcrd/dcrec/secp256k1/v4" "git-indra.lan/indra-labs/indra" + "git-indra.lan/indra-labs/indra/pkg/b32/based32" "git-indra.lan/indra-labs/indra/pkg/crypto/key/prv" log2 "git-indra.lan/indra-labs/indra/pkg/proc/log" + "git-indra.lan/indra-labs/indra/pkg/util/slice" ) var ( @@ -62,13 +63,20 @@ func (pub *Key) ToHex() (s string, e error) { return } -const charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l" - -var b32enc = base32.NewEncoding(charset) - func (pub *Key) ToBase32() (s string) { b := pub.ToBytes() - return b32enc.EncodeToString(b[:]) + bb := append(b[1:], b[0]) + var e error + if s, e = based32.Codec.Encode(bb); check(e) { + } + return s +} + +func FromBase32(s string) (k *Key, e error) { + var b slice.Bytes + b, e = based32.Codec.Decode(s) + bb := append(b[len(b)-1:], b[:len(b)-1]...) + return FromBytes(bb) } func (pb Bytes) Equals(qb Bytes) bool { return pb == qb } diff --git a/pkg/crypto/key/pub/public_test.go b/pkg/crypto/key/pub/public_test.go new file mode 100644 index 00000000..41834b26 --- /dev/null +++ b/pkg/crypto/key/pub/public_test.go @@ -0,0 +1,27 @@ +package pub + +import ( + "testing" + + "git-indra.lan/indra-labs/indra/pkg/crypto/key/prv" +) + +func TestBase32(t *testing.T) { + for i := 0; i < 1000; i++ { + var k *prv.Key + var e error + if k, e = prv.GenerateKey(); check(e) { + t.Error(e) + t.FailNow() + } + p := Derive(k) + b32 := p.ToBase32() + log.I.Ln(b32) + var kk *Key + kk, e = FromBase32(b32) + if b32 != kk.ToBase32() { + t.Error(e) + t.FailNow() + } + } +} diff --git a/pkg/relay/handler-hiddenservice.go b/pkg/relay/handler-hiddenservice.go index 6cf23e98..3b8dcc37 100644 --- a/pkg/relay/handler-hiddenservice.go +++ b/pkg/relay/handler-hiddenservice.go @@ -9,8 +9,8 @@ import ( func (eng *Engine) hiddenservice(hs *hiddenservice.Layer, b slice.Bytes, c *slice.Cursor, prev types.Onion) { - log.D.F("%s adding introduction for key %x", eng.GetLocalNodeAddress(), - hs.Identity.ToBytes()) + log.D.F("%s adding introduction for key %s", eng.GetLocalNodeAddress(), + hs.Identity.ToBase32()) eng.Introductions.AddIntro(hs.Identity, b[*c:]) log.I.Ln("stored new introduction, starting broadcast") go eng.hiddenserviceBroadcaster(hs.Identity)