1// SPDX-License-Identifier: ISC 2// Copyright (c) 2014-2020 Bitmark Inc. 3// Use of this source code is governed by an ISC 4// license that can be found in the LICENSE file. 5 6package transactionrecord 7 8import ( 9 "encoding/hex" 10 "fmt" 11 12 "golang.org/x/crypto/sha3" 13 14 "github.com/bitmark-inc/bitmarkd/fault" 15) 16 17// limits 18const ( 19 AssetIdentifierLength = 64 20) 21 22// AssetIdentifier - the type for an asset identifier 23// stored as little endian byte array 24// represented as little endian hex text for JSON encoding 25// convert a binary assetId to byte slice 26// to get bytes value just use assetId[:] 27type AssetIdentifier [AssetIdentifierLength]byte 28 29// NewAssetIdentifier - create an asset id from a byte slice 30// 31// SHA3-512 Hash 32func NewAssetIdentifier(record []byte) AssetIdentifier { 33 return AssetIdentifier(sha3.Sum512(record)) 34} 35 36// String - convert a binary assetId to little endian hex string for use by the fmt package (for %s) 37func (assetId AssetIdentifier) String() string { 38 return hex.EncodeToString(assetId[:]) 39} 40 41// GoString - convert a binary assetId to little endian hex string for use by the fmt package (for %#v) 42func (assetId AssetIdentifier) GoString() string { 43 return "<asset:" + hex.EncodeToString(assetId[:]) + ">" 44} 45 46// Scan - convert a little endian hex text representation to a assetId for use by the format package scan routines 47func (assetId *AssetIdentifier) Scan(state fmt.ScanState, verb rune) error { 48 token, err := state.Token(true, func(c rune) bool { 49 if c >= '0' && c <= '9' { 50 return true 51 } 52 if c >= 'A' && c <= 'F' { 53 return true 54 } 55 if c >= 'a' && c <= 'f' { 56 return true 57 } 58 return false 59 }) 60 if nil != err { 61 return err 62 } 63 if len(token) != hex.EncodedLen(AssetIdentifierLength) { 64 return fault.NotAssetId 65 } 66 67 byteCount, err := hex.Decode(assetId[:], token) 68 if nil != err { 69 return err 70 } 71 72 if AssetIdentifierLength != byteCount { 73 return fault.NotAssetId 74 } 75 return nil 76} 77 78// MarshalText - convert assetId to little endian hex text 79func (assetId AssetIdentifier) MarshalText() ([]byte, error) { 80 size := hex.EncodedLen(len(assetId)) 81 buffer := make([]byte, size) 82 hex.Encode(buffer, assetId[:]) 83 return buffer, nil 84} 85 86// UnmarshalText - convert little endian hex text into a assetId 87func (assetId *AssetIdentifier) UnmarshalText(s []byte) error { 88 if len(assetId) != hex.DecodedLen(len(s)) { 89 return fault.NotLink 90 } 91 byteCount, err := hex.Decode(assetId[:], s) 92 if nil != err { 93 return err 94 } 95 if AssetIdentifierLength != byteCount { 96 return fault.NotAssetId 97 } 98 return nil 99} 100 101// AssetIdentifierFromBytes - convert and validate little endian binary byte slice to a assetId 102func AssetIdentifierFromBytes(assetId *AssetIdentifier, buffer []byte) error { 103 if AssetIdentifierLength != len(buffer) { 104 return fault.NotAssetId 105 } 106 copy(assetId[:], buffer) 107 return nil 108} 109