Wie kann ich eine Bytes32-Quelle in zwei Hälften teilen und sie in Bytes16 speichern?

Ich möchte eine 32-Byte-Quelle aufteilen: erste Hälfte in Bytes16 half1; zweite Hälfte in Bytes16 half2. Mein Code funktioniert jedoch nur für dynamische Arrays, nicht mit fester Größe 16.

pragma solidity ^0.4.8;

contract cut {

    function cutSha(bytes32 source) constant returns (bytes, bytes) {
        bytes memory half1 = new bytes(16);
        bytes memory half2 = new bytes(16);
        for (uint j = 0; j < 16; j++) {
                half1[j] = source[j];
                half2[j] = source[j+16];
        }
        return (half1, half2);
    }
}
Da die Hälften nur die ersten/letzten 16 Bytes sind, sollte es einen effizienten Weg geben, wie die Verwendung von Inline-Assembly und mload?

Antworten (4)

Dies ist mit der Montage möglich:

pragma solidity ^0.4.8;

contract c {
    event trace(bytes32 x, bytes16 a, bytes16 b);

    function foo(bytes32 source) {
        bytes16[2] memory y = [bytes16(0), 0];
        assembly {
            mstore(y, source)
            mstore(add(y, 16), source)
        }
        trace(source, y[0], y[1]);
    }
}

Wenn Sie beispielsweise Bytes aus der Zeichenfolge „what a wonderful world!“ Konvertieren, wird dies nach dem Verbrauch von 2245-Gas erzeugt:

trace[
  "0x77686174206120776f6e64657266756c20776f726c6421000000000000000000",
  "0x77686174206120776f6e64657266756c",
  "0x20776f726c6421000000000000000000"
]

NB : Der Code stützt sich auf die interne Datendarstellung, die in späteren Versionen von Solidity geändert werden kann oder den Solidity-Optimierer auf unvorhersehbare Weise stört.

Habe das jetzt erst gesehen. Vielen Dank, werde jetzt mit meiner eigenen Lösung vergleichen, die unten gepostet wurde.
Wie ändern wir Ihren Code, damit ich 56 Zeichen eingeben und in zwei Bytes aufteilen kann32?

Ich habe eine Lösung mit Inline-Assembly gefunden:

contract cutByte32 {

  //"0xa9c40ddcb43ebbc83add97b8f9f361f12b19bceff2f76b68f66b5bb1812365a9"
  //use this as remix command

  function cut(bytes32 sha) constant returns (bytes16 half1, bytes16 half2) {
    assembly {
      let freemem_pointer := mload(0x40)
      mstore(add(freemem_pointer,0x00), sha)
      half1 := mload(add(freemem_pointer,0x00))
      half2 := mload(add(freemem_pointer,0x10))
    }
  }
}
+1, das ist schön. aber kannst du ein bisschen erklären was das mload(0x40)bedeutet?
Danke, an der Adresse 0x40 (solidity definition) ist der Pointer (/address) für den nächsten freien Slot auf dem Speicher abgelegt. Wenn ich es zuerst in die Variable freemem_pointer lade, wird sichergestellt, dass ich nichts im Speicher überschreibe. Ich gehe aber davon aus, dass es noch bessere Lösungen gibt. Wenn ich neu wüsste, an welcher Adresse der Parameterwert "bytes32 sha" gespeichert ist, brauche ich ihn nicht erneut zu speichern und kann direkt beginnen, ihn 16-Byte-weise auszulesen.
Wie ändern wir Ihren Code, damit ich 56 Zeichen eingeben und in zwei Bytes aufteilen kann32?

Es ist jetzt möglich, Typkonvertierungen zu verwenden, um dies in ein paar Zeilen zu tun.

pragma solidity 0.8.16;

contract cut {

    function cutSha(bytes32 source) 
        public 
        returns (bytes16 half1, bytes16 half2) 
    {
        half1 = bytes16(source);
        half2 = bytes16(uint128(uint256(source)));
        
    }
}

PS Tut mir leid, wenn dieser Code fusseln muss - ich kann ihn gerade nicht testen, dies ist nur eine Illustration für die Idee; Korrekturen sind also willkommen.

Versuchen Sie es mit uints

   function bytesChunck(bytes32 source, uint start, uint numBytes) constant returns(uint _result){
                uint counter = 0;
                uint result;

                for(uint i = 0; i < numBytes; i++) {
                    result += uint8(source[start + i]);
                }
                return result;
        }

aber das Lesen von Bytes aus bytes32 gibt einen Nullwert zurück (außer dem ersten)