From 0a49bd57bbe87f74b26d34318c86d0638bb381e9 Mon Sep 17 00:00:00 2001 From: Gowtham Gopalakrishnan Date: Sun, 10 Feb 2019 16:41:02 +0530 Subject: [PATCH] added base2 implementation as per RFC --- base2.go | 55 +++++++++++++++++++++++++++++++++++++++++++++++ multibase.go | 7 ++++++ multibase_test.go | 2 ++ 3 files changed, 64 insertions(+) create mode 100644 base2.go diff --git a/base2.go b/base2.go new file mode 100644 index 0000000..7924467 --- /dev/null +++ b/base2.go @@ -0,0 +1,55 @@ +package multibase + +import ( + "fmt" + "math" + "strconv" +) + +// binaryEncodeToString takes an array of bytes and returns +// multibase binary representation +func binaryEncodeToString(src []byte) string { + dst := make([]byte, len(src)*8) + encodeBinary(dst, src) + return string(dst) +} + +// encodeBinary takes the src and dst bytes and converts each +// byte to their binary rep using power reduction method +func encodeBinary(dst []byte, src []byte) { + for i := 0; i < len(src); i++ { + t := src[i] + for j := i * 8; j < (i*8)+8; j++ { + higherPower := math.Pow(2, float64(7-(j%8))) + if float64(t) >= higherPower { + dst[j] = '1' + t = t - byte(higherPower) + } else { + dst[j] = '0' + } + } + } +} + +// decodeBinaryString takes multibase binary representation +// and returns a byte array +func decodeBinaryString(s string) ([]byte, error) { + if len(s) % 8 != 0 { + return nil, fmt.Errorf("cannot decode multibase: %s", + "length should be a multiple of 4") + } + + data := make([]byte, len(s)/8) + + for i, dstIndex := 0, 0; i < len(s); i = i + 8 { + value, err := strconv.ParseInt(s[i:i+8], 2, 0) + if err != nil { + return nil, fmt.Errorf("error while conversion: %s", err) + } + + data[dstIndex] = byte(value) + dstIndex++ + } + + return data, nil +} diff --git a/multibase.go b/multibase.go index 38cbfb8..ccf3232 100644 --- a/multibase.go +++ b/multibase.go @@ -42,6 +42,7 @@ const ( // specified in standard are left out var Encodings = map[string]Encoding{ "identity": 0x00, + "base2": '0', "base16": 'f', "base16upper": 'F', "base32": 'b', @@ -62,6 +63,7 @@ var Encodings = map[string]Encoding{ var EncodingToStr = map[Encoding]string{ 0x00: "identity", + '0': "base2", 'f': "base16", 'F': "base16upper", 'b': "base32", @@ -92,6 +94,8 @@ func Encode(base Encoding, data []byte) (string, error) { case Identity: // 0x00 inside a string is OK in golang and causes no problems with the length calculation. return string(Identity) + string(data), nil + case Base2: + return string(Base2) + binaryEncodeToString(data), nil case Base16: return string(Base16) + hex.EncodeToString(data), nil case Base16Upper: @@ -141,6 +145,9 @@ func Decode(data string) (Encoding, []byte, error) { switch enc { case Identity: return Identity, []byte(data[1:]), nil + case Base2: + bytes, err := decodeBinaryString(data[1:]) + return enc, bytes, err case Base16, Base16Upper: bytes, err := hex.DecodeString(data[1:]) return enc, bytes, err diff --git a/multibase_test.go b/multibase_test.go index f389f5c..b0f4ce8 100644 --- a/multibase_test.go +++ b/multibase_test.go @@ -24,6 +24,7 @@ func TestMap(t *testing.T) { var sampleBytes = []byte("Decentralize everything!!!") var encodedSamples = map[Encoding]string{ Identity: string(0x00) + "Decentralize everything!!!", + Base2: "00100010001100101011000110110010101101110011101000111001001100001011011000110100101111010011001010010000001100101011101100110010101110010011110010111010001101000011010010110111001100111001000010010000100100001", Base16: "f446563656e7472616c697a652065766572797468696e67212121", Base16Upper: "F446563656E7472616C697A652065766572797468696E67212121", Base32: "birswgzloorzgc3djpjssazlwmvzhs5dinfxgoijbee", @@ -117,6 +118,7 @@ func BenchmarkRoundTrip(b *testing.B) { bases := map[string]Encoding{ "Identity": Identity, + "Base2": Base2, "Base16": Base16, "Base16Upper": Base16Upper, "Base32": Base32,