From 3ea5c212ef53fa9a8538482fc2427f9fb057e8cc Mon Sep 17 00:00:00 2001 From: Kevin Atkinson Date: Thu, 26 Jul 2018 12:49:34 -0400 Subject: [PATCH 1/5] Add maps for converting from the string repr. to the code and back. --- multibase.go | 45 ++++++++++++++++++++++++++++++++++++++++++++- multibase_test.go | 15 +++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/multibase.go b/multibase.go index 4650376..478fa6d 100644 --- a/multibase.go +++ b/multibase.go @@ -12,7 +12,8 @@ import ( // Encoding identifies the type of base-encoding that a multibase is carrying. type Encoding int -// These are the supported encodings +// These are the encodings specified in the standard, not are all +// supported yet const ( Identity = 0x00 Base1 = '1' @@ -37,6 +38,48 @@ const ( Base64urlPad = 'U' ) +// Encodigs is a map of the supported encoding, unsupported encoding +// specified in standard are left out +var Encodings = map[string]Encoding{ + "identity": 0x00, + "base16": 'f', + "base16upper": 'F', + "base32": 'b', + "base32upper": 'B', + "base32pad": 'c', + "base32padupper": 'C', + "base32hex": 'v', + "base32hexupper": 'V', + "base32hexpad": 't', + "base32hexpadupper": 'T', + "base58flickr": 'Z', + "base58btc": 'z', + "base64": 'm', + "base64url": 'u', + "base64pad": 'M', + "base64urlpad": 'U', +} + +var EncodingToStr = map[Encoding]string{ + 0x00: "identity", + 'f': "base16", + 'F': "base16upper", + 'b': "base32", + 'B': "base32upper", + 'c': "base32pad", + 'C': "base32padupper", + 'v': "base32hex", + 'V': "base32hexupper", + 't': "base32hexpad", + 'T': "base32hexpadupper", + 'Z': "base58flickr", + 'z': "base58btc", + 'm': "base64", + 'u': "base64url", + 'M': "base64pad", + 'U': "base64urlpad", +} + // ErrUnsupportedEncoding is returned when the selected encoding is not known or // implemented. var ErrUnsupportedEncoding = fmt.Errorf("selected encoding not supported") diff --git a/multibase_test.go b/multibase_test.go index a69d721..0b490df 100644 --- a/multibase_test.go +++ b/multibase_test.go @@ -6,6 +6,21 @@ import ( "testing" ) +func TestMap(t *testing.T) { + for s,e := range Encodings { + s2 := EncodingToStr[e] + if s != s2 { + t.Errorf("round trip failed on encoding map: %s != %s", s, s2) + } + } + for e,s := range EncodingToStr { + e2 := Encodings[s] + if e != e2 { + t.Errorf("round trip failed on encoding map: '%c' != '%c'", e, e2) + } + } +} + var sampleBytes = []byte("Decentralize everything!!!") var encodedSamples = map[Encoding]string{ Identity: string(0x00) + "Decentralize everything!!!", From a0557075ec3c84e6dd18d13aca6596ca3a7ed689 Mon Sep 17 00:00:00 2001 From: Kevin Atkinson Date: Thu, 26 Jul 2018 12:50:11 -0400 Subject: [PATCH 2/5] Add prefix type that guarantees a valid multibase prefix. --- prefix.go | 28 ++++++++++++++++++++++++++++ prefix_test.go | 29 +++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 prefix.go create mode 100644 prefix_test.go diff --git a/prefix.go b/prefix.go new file mode 100644 index 0000000..92ad4f8 --- /dev/null +++ b/prefix.go @@ -0,0 +1,28 @@ +package multibase + +import () + +type Prefix struct { + enc Encoding +} + +func NewPrefix(e Encoding) (Prefix, error) { + _, err := Encode(e, nil) + if err != nil { + return Prefix{-1}, err + } + return Prefix{e}, nil +} + +func (p Prefix) Encoding() Encoding { + return p.enc +} + +func (p Prefix) Encode(data []byte) string { + str, err := Encode(p.enc, data) + if err != nil { + // should not happen + panic(err) + } + return str +} diff --git a/prefix_test.go b/prefix_test.go new file mode 100644 index 0000000..e0214cd --- /dev/null +++ b/prefix_test.go @@ -0,0 +1,29 @@ +package multibase + +import ( + "testing" +) + +func TestInvalidPrefix(t *testing.T) { + _, err := NewPrefix('q') + if err == nil { + t.Error("expected failure") + } +} + +func TestPrefix(t *testing.T) { + for _, base := range Encodings { + prefix,err := NewPrefix(base) + if err != nil { + t.Fatalf("NewPrefix(%c) failed: %v", base, err) + } + str1, err := Encode(base, sampleBytes) + if err != nil { + t.Fatal(err) + } + str2 := prefix.Encode(sampleBytes) + if str1 != str2 { + t.Errorf("encoded string mismatch: %s != %s", str1, str2) + } + } +} From 5547437445411666f064d2dc37447ed96764402a Mon Sep 17 00:00:00 2001 From: Kevin Atkinson Date: Thu, 26 Jul 2018 17:57:34 -0400 Subject: [PATCH 3/5] Enhance constructor for Prefix type. --- prefix.go | 48 ++++++++++++++++++++++++++++++++++++++++++------ prefix_test.go | 15 +++++++++++++-- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/prefix.go b/prefix.go index 92ad4f8..bdf2f1d 100644 --- a/prefix.go +++ b/prefix.go @@ -1,23 +1,59 @@ package multibase -import () +import ( + "fmt" +) +// Prefix is a multibase encoding that is verified to be supported and +// supports an Encode method that does not return an error type Prefix struct { enc Encoding } -func NewPrefix(e Encoding) (Prefix, error) { - _, err := Encode(e, nil) - if err != nil { - return Prefix{-1}, err +// NewPrefix create a new Prefix type from either an Encoding or a +// string. If nil or an empty string the default base (currently +// Base58BTC) will be used. +func NewPrefix(e interface{}) (Prefix, error) { + base := Encoding(Base58BTC) + switch v := e.(type) { + case byte: + base = Encoding(v) + case rune: + base = Encoding(v) + case int: + base = Encoding(v) + case Encoding: + base = v + case string: + ok := true + // note: if empty string use default value + if len(v) == 1 { + base = Encoding(v[0]) + _, ok = EncodingToStr[base] + } else if len(v) > 1 { + base, ok = Encodings[v] + } + if !ok { + return Prefix{-1}, fmt.Errorf("Unsupported multibase encoding: %s", v) + } + return Prefix{base}, nil + case nil: + /* use default value */ + default: + return Prefix{-1}, fmt.Errorf("Unsupported parameter type.") } - return Prefix{e}, nil + _, ok := EncodingToStr[base] + if !ok { + return Prefix{-1}, fmt.Errorf("Unsupported multibase encoding: %d", base) + } + return Prefix{base}, nil } func (p Prefix) Encoding() Encoding { return p.enc } +// Encode encodes the multibase using the given Prefix. func (p Prefix) Encode(data []byte) string { str, err := Encode(p.enc, data) if err != nil { diff --git a/prefix_test.go b/prefix_test.go index e0214cd..642b9f4 100644 --- a/prefix_test.go +++ b/prefix_test.go @@ -12,8 +12,15 @@ func TestInvalidPrefix(t *testing.T) { } func TestPrefix(t *testing.T) { - for _, base := range Encodings { - prefix,err := NewPrefix(base) + prefix,err := NewPrefix(nil) + if err != nil { + t.Fatal(err) + } + if prefix.Encoding() != Base58BTC { + t.Error("unexpected default encoding") + } + for str, base := range Encodings { + prefix,err = NewPrefix(base) if err != nil { t.Fatalf("NewPrefix(%c) failed: %v", base, err) } @@ -25,5 +32,9 @@ func TestPrefix(t *testing.T) { if str1 != str2 { t.Errorf("encoded string mismatch: %s != %s", str1, str2) } + _, err = NewPrefix(str) + if err != nil { + t.Fatalf("NewPrefix(%s) failed: %v", str, err) + } } } From 2eb83a994b4e7de6aacdcf6f29b7bd497d0774e8 Mon Sep 17 00:00:00 2001 From: Kevin Atkinson Date: Thu, 26 Jul 2018 20:55:47 -0400 Subject: [PATCH 4/5] Remove "magical" NewPrefix function, rename Prefix to Encoder. --- encoder.go | 53 +++++++++++++++++++++++++ prefix_test.go => encoder_test.go | 17 +++----- prefix.go | 64 ------------------------------- 3 files changed, 58 insertions(+), 76 deletions(-) create mode 100644 encoder.go rename prefix_test.go => encoder_test.go (57%) delete mode 100644 prefix.go diff --git a/encoder.go b/encoder.go new file mode 100644 index 0000000..d1f87f0 --- /dev/null +++ b/encoder.go @@ -0,0 +1,53 @@ +package multibase + +import ( + "fmt" +) + +// Encoder is a multibase encoding that is verified to be supported and +// supports an Encode method that does not return an error +type Encoder struct { + enc Encoding +} + +// NewEncoder create a new Encoder from an Encoding +func NewEncoder(base Encoding) (Encoder, error) { + _, ok := EncodingToStr[base] + if !ok { + return Encoder{-1}, fmt.Errorf("Unsupported multibase encoding: %d", base) + } + return Encoder{base}, nil +} + +// EncoderByName creates an encoder from a string, the string can +// either be the multibase name or single character multibase prefix +func EncoderByName(str string) (Encoder, error) { + var base Encoding + ok := true + if len(str) == 0 { + return Encoder{-1}, fmt.Errorf("Empty multibase encoding") + } else if len(str) == 1 { + base = Encoding(str[0]) + _, ok = EncodingToStr[base] + } else { + base, ok = Encodings[str] + } + if !ok { + return Encoder{-1}, fmt.Errorf("Unsupported multibase encoding: %s", str) + } + return Encoder{base}, nil +} + +func (p Encoder) Encoding() Encoding { + return p.enc +} + +// Encode encodes the multibase using the given Encoder. +func (p Encoder) Encode(data []byte) string { + str, err := Encode(p.enc, data) + if err != nil { + // should not happen + panic(err) + } + return str +} diff --git a/prefix_test.go b/encoder_test.go similarity index 57% rename from prefix_test.go rename to encoder_test.go index 642b9f4..714ba02 100644 --- a/prefix_test.go +++ b/encoder_test.go @@ -5,24 +5,17 @@ import ( ) func TestInvalidPrefix(t *testing.T) { - _, err := NewPrefix('q') + _, err := NewEncoder('q') if err == nil { t.Error("expected failure") } } func TestPrefix(t *testing.T) { - prefix,err := NewPrefix(nil) - if err != nil { - t.Fatal(err) - } - if prefix.Encoding() != Base58BTC { - t.Error("unexpected default encoding") - } for str, base := range Encodings { - prefix,err = NewPrefix(base) + prefix, err := NewEncoder(base) if err != nil { - t.Fatalf("NewPrefix(%c) failed: %v", base, err) + t.Fatalf("NewEncoder(%c) failed: %v", base, err) } str1, err := Encode(base, sampleBytes) if err != nil { @@ -32,9 +25,9 @@ func TestPrefix(t *testing.T) { if str1 != str2 { t.Errorf("encoded string mismatch: %s != %s", str1, str2) } - _, err = NewPrefix(str) + _, err = EncoderByName(str) if err != nil { - t.Fatalf("NewPrefix(%s) failed: %v", str, err) + t.Fatalf("NewEncoder(%s) failed: %v", str, err) } } } diff --git a/prefix.go b/prefix.go deleted file mode 100644 index bdf2f1d..0000000 --- a/prefix.go +++ /dev/null @@ -1,64 +0,0 @@ -package multibase - -import ( - "fmt" -) - -// Prefix is a multibase encoding that is verified to be supported and -// supports an Encode method that does not return an error -type Prefix struct { - enc Encoding -} - -// NewPrefix create a new Prefix type from either an Encoding or a -// string. If nil or an empty string the default base (currently -// Base58BTC) will be used. -func NewPrefix(e interface{}) (Prefix, error) { - base := Encoding(Base58BTC) - switch v := e.(type) { - case byte: - base = Encoding(v) - case rune: - base = Encoding(v) - case int: - base = Encoding(v) - case Encoding: - base = v - case string: - ok := true - // note: if empty string use default value - if len(v) == 1 { - base = Encoding(v[0]) - _, ok = EncodingToStr[base] - } else if len(v) > 1 { - base, ok = Encodings[v] - } - if !ok { - return Prefix{-1}, fmt.Errorf("Unsupported multibase encoding: %s", v) - } - return Prefix{base}, nil - case nil: - /* use default value */ - default: - return Prefix{-1}, fmt.Errorf("Unsupported parameter type.") - } - _, ok := EncodingToStr[base] - if !ok { - return Prefix{-1}, fmt.Errorf("Unsupported multibase encoding: %d", base) - } - return Prefix{base}, nil -} - -func (p Prefix) Encoding() Encoding { - return p.enc -} - -// Encode encodes the multibase using the given Prefix. -func (p Prefix) Encode(data []byte) string { - str, err := Encode(p.enc, data) - if err != nil { - // should not happen - panic(err) - } - return str -} From 03643c33f599787d11414f8c54d83960233a0ae0 Mon Sep 17 00:00:00 2001 From: Steven Allen Date: Fri, 27 Jul 2018 13:48:06 -0700 Subject: [PATCH 5/5] ci: bump minimum go version --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 3cb0758..7462824 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ os: language: go go: - - 1.8.3 + - 1.10.2 install: - go get -u github.com/whyrusleeping/gx