code: func (x *XC) Decrypt(ctx context.Context, buf []byte) ([]byte, error) {
  	// unmarshal the protobuf message, the header and body are still encrypted
  	// afterwards (parts of the header are plaintext!)
  	msg := &xcpb.Message{}
  	if err := proto.Unmarshal(buf, msg); err != nil {
  		return nil, err
  	}
  
  	// try to find a suiteable decryption key in the header
  	sk, err := x.decryptSessionKey(ctx, msg.Header)
  	if err != nil {
  		return nil, err
  	}
  
  	var secretKey [32]byte
  	copy(secretKey[:], sk)
  
  	plainBuf := &bytes.Buffer{}
  
  	for i, chunk := range msg.Chunks {
  		// reconstruct nonce from chunk number
  		// in case chunks have been reordered by some adversary
  		// decryption will fail
  		var nonce [24]byte
  		binary.BigEndian.PutUint64(nonce[:], uint64(i))
  
  		// decrypt and verify the ciphertext
  		//plaintext, err := cp.Open(nil, nonce, chunk.Body, nil)
  		plaintext, ok := secretbox.Open(nil, chunk.Body, &nonce, &secretKey)
  		if !ok {
  			return nil, fmt.Errorf("failed to decrypt")
  		}
  
  		plainBuf.Write(plaintext)
  	}
  
  	if !msg.Compressed {
  		return plainBuf.Bytes(), nil
  	}
  
  	return decompress(plainBuf.Bytes())
  }
docs: // Decrypt tries to decrypt the given ciphertext and returns the plaintext