cid.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. // Copyright 2016 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. package ens
  17. import (
  18. "encoding/binary"
  19. "errors"
  20. "fmt"
  21. "github.com/ethereum/go-ethereum/common"
  22. )
  23. const (
  24. cidv1 = 0x1
  25. nsIpfs = 0xe3
  26. nsSwarm = 0xe4
  27. swarmTypecode = 0xfa // swarm manifest, see https://github.com/multiformats/multicodec/blob/master/table.csv
  28. swarmHashtype = 0x1b // keccak256, see https://github.com/multiformats/multicodec/blob/master/table.csv
  29. hashLength = 32
  30. )
  31. // deocodeEIP1577ContentHash decodes a chain-stored content hash from an ENS record according to EIP-1577
  32. // a successful decode will result the different parts of the content hash in accordance to the CID spec
  33. // Note: only CIDv1 is supported
  34. func decodeEIP1577ContentHash(buf []byte) (storageNs, contentType, hashType, hashLength uint64, hash []byte, err error) {
  35. if len(buf) < 10 {
  36. return 0, 0, 0, 0, nil, errors.New("buffer too short")
  37. }
  38. storageNs, n := binary.Uvarint(buf)
  39. buf = buf[n:]
  40. vers, n := binary.Uvarint(buf)
  41. if vers != 1 {
  42. return 0, 0, 0, 0, nil, fmt.Errorf("expected cid v1, got: %d", vers)
  43. }
  44. buf = buf[n:]
  45. contentType, n = binary.Uvarint(buf)
  46. buf = buf[n:]
  47. hashType, n = binary.Uvarint(buf)
  48. buf = buf[n:]
  49. hashLength, n = binary.Uvarint(buf)
  50. hash = buf[n:]
  51. if len(hash) != int(hashLength) {
  52. return 0, 0, 0, 0, nil, errors.New("hash length mismatch")
  53. }
  54. return storageNs, contentType, hashType, hashLength, hash, nil
  55. }
  56. func extractContentHash(buf []byte) (common.Hash, error) {
  57. storageNs, _ /*contentType*/, _ /* hashType*/, decodedHashLength, hashBytes, err := decodeEIP1577ContentHash(buf)
  58. if err != nil {
  59. return common.Hash{}, err
  60. }
  61. if storageNs != nsSwarm {
  62. return common.Hash{}, errors.New("unknown storage system")
  63. }
  64. //todo: for the time being we implement loose enforcement for the EIP rules until ENS manager is updated
  65. /*if contentType != swarmTypecode {
  66. return common.Hash{}, errors.New("unknown content type")
  67. }
  68. if hashType != swarmHashtype {
  69. return common.Hash{}, errors.New("unknown multihash type")
  70. }*/
  71. if decodedHashLength != hashLength {
  72. return common.Hash{}, errors.New("odd hash length, swarm expects 32 bytes")
  73. }
  74. if len(hashBytes) != int(hashLength) {
  75. return common.Hash{}, errors.New("hash length mismatch")
  76. }
  77. return common.BytesToHash(buf), nil
  78. }
  79. func EncodeSwarmHash(hash common.Hash) ([]byte, error) {
  80. var cidBytes []byte
  81. var headerBytes = []byte{
  82. nsSwarm, //swarm namespace
  83. cidv1, // CIDv1
  84. swarmTypecode, // swarm hash
  85. swarmHashtype, // keccak256 hash
  86. hashLength, //hash length. 32 bytes
  87. }
  88. varintbuf := make([]byte, binary.MaxVarintLen64)
  89. for _, v := range headerBytes {
  90. n := binary.PutUvarint(varintbuf, uint64(v))
  91. cidBytes = append(cidBytes, varintbuf[:n]...)
  92. }
  93. cidBytes = append(cidBytes, hash[:]...)
  94. return cidBytes, nil
  95. }