16 Commits

Author SHA1 Message Date
Jakub Sztandera
d63641945d Merge pull request #29 from multiformats/feat/gomod
Switch to multiformats/go-base32, introduce gomod
2019-02-27 13:28:37 +01:00
Jakub Sztandera
79803cc6b5 Merge pull request #27 from multiformats/fix/captain
README: remove out-of-date captain
2019-02-27 13:24:41 +01:00
Jakub Sztandera
4819336788 Switch to multiformats/go-base32, introduce gomod 2019-02-26 19:54:23 +01:00
Steven Allen
f25b77813c Merge pull request #28 from gowthamgts/base2
Added base2 implementation as per RFC
2019-02-18 18:49:39 -08:00
Gowtham Gopalakrishnan
be9178df09 changed shifting logic 2019-02-17 12:13:57 +05:30
Gowtham Gopalakrishnan
f7396abfab bitwise ops and left padding added 2019-02-14 19:34:11 +05:30
Gowtham Gopalakrishnan
fca1c65daf go fmt base2.go 2019-02-10 16:49:34 +05:30
Gowtham Gopalakrishnan
0a49bd57bb added base2 implementation as per RFC 2019-02-10 16:41:02 +05:30
Steven Allen
5d43951a20 README: remove out-of-date captain 2018-12-10 13:16:20 -08:00
Steven Allen
4cd2fef284 Merge pull request #24 from multiformats/testing/test-vectors
test against spec
2018-11-27 18:45:57 -08:00
Steven Allen
916e8af3d6 ci: standardize
* Add makfile
* Use standard CI scripts.
2018-11-27 18:44:08 -08:00
Steven Allen
007b57d388 Merge pull request #25 from gowthamgts/master
Typo fix and readibility improvements
2018-11-17 10:16:56 -08:00
Gowtham Gopalakrishnan
3cdc462d3f Typo fix and readibility improvements 2018-11-17 19:59:15 +05:30
Steven Allen
5b7719f2f5 test implementation against test-vectors 2018-11-15 15:25:58 -08:00
Steven Allen
c53ff45d4d gx: ignore tests when publishing as well 2018-11-15 15:25:51 -08:00
Steven Allen
8ab2e3688b add the spec as a submodule 2018-11-15 15:25:49 -08:00
16 changed files with 271 additions and 31 deletions

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "spec"]
path = spec
url = https://github.com/multiformats/multibase.git

2
.gxignore Normal file
View File

@@ -0,0 +1,2 @@
/spec/
*_test.go

View File

@@ -1,25 +1,32 @@
os:
- linux
- linux
language: go
go:
- 1.10.2
- 1.11.x
env:
global:
- GOTFLAGS="-race"
matrix:
- BUILD_DEPTYPE=gx
- BUILD_DEPTYPE=gomod
# disable travis install
install:
- go get -u github.com/whyrusleeping/gx
- go get -u github.com/whyrusleeping/gx-go
- gx install
- true
script:
- gx-go rewrite
- go test -race -coverprofile=unittest.coverprofile -covermode=atomic .
- bash <(curl -s https://raw.githubusercontent.com/ipfs/ci-helpers/master/travis-ci/run-standard-tests.sh)
after_success:
- bash <(curl -s https://codecov.io/bash) -f unittest.coverprofile -F unittest
cache:
directories:
- $GOPATH/src/gx
directories:
- $GOPATH/src/gx
- $GOPATH/pkg/mod
- /home/travis/.cache/go-build
notifications:
email: false

13
Makefile Normal file
View File

@@ -0,0 +1,13 @@
test: deps
go test -race -v ./...
export IPFS_API ?= v04x.ipfs.io
gx:
go get -u github.com/whyrusleeping/gx
go get -u github.com/whyrusleeping/gx-go
deps: gx
gx --verbose install --global
gx-go rewrite
go get -t ./...

View File

@@ -36,10 +36,6 @@ gx-go --rewrite
Please check [Gx](https://github.com/whyrusleeping/gx) and [Gx-go](https://github.com/whyrusleeping/gx-go) documentation for more information.
## Maintainers
Captain: [@whyrusleeping](https://github.com/whyrusleeping).
## Contribute
Contributions welcome. Please check out [the issues](https://github.com/multiformats/go-multibase/issues).

View File

@@ -6,15 +6,15 @@ func hexEncodeToStringUpper(src []byte) string {
return string(dst)
}
var hextableUpper = [16]byte{
var hexTableUppers = [16]byte{
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F',
}
func hexEncodeUpper(dst, src []byte) int {
for i, v := range src {
dst[i*2] = hextableUpper[v>>4]
dst[i*2+1] = hextableUpper[v&0x0f]
dst[i*2] = hexTableUppers[v>>4]
dst[i*2+1] = hexTableUppers[v&0x0f]
}
return len(src) * 2

52
base2.go Normal file
View File

@@ -0,0 +1,52 @@
package multibase
import (
"fmt"
"strconv"
"strings"
)
// 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, b := range src {
for j := 0; j < 8; j++ {
if b&(1<<uint(7-j)) == 0 {
dst[i*8+j] = '0'
} else {
dst[i*8+j] = '1'
}
}
}
}
// decodeBinaryString takes multibase binary representation
// and returns a byte array
func decodeBinaryString(s string) ([]byte, error) {
if len(s)&7 != 0 {
// prepend the padding
s = strings.Repeat("0", 8-len(s)&7) + s
}
data := make([]byte, len(s)>>3)
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
}

View File

@@ -1,7 +1,7 @@
package multibase
import (
b32 "github.com/whyrusleeping/base32"
b32 "github.com/multiformats/go-base32"
)
var base32StdLowerPad = b32.NewEncodingCI("abcdefghijklmnopqrstuvwxyz234567")

6
go.mod Normal file
View File

@@ -0,0 +1,6 @@
module github.com/multiformats/go-multibase
require (
github.com/mr-tron/base58 v1.1.0
github.com/multiformats/go-base32 v0.0.3
)

4
go.sum Normal file
View File

@@ -0,0 +1,4 @@
github.com/mr-tron/base58 v1.1.0 h1:Y51FGVJ91WBqCEabAi5OPUz38eAx8DakuAm5svLcsfQ=
github.com/mr-tron/base58 v1.1.0/go.mod h1:xcD2VGqlgYjBdcBLw+TuYLr8afG+Hj8g2eTVqeSzSU8=
github.com/multiformats/go-base32 v0.0.3 h1:tw5+NhuwaOjJCC5Pp82QuXbrmLzWg7uxlMFp8Nq/kkI=
github.com/multiformats/go-base32 v0.0.3/go.mod h1:pLiuGC8y0QR3Ue4Zug5UzK9LjgbkL8NSQj0zQ5Nz/AA=

View File

@@ -14,8 +14,8 @@ func main() {
}
var newBase multibase.Encoding
if baseParm := os.Args[1]; len(baseParm) != 0 {
newBase = multibase.Encoding(baseParm[0])
if baseParam := os.Args[1]; len(baseParam) != 0 {
newBase = multibase.Encoding(baseParam[0])
} else {
fmt.Fprintln(os.Stderr, "<new-base> is empty")
os.Exit(1)

View File

@@ -6,7 +6,7 @@ import (
"fmt"
b58 "github.com/mr-tron/base58/base58"
b32 "github.com/whyrusleeping/base32"
b32 "github.com/multiformats/go-base32"
)
// Encoding identifies the type of base-encoding that a multibase is carrying.
@@ -38,10 +38,11 @@ const (
Base64urlPad = 'U'
)
// Encodigs is a map of the supported encoding, unsupported encoding
// Encodings is a map of the supported encoding, unsupported encoding
// 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

View File

@@ -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,

View File

@@ -7,17 +7,17 @@
"dvcsimport": "github.com/multiformats/go-multibase"
},
"gxDependencies": [
{
"author": "whyrusleeping",
"hash": "QmfVj3x4D6Jkq9SEoi5n2NmoUomLwoeiwnYz2KQa15wRw6",
"name": "base32",
"version": "0.0.2"
},
{
"author": "mr-tron",
"hash": "QmWFAMPqsEyUX7gDUsRVmMWz59FxSpJ1b2v6bJ1yYzo7jY",
"name": "go-base58-fast",
"version": "0.1.1"
},
{
"author": "Golang",
"hash": "QmPbbYin7KBd1Y1BfUe15vHzwJiioyi3wtKQTtXWWf8SC5",
"name": "base32",
"version": "0.0.3"
}
],
"gxVersion": "0.8.0",

1
spec Submodule

Submodule spec added at f0792f7030

147
spec_test.go Normal file
View File

@@ -0,0 +1,147 @@
package multibase
import (
"encoding/csv"
"os"
"path/filepath"
"strconv"
"strings"
"testing"
"unicode/utf8"
)
func TestSpec(t *testing.T) {
file, err := os.Open("spec/multibase.csv")
if err != nil {
t.Fatal(err)
}
defer file.Close()
reader := csv.NewReader(file)
reader.LazyQuotes = false
reader.FieldsPerRecord = 3
reader.TrimLeadingSpace = true
values, err := reader.ReadAll()
if err != nil {
t.Error(err)
}
expectedEncodings := make(map[Encoding]string, len(values)-1)
for _, v := range values[1:] {
encoding := v[0]
codeStr := v[1]
var code Encoding
if strings.HasPrefix(codeStr, "0x") {
i, err := strconv.ParseUint(codeStr[2:], 16, 64)
if err != nil {
t.Errorf("invalid multibase byte %q", codeStr)
continue
}
code = Encoding(i)
} else {
codeRune, length := utf8.DecodeRuneInString(codeStr)
if code == utf8.RuneError {
t.Errorf("multibase %q wasn't valid utf8", codeStr)
continue
}
if length != len(codeStr) {
t.Errorf("multibase %q wasn't a single character", codeStr)
continue
}
code = Encoding(codeRune)
}
expectedEncodings[code] = encoding
}
for name, enc := range Encodings {
expectedName, ok := expectedEncodings[enc]
if !ok {
t.Errorf("encoding %q (%c) not defined in the spec", name, enc)
continue
}
if expectedName != name {
t.Errorf("encoding %q (%c) has unexpected name %q", expectedName, enc, name)
}
}
}
func TestSpecVectors(t *testing.T) {
files, err := filepath.Glob("spec/tests/test[0-9]*.csv")
if err != nil {
t.Fatal(err)
}
for _, fname := range files {
t.Run(fname, func(t *testing.T) {
file, err := os.Open(fname)
if err != nil {
t.Error(err)
return
}
defer file.Close()
reader := csv.NewReader(file)
reader.LazyQuotes = false
reader.FieldsPerRecord = 2
reader.TrimLeadingSpace = true
values, err := reader.ReadAll()
if err != nil {
t.Error(err)
}
if len(values) == 0 {
t.Error("no test values")
return
}
header := values[0]
var decodeOnly bool
switch header[0] {
case "encoding":
case "non-canonical encoding":
decodeOnly = true
default:
t.Errorf("invalid test spec %q", fname)
return
}
testValue, err := strconv.Unquote("\"" + header[1] + "\"")
if err != nil {
t.Error("failed to unquote testcase:", err)
return
}
for _, testCase := range values[1:] {
encodingName := testCase[0]
expected := testCase[1]
t.Run(encodingName, func(t *testing.T) {
encoder, err := EncoderByName(encodingName)
if err != nil {
t.Skipf("skipping %s: not supported", encodingName)
return
}
if !decodeOnly {
t.Logf("encoding %q with %s", testValue, encodingName)
actual := encoder.Encode([]byte(testValue))
if expected != actual {
t.Errorf("expected %q, got %q", expected, actual)
}
}
t.Logf("decoding %q", expected)
encoding, decoded, err := Decode(expected)
if err != nil {
t.Error("failed to decode:", err)
return
}
expectedEncoding := Encodings[encodingName]
if encoding != expectedEncoding {
t.Errorf("expected encoding to be %c, got %c", expectedEncoding, encoding)
}
if string(decoded) != testValue {
t.Errorf("failed to decode %q to %q, got %q", expected, testValue, string(decoded))
}
})
}
})
}
}