git.frostfs.info/TrueCloudLab/frostfs-sdk-go@v0.0.0-20241022124111-5361f0ecebd3/object/id/id.go (about) 1 package oid 2 3 import ( 4 "crypto/ecdsa" 5 "crypto/sha256" 6 "fmt" 7 8 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs" 9 frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto" 10 frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa" 11 "github.com/mr-tron/base58" 12 ) 13 14 // ID represents FrostFS object identifier in a container. 15 // 16 // ID is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs.ObjectID 17 // message. See ReadFromV2 / WriteToV2 methods. 18 // 19 // Instances can be created using built-in var declaration. 20 // 21 // Note that direct typecast is not safe and may result in loss of compatibility: 22 // 23 // _ = ID([32]byte{}) // not recommended 24 type ID [sha256.Size]byte 25 26 // ReadFromV2 reads ID from the refs.ObjectID message. Returns an error if 27 // the message is malformed according to the FrostFS API V2 protocol. 28 // 29 // See also WriteToV2. 30 func (id *ID) ReadFromV2(m refs.ObjectID) error { 31 return id.Decode(m.GetValue()) 32 } 33 34 // WriteToV2 writes ID to the refs.ObjectID message. 35 // The message must not be nil. 36 // 37 // See also ReadFromV2. 38 func (id ID) WriteToV2(m *refs.ObjectID) { 39 m.SetValue(id[:]) 40 } 41 42 // Encode encodes ID into 32 bytes of dst. Panics if 43 // dst length is less than 32. 44 // 45 // Zero ID is all zeros. 46 // 47 // See also Decode. 48 func (id ID) Encode(dst []byte) { 49 if l := len(dst); l < sha256.Size { 50 panic(fmt.Sprintf("destination length is less than %d bytes: %d", sha256.Size, l)) 51 } 52 53 copy(dst, id[:]) 54 } 55 56 // Decode decodes src bytes into ID. 57 // 58 // Decode expects that src has 32 bytes length. If the input is malformed, 59 // Decode returns an error describing format violation. In this case ID 60 // remains unchanged. 61 // 62 // Decode doesn't mutate src. 63 // 64 // See also Encode. 65 func (id *ID) Decode(src []byte) error { 66 if len(src) != 32 { 67 return fmt.Errorf("invalid length %d", len(src)) 68 } 69 70 copy(id[:], src) 71 72 return nil 73 } 74 75 // SetSHA256 sets object identifier value to SHA256 checksum. 76 func (id *ID) SetSHA256(v [sha256.Size]byte) { 77 copy(id[:], v[:]) 78 } 79 80 // Equals defines a comparison relation between two ID instances. 81 // 82 // Note that comparison using '==' operator is not recommended since it MAY result 83 // in loss of compatibility. 84 func (id ID) Equals(id2 ID) bool { 85 return id == id2 86 } 87 88 // EncodeToString encodes ID into FrostFS API protocol string. 89 // 90 // Zero ID is base58 encoding of 32 zeros. 91 // 92 // See also DecodeString. 93 func (id ID) EncodeToString() string { 94 return base58.Encode(id[:]) 95 } 96 97 // DecodeString decodes string into ID according to FrostFS API protocol. Returns 98 // an error if s is malformed. 99 // 100 // See also DecodeString. 101 func (id *ID) DecodeString(s string) error { 102 data, err := base58.Decode(s) 103 if err != nil { 104 return fmt.Errorf("decode base58: %w", err) 105 } 106 107 return id.Decode(data) 108 } 109 110 // String implements fmt.Stringer. 111 // 112 // String is designed to be human-readable, and its format MAY differ between 113 // SDK versions. String MAY return same result as EncodeToString. String MUST NOT 114 // be used to encode ID into FrostFS protocol string. 115 func (id ID) String() string { 116 return id.EncodeToString() 117 } 118 119 // CalculateIDSignature signs object id with provided key. 120 func (id ID) CalculateIDSignature(key ecdsa.PrivateKey) (frostfscrypto.Signature, error) { 121 data, err := id.Marshal() 122 if err != nil { 123 return frostfscrypto.Signature{}, fmt.Errorf("marshal ID: %w", err) 124 } 125 126 var sig frostfscrypto.Signature 127 128 return sig, sig.Calculate(frostfsecdsa.Signer(key), data) 129 } 130 131 // Marshal marshals ID into a protobuf binary form. 132 func (id ID) Marshal() ([]byte, error) { 133 var v2 refs.ObjectID 134 v2.SetValue(id[:]) 135 136 return v2.StableMarshal(nil), nil 137 } 138 139 // Unmarshal unmarshals protobuf binary representation of ID. 140 func (id *ID) Unmarshal(data []byte) error { 141 var v2 refs.ObjectID 142 if err := v2.Unmarshal(data); err != nil { 143 return err 144 } 145 146 copy(id[:], v2.GetValue()) 147 148 return nil 149 } 150 151 // MarshalJSON encodes ID to protobuf JSON format. 152 func (id ID) MarshalJSON() ([]byte, error) { 153 var v2 refs.ObjectID 154 v2.SetValue(id[:]) 155 156 return v2.MarshalJSON() 157 } 158 159 // UnmarshalJSON decodes ID from protobuf JSON format. 160 func (id *ID) UnmarshalJSON(data []byte) error { 161 var v2 refs.ObjectID 162 if err := v2.UnmarshalJSON(data); err != nil { 163 return err 164 } 165 166 copy(id[:], v2.GetValue()) 167 168 return nil 169 }