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  }