@@ -6,12 +6,8 @@ import "./CborDecode.sol";
66library CidCbor {
77 using CBORDecoder for bytes ;
88
9- uint8 private constant MAJOR_BYTE_STRING = 2 ;
10- uint8 private constant MAJOR_TYPE_TAG = 6 ;
119 uint8 private constant TAG_CID = 42 ;
1210
13- uint8 private constant EXPECTED_CID_LENGTH = 37 ;
14-
1511 uint8 private constant MULTIBASE_FORMAT = 0x00 ;
1612 uint8 private constant CID_V1 = 0x01 ;
1713 uint8 private constant MULTICODEC_DAG_CBOR = 0x71 ;
@@ -32,25 +28,48 @@ library CidCbor {
3228 */
3329 type CidBytes32 is bytes32 ;
3430
35- function expectCidTag (bytes memory cborData , uint byteIdx ) internal pure returns (uint ) {
36- uint8 maj;
37- uint value;
38- (maj, value, byteIdx) = cborData.parseCborHeader (byteIdx);
39- require (maj == MAJOR_TYPE_TAG, "expected tag major " );
40- require (value == TAG_CID, "expected tag 42 for CID " );
31+ function expectTagCid (bytes memory cborData , uint byteIdx ) internal pure returns (uint ) {
32+ uint8 head = uint8 (cborData[byteIdx]);
33+ uint8 tagValue = uint8 (cborData[byteIdx + 1 ]);
34+ require (head == MajorTag << shiftMajor | MinorExtend1, "expected tag head with 1-byte extension " );
35+ require (tagValue == TAG_CID, "expected tag 42 for CID " );
36+ return byteIdx + 2 ;
37+ }
38+
39+ function expect37Bytes (bytes memory cborData , uint byteIdx ) internal pure returns (uint ) {
40+ require (
41+ uint8 (cborData[byteIdx]) == MajorBytes << shiftMajor | MinorExtend1,
42+ "expected byte head with 1-byte extension "
43+ );
44+ require (uint8 (cborData[byteIdx + 1 ]) == 37 , "expected 37 bytes for CID " );
45+ byteIdx += 2 ;
4146 return byteIdx;
4247 }
4348
4449 function readCidBytes32 (bytes memory cborData , CidIndex idx ) internal pure returns (CidBytes32) {
50+ return readCidBytes32_assembly (cborData, idx);
51+ }
52+
53+ function readCidBytes32_loop (bytes memory cborData , CidIndex idx ) internal pure returns (CidBytes32) {
4554 uint cidIdx = CidIndex.unwrap (idx);
46- require (cidIdx != 0 , "Can't read a CID hash at index 0 " );
47- bytes memory cidBytes = new bytes (MULTIHASH_SIZE_32);
48- for (uint i = 0 ; i < MULTIHASH_SIZE_32; i++ ) {
55+ bytes memory cidBytes = new bytes (32 );
56+ for (uint i = 0 ; i < 32 ; i++ ) {
4957 cidBytes[i] = cborData[cidIdx + i];
5058 }
5159 return CidBytes32.wrap (bytes32 (cidBytes));
5260 }
5361
62+ function readCidBytes32_assembly (bytes memory cborData , CidIndex idx ) internal pure returns (CidBytes32) {
63+ uint cidIdx = CidIndex.unwrap (idx);
64+ require (cidIdx != 0 , "Can't read a CID hash at index 0 " );
65+
66+ bytes32 cidBytes;
67+ assembly ("memory-safe" ) {
68+ cidBytes := mload (add (cborData, add (0x20 , cidIdx)))
69+ }
70+ return CidBytes32.wrap (cidBytes);
71+ }
72+
5473 function readNullableCidIndex (bytes memory cborData , uint byteIdx ) internal pure returns (CidIndex, uint ) {
5574 if (cborData.isNullNext (byteIdx)) {
5675 return (CidIndex.wrap (0 ), byteIdx + 1 );
@@ -60,20 +79,40 @@ library CidCbor {
6079 }
6180
6281 function readCidIndex (bytes memory cborData , uint byteIdx ) internal pure returns (CidIndex, uint ) {
63- (byteIdx) = expectCidTag (cborData, byteIdx);
64- (uint8 maj , uint len , uint bytesStart ) = cborData.parseCborHeader (byteIdx);
82+ return readCidIndex_assembly (cborData, byteIdx);
83+ }
84+
85+ function readCidIndex_assembly (bytes memory cborData , uint byteIdx ) internal pure returns (CidIndex, uint ) {
86+ bytes9 cidHead;
87+ assembly ("memory-safe" ) {
88+ cidHead := mload (add (cborData, add (0x20 , byteIdx)))
89+ }
90+
91+ // all cids encountered will contain this 9-byte header
92+ // D8 2A cbor tag(42) cid
93+ // 58 25 cbor bytes(37) total length
94+ // 00 multibase format
95+ // 01 CID version
96+ // 71 multicodec DAG-CBOR
97+ // 12 multihash sha-256
98+ // 20 hash size 32 bytes
99+ require (cidHead == hex "D82A58250001711220 " , "expected CIDv1 dag-cbor sha256 head " );
100+ byteIdx += 9 ;
101+ return (CidIndex.wrap (byteIdx), byteIdx + 32 );
102+ }
65103
66- require (maj == MAJOR_BYTE_STRING, "expected byte string " );
67- require (len == EXPECTED_CID_LENGTH, "expected bytes length 37 for CID " );
104+ function readCidIndex_access (bytes memory cborData , uint byteIdx ) internal pure returns (CidIndex, uint ) {
105+ byteIdx = expectTagCid (cborData, byteIdx);
106+ byteIdx = expect37Bytes (cborData, byteIdx);
68107
69- // multibase format
70- require (uint8 (cborData[bytesStart ]) == MULTIBASE_FORMAT, "expected multibase item " );
71- // cid format
72- require (uint8 (cborData[bytesStart + 1 ]) == CID_V1, "expected CID v1 " );
73- require (uint8 (cborData[bytesStart + 2 ]) == MULTICODEC_DAG_CBOR, "expected CID multicodec DAG-CBOR " );
74- require (uint8 (cborData[bytesStart + 3 ]) == MULTIHASH_SHA_256, "expected CID multihash sha-256 " );
75- require (uint8 (cborData[bytesStart + 4 ]) == MULTIHASH_SIZE_32, "expected CID content size 32 bytes " );
108+ // uint8 conversion is faster than assembly? lol
109+ require (uint8 (cborData[byteIdx ]) == MULTIBASE_FORMAT, "expected multibase item " );
110+ // cid format always
111+ require (uint8 (cborData[byteIdx + 1 ]) == CID_V1, "expected CID v1 " );
112+ require (uint8 (cborData[byteIdx + 2 ]) == MULTICODEC_DAG_CBOR, "expected CID multicodec DAG-CBOR " );
113+ require (uint8 (cborData[byteIdx + 3 ]) == MULTIHASH_SHA_256, "expected CID multihash sha-256 " );
114+ require (uint8 (cborData[byteIdx + 4 ]) == MULTIHASH_SIZE_32, "expected CID content size 32 bytes " );
76115
77- return (CidIndex.wrap (bytesStart + 5 ), bytesStart + len );
116+ return (CidIndex.wrap (byteIdx + 5 ), byteIdx + 37 );
78117 }
79118}
0 commit comments