package multihash
import (
"encoding/hex"
"errors"
"fmt"
"math"
b58 "github.com/mr-tron/base58/base58"
"github.com/multiformats/go-varint"
)
var (
ErrUnknownCode = errors .New ("unknown multihash code" )
ErrTooShort = errors .New ("multihash too short. must be >= 2 bytes" )
ErrTooLong = errors .New ("multihash too long. must be < 129 bytes" )
ErrLenNotSupported = errors .New ("multihash does not yet support digests longer than 127 bytes" )
ErrInvalidMultihash = errors .New ("input isn't valid multihash" )
ErrVarintBufferShort = errors .New ("uvarint: buffer too small" )
ErrVarintTooLong = errors .New ("uvarint: varint too big (max 64bit)" )
)
type ErrInconsistentLen struct {
dm DecodedMultihash
lengthFound int
}
func (e ErrInconsistentLen ) Error () string {
return fmt .Sprintf ("multihash length inconsistent: expected %d; got %d" , e .dm .Length , e .lengthFound )
}
const (
IDENTITY = 0x00
ID = IDENTITY
SHA1 = 0x11
SHA2_256 = 0x12
SHA2_512 = 0x13
SHA3_224 = 0x17
SHA3_256 = 0x16
SHA3_384 = 0x15
SHA3_512 = 0x14
SHA3 = SHA3_512
KECCAK_224 = 0x1A
KECCAK_256 = 0x1B
KECCAK_384 = 0x1C
KECCAK_512 = 0x1D
BLAKE3 = 0x1E
SHAKE_128 = 0x18
SHAKE_256 = 0x19
BLAKE2B_MIN = 0xb201
BLAKE2B_MAX = 0xb240
BLAKE2S_MIN = 0xb241
BLAKE2S_MAX = 0xb260
MD5 = 0xd5
DBL_SHA2_256 = 0x56
MURMUR3X64_64 = 0x22
MURMUR3 = MURMUR3X64_64
SHA2_256_TRUNC254_PADDED = 0x1012
X11 = 0x1100
POSEIDON_BLS12_381_A1_FC1 = 0xb401
)
func init() {
for c := uint64 (BLAKE2B_MIN ); c <= BLAKE2B_MAX ; c ++ {
n := c - BLAKE2B_MIN + 1
name := fmt .Sprintf ("blake2b-%d" , n *8 )
Names [name ] = c
Codes [c ] = name
}
for c := uint64 (BLAKE2S_MIN ); c <= BLAKE2S_MAX ; c ++ {
n := c - BLAKE2S_MIN + 1
name := fmt .Sprintf ("blake2s-%d" , n *8 )
Names [name ] = c
Codes [c ] = name
}
}
var Names = map [string ]uint64 {
"identity" : IDENTITY ,
"sha1" : SHA1 ,
"sha2-256" : SHA2_256 ,
"sha2-512" : SHA2_512 ,
"sha3" : SHA3_512 ,
"sha3-224" : SHA3_224 ,
"sha3-256" : SHA3_256 ,
"sha3-384" : SHA3_384 ,
"sha3-512" : SHA3_512 ,
"dbl-sha2-256" : DBL_SHA2_256 ,
"murmur3-x64-64" : MURMUR3X64_64 ,
"keccak-224" : KECCAK_224 ,
"keccak-256" : KECCAK_256 ,
"keccak-384" : KECCAK_384 ,
"keccak-512" : KECCAK_512 ,
"blake3" : BLAKE3 ,
"shake-128" : SHAKE_128 ,
"shake-256" : SHAKE_256 ,
"sha2-256-trunc254-padded" : SHA2_256_TRUNC254_PADDED ,
"x11" : X11 ,
"md5" : MD5 ,
"poseidon-bls12_381-a2-fc1" : POSEIDON_BLS12_381_A1_FC1 ,
}
var Codes = map [uint64 ]string {
IDENTITY : "identity" ,
SHA1 : "sha1" ,
SHA2_256 : "sha2-256" ,
SHA2_512 : "sha2-512" ,
SHA3_224 : "sha3-224" ,
SHA3_256 : "sha3-256" ,
SHA3_384 : "sha3-384" ,
SHA3_512 : "sha3-512" ,
DBL_SHA2_256 : "dbl-sha2-256" ,
MURMUR3X64_64 : "murmur3-x64-64" ,
KECCAK_224 : "keccak-224" ,
KECCAK_256 : "keccak-256" ,
KECCAK_384 : "keccak-384" ,
KECCAK_512 : "keccak-512" ,
BLAKE3 : "blake3" ,
SHAKE_128 : "shake-128" ,
SHAKE_256 : "shake-256" ,
SHA2_256_TRUNC254_PADDED : "sha2-256-trunc254-padded" ,
X11 : "x11" ,
POSEIDON_BLS12_381_A1_FC1 : "poseidon-bls12_381-a2-fc1" ,
MD5 : "md5" ,
}
func uvarint(buf []byte ) (uint64 , []byte , error ) {
n , c , err := varint .FromUvarint (buf )
if err != nil {
return n , buf , err
}
if c == 0 {
return n , buf , ErrVarintBufferShort
} else if c < 0 {
return n , buf [-c :], ErrVarintTooLong
} else {
return n , buf [c :], nil
}
}
type DecodedMultihash struct {
Code uint64
Name string
Length int
Digest []byte
}
type Multihash []byte
func (m Multihash ) HexString () string {
return hex .EncodeToString ([]byte (m ))
}
func (m Multihash ) String () string {
return m .HexString ()
}
func FromHexString (s string ) (Multihash , error ) {
b , err := hex .DecodeString (s )
if err != nil {
return Multihash {}, err
}
return Cast (b )
}
func (m Multihash ) B58String () string {
return b58 .Encode ([]byte (m ))
}
func FromB58String (s string ) (m Multihash , err error ) {
b , err := b58 .Decode (s )
if err != nil {
return Multihash {}, ErrInvalidMultihash
}
return Cast (b )
}
func Cast (buf []byte ) (Multihash , error ) {
_ , err := Decode (buf )
if err != nil {
return Multihash {}, err
}
return Multihash (buf ), nil
}
func Decode (buf []byte ) (*DecodedMultihash , error ) {
dm , err := decode (buf )
if err != nil {
return nil , err
}
return &dm , nil
}
func decode(buf []byte ) (dm DecodedMultihash , err error ) {
rlen , code , hdig , err := readMultihashFromBuf (buf )
if err != nil {
return DecodedMultihash {}, err
}
dm = DecodedMultihash {
Code : code ,
Name : Codes [code ],
Length : len (hdig ),
Digest : hdig ,
}
if len (buf ) != rlen {
return dm , ErrInconsistentLen {dm , rlen }
}
return dm , nil
}
func Encode (buf []byte , code uint64 ) ([]byte , error ) {
newBuf := make ([]byte , varint .UvarintSize (code )+varint .UvarintSize (uint64 (len (buf )))+len (buf ))
n := varint .PutUvarint (newBuf , code )
n += varint .PutUvarint (newBuf [n :], uint64 (len (buf )))
copy (newBuf [n :], buf )
return newBuf , nil
}
func EncodeName (buf []byte , name string ) ([]byte , error ) {
return Encode (buf , Names [name ])
}
func readMultihashFromBuf(buf []byte ) (int , uint64 , []byte , error ) {
initBufLength := len (buf )
if initBufLength < 2 {
return 0 , 0 , nil , ErrTooShort
}
var err error
var code , length uint64
code , buf , err = uvarint (buf )
if err != nil {
return 0 , 0 , nil , err
}
length , buf , err = uvarint (buf )
if err != nil {
return 0 , 0 , nil , err
}
if length > math .MaxInt32 {
return 0 , 0 , nil , errors .New ("digest too long, supporting only <= 2^31-1" )
}
if int (length ) > len (buf ) {
return 0 , 0 , nil , errors .New ("length greater than remaining number of bytes in buffer" )
}
rlen := (initBufLength - len (buf )) + int (length )
return rlen , code , buf [:length ], nil
}
func MHFromBytes (buf []byte ) (int , Multihash , error ) {
nr , _ , _ , err := readMultihashFromBuf (buf )
if err != nil {
return 0 , nil , err
}
return nr , Multihash (buf [:nr ]), nil
}
The pages are generated with Golds v0.8.2 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .