Отправитель может предоставить все, что угодно, в примере на месте C был msg.sender, то есть адрес самого отправителя. На место C msg.sender ставится строго всегда, и мы таким образом проверяем, есть ли msg.sender в вайтлисте.
По этой причине подделку нельзя совершить, потому что в конечном итоге смотрится наличие в root адреса откуда была отправлена транзакция.
"а там же проверяется, что [ D, H(AB), H(EH) ] входят в дерево" - не совсем так, проверяется, что входит хэш C, а [ D, H(AB), H(EH) ] это промежуточные узлы, через которые можно восстановить корневой хэш, и уже если восстановленный хэш равен root, то верификация на наличие C пройдена успешно
в приведенном примере используется библиотека MerkleProof, в ней восстановление корневого хэша идет с использованием функции keccak256, поэтому теоретическая часть была написана с прицелом на то, как это будет показано на практике
Согласен, мой недочет, я бы ещё добавил ссылку на первоисточник самого стандарта: https://eips.ethereum.org/EIPS/eip-2535
Отправитель может предоставить все, что угодно, в примере на месте C был msg.sender, то есть адрес самого отправителя. На место C msg.sender ставится строго всегда, и мы таким образом проверяем, есть ли msg.sender в вайтлисте.
По этой причине подделку нельзя совершить, потому что в конечном итоге смотрится наличие в root адреса откуда была отправлена транзакция.
"а там же проверяется, что [ D, H(AB), H(EH) ] входят в дерево" - не совсем так, проверяется, что входит хэш C, а [ D, H(AB), H(EH) ] это промежуточные узлы, через которые можно восстановить корневой хэш, и уже если восстановленный хэш равен root, то верификация на наличие C пройдена успешно
в приведенном примере используется библиотека MerkleProof, в ней восстановление корневого хэша идет с использованием функции keccak256, поэтому теоретическая часть была написана с прицелом на то, как это будет показано на практике
https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/MerkleProof.sol#L220
С уважением!