Аналог web3.eth.accounts.sign (от web3js) в web3py

В реализации web3js есть функция web3.eth.accounts.sign. Но я не могу найти точного эквивалента в web3py, я этого не вижу. Я нашел что-то похожее на это — функцию signHash (ссылка https://web3py.readthedocs.io/en/stable/web3.eth.account.html#sign-a-message ). В этой документации написано, что тот же механизм хеширования, но в результате выполнение возвращает не такое, как в web3js (web3.eth.accounts.sign).

Я использовал эту функцию в web3js для получения подписи (а затем с помощью библиотеки ECDSA (на Solidity) для получения подписчика. На web3js работает корректно (а на web3py - нет). Подключаюсь к тестовой сети (ropsten) через Infura.

На web3js (где msg — что подписано):

let signature = await web3.eth.accounts.sign(msgHash, '0x' + privateKeyUser);
console.log('signature ='+signature.signature);

На web3py (пробую, но не работает):

signature = web3.eth.account.signHash(msgHash, '0x' + privateKeyUser)
print('signature ='+signature.signature.hex())

And for example in variable "msgHash" value: 0x058c3b4c8e5dc4632b5c6b861b2c1861d53e426dc673c907ddf2651942b0f230 And at the output of web3js function (web3.eth.accounts.sign), we get signature: 0xd19241ed816026e846c8511e03a468aa6e038165ecb3c2229eee38b04c64b235408389dfad2b65d776dba236e7de1b63fdb6b2579e70c4ce9ad1b09a35da96521c And this is the correct value. Web3py имеет другое значение.

Что является точным аналогом в web3py того, как эта функция web3.eth.accounts.sign работает в web3js? Спасибо!

Было бы полезно, если бы вы предоставили пример сообщения, которое вы пытаетесь подписать, а также необработанные (шестнадцатеричные) данные, которые он web3.jsсоздает.
Также было бы полезно знать, используете ли вы удаленный узел для подписи/обработки ключей или доступен ли закрытый ключ для подписи в скрипте для web3.js. (Есть такое различие в web3.py.)
В общем, удобные методы для структурированного подписания EIP-712 были добавлены web3.pyв v5 ; документы stable, на которые вы ссылаетесь, относятся к версии 4. Уточните, нужна ли вам конкретно v4, или v5 также приемлема.
... И поскольку вы новичок в SE: эти разъяснения должны быть изменены на ваш исходный вопрос. (Добро пожаловать! :D)
Спасибо за помощь! Да, я здесь новенький :) Добавил информации.
Помоги мне, пожалуйста. Я добавил больше информации в свой первоначальный вопрос. Я до сих пор не знаю ответа.
Об этом: «В общем, удобные методы для структурированной подписи EIP-712 были добавлены в web3.py в версии 5; стабильные документы, на которые вы ссылаетесь, относятся к версии 4. Уточните, нужна ли вам конкретно версия 4 или если версия 5 также приемлема».
(конец моего предыдущего поста) Пробовал обе версии - 4 и 5. До этого не пробовал 5 версию (ибо она нестабильна, насколько я понимаю). В версии 5 я вижу возможность работать с функцией "send_message". Если я правильно понимаю, нужно передать экземпляр класса "SignableMessage" (из eth_account.messages). Но я не понимаю до конца, какие правильные параметры для инициализации этого экземпляра.
@Alex Добро пожаловать на биржу стека! Этот вопрос можно улучшить, добавив закрытый ключ (очевидно, ключ «горелки», поскольку он будет обнародован) и ожидаемый результат подписи, чтобы сделать его полностью воспроизводимым. См. stackoverflow.com/help/minimal-reproducible-example
@carver, я показал в начальном описании этого вопроса фрагменты кода, описывающие мою проблему. Но также могу добавить, что затем я передаю подпись смарт-контракту и использую библиотеку ECDSA на Solidity (от OpenZeppelin) — функция ECDSA.recover для подписавшего извлечения.
@carver Я добавил в исходное описание ожидаемый результат подписи.

Ответы (3)

Поскольку вы упомянули в комментариях, что вы открыты для использования web3.py v5, вот подход v5 для подписи сообщения :

from eth_account import Account, messages

msg_hash_hex = "058c3b4c8e5dc4632b5c6b861b2c1861d53e426dc673c907ddf2651942b0f230"
private_key_hex = "b25c7db31feed9122727bf0939dc769a96564b2de4c4726d035b36ecf1e5b364"

#// This part prepares "version E" messages, using the EIP-191 standard
message = messages.encode_defunct(hexstr=msg_hash_hex)

#// This part signs any EIP-191-valid message
signed_message = Account.sign_message(message, private_key=private_key_hex)
print("signature =", signed_message.signature.hex())

Если вы хотите узнать больше об EIP-191, ознакомьтесь с оригинальным описанием EIP-191 . Он короткий и читаемый.

Этот фрагмент эквивалентен javascript:

msgHash = "0x058c3b4c8e5dc4632b5c6b861b2c1861d53e426dc673c907ddf2651942b0f230"
privateKeyUser = "b25c7db31feed9122727bf0939dc769a96564b2de4c4726d035b36ecf1e5b364"

// web3.js sign() *only* supports "version E" EIP-191 signing
// so it adds the preamble for you.
let signature = await web3.eth.accounts.sign(msgHash, '0x' + privateKeyUser);
console.log('signature ='+signature.signature);

sign()Обратите внимание, что метод javascript «подписывает произвольные данные», а не хэш сообщения. Таким образом, хотя вы, кажется, сначала хешируете его, вместо этого вы можете подписать исходное сообщение.

В версии Python подготовьте исходное сообщение для подписи с помощью: encode_defunct(text=original_message).

Спасибо за ответ! Но я не преуспел в вашем совете:
1) В версии с web3py у меня ошибка: "AttributeError: у объекта 'bytes' нет атрибута 'encode'" Я преобразовал переменную "msg_hash" в текст. Строка с "encode_defunct" стала: "message = encode_defunct(text="0x058c3b4c8e5dc4632b5c6b861b2c1861d53e426dc673c907ddf2651942b0f230")"
И после этого запустилось без ошибок. и результат: 0x4ef46c84d3b33927369c69da0aa46328a80c88f747ee33e9a597e76e8cf8a723642302bf793c1b80b8979a97416ff64423f0b4cad8a1f0e5e141b3f82a81bb3
2) В версии с web3js у меня нет ошибок. И результат: 0xdccea59712c525f67783bc2c6bb5add55447d3f2122f30eccb602c3e629a609f2a13c74c32fcb15799c94d3e00753c7264aee93339b327c2130e2f02ce4abb5.
Как видите, результаты не те. Для справки: у меня версия web3py - 5.0.0b2, а версия web3js - 1.0.0-beta.55
Ах, извините за опечатку в encode_defunct. Я обновил ответ и получил тот же результат, что и вы с web3js.
Проверил, теперь работает корректно! @carver, спасибо большое!

Трудно сказать, не видя содержимого всех переменных, включая ключи.

Но я чувствую, что вы смешиваете необработанные байты и шестнадцатеричные строки ASCII - некоторые переменные не то, что вы думаете.

Если возможно, вы можете отредактировать свой вопрос с большим количеством отпечатков и результатов для сравнения?

Спасибо за ответ! Мне нужно написать переменную, где находится закрытый ключ? Я думаю, что это только одна вещь, которой не хватает здесь. Смешивание данных - по-моему, здесь я их явно написал строками). Пожалуйста, поправьте меня, если я вас неправильно понял.

Для тех, кто пришел сюда с web3.py < v5:

Используйте defunct_hash_message в сообщении перед использованием signHash.

from eth_account.messages import defunct_hash_message
prepared_message = defunct_hash_message(primitive=msgHash)
signature = web3.eth.account.signHash(prepared_message, '0x' + privateKeyUser)
print('signature =' + signature.signature.hex())