Я пишу небольшую программу моделирования блокчейна на Rust и пытаюсь использовать ключ подписи ECDSA, чтобы подписывать транзакции, добавляемые в блокчейн.
У меня есть следующая пара ключей, настроенная в файле crypto.rs:
pub struct KeyPair {
pub name: String,
pub public_key: String,
private_key: String,
}
и следующая реализация для генерации ключей:
impl KeyPair {
pub fn generate(name: String, key_store: &mut KeyStore) -> KeyPair {
// private key first
let secret = SecretKey::random(&mut OsRng);
let private_key = hex::encode(&secret.to_bytes());
// then public key
let public_key = hex::encode(secret.public_key().to_sec1_bytes());
let key_pair: KeyPair = KeyPair {
name,
public_key,
private_key,
};
// store a clone and return the original for further operations
key_store.append_key_pair(key_pair.clone());
key_store.write();
key_pair
}
}
Тест генерирует следующее в файле с именем key_store.json:
{
"keys": [
{
"name": "TEST",
"public_key": "040eda3b0d1b30a78cc830ab9e69dc25a52d5448c3c8228511481a67b1f6420bc55beb4efc297a49a657cfe08b7873293e78fef553724453f55eea3656a6369d5a",
"private_key": "ccb789f12826fd81b45f27489b73ac5650f46f9b8f0281922f459be515f018b6"
}
]
}
Теперь, чтобы подписать хэш транзакции, мне нужно получить ключ подписи из закрытого ключа (SecretKey), но, похоже, ничего из того, что я делаю, не работает.
Я пытался извлечь подпись с помощью этой функции, но она вызывает панику signature error:
pub fn get_signature(&self, hash: &String) -> String {
let private_key = self.get_private_key();
let signing_key = match private_key.parse::<SigningKey>() {
Ok(key) => key,
Err(e) => panic!("Error parsing signing key from private key: {}", e),
};
let signature: Signature = signing_key.sign(&hash.as_bytes());
signature.to_string()
}
Я использовал эту статью SO, чтобы понять реализацию:
Как я могу экспортировать (хранить) пару ключей ecdsa в Rust?
в этой реализации используется pem, но я решил использовать байтовую строку, преобразованную в шестнадцатеричный формат, поскольку это распространенный способ хранения ключей.
Эта попытка приводит к панике с этим сообщением Error parsing bytes to String: invalid utf-8 sequence of 1 bytes from index 0:
pub fn get_signature(&self, hash: &String) -> String {
let private_key: String = self.get_private_key();
let decoded: Vec<u8> = match hex::decode(&private_key) {
Ok(bytes) => bytes,
Err(e) => panic!("Error decoding bytes: {}", e),
};
let str_from_bytes: String = match String::from_utf8(decoded) {
Ok(s) => s,
Err(e) => panic!("Error parsing bytes to String: {}", e),
};
let signing_key = match str_from_bytes.parse::<SigningKey>() {
Ok(key) => key,
Err(e) => panic!("Error parsing signing key from private key: {}", e),
};
let signature: Signature = signing_key.sign(&hash.as_bytes());
signature.to_string()
}
Кто-нибудь знает, как получить ключ подписи из SecretKey после преобразования в шестнадцатеричный?
Спасибо

После экспериментов эта функция возвращает подпись и ключ подписи, используемый для последующей проверки подписи.
pub fn get_signature(&self, hash: &String) -> (Signature, SigningKey) {
let private_key = self.get_private_key();
let key_bytes = hex::decode(&private_key).unwrap();
let signing_key = SigningKey::from_slice(key_bytes.as_slice()).unwrap();
let signature: Signature = signing_key.sign(&hash.as_bytes());
(signature, signing_key)
}
Использование from_slice для инициализации SigningKey работает:
SigningKey::from_slice(key_bytes.as_slice()).unwrap()
Для полноты сопровождающая функция verify выглядит так:
pub fn verify(&self, signature: Signature, signing_key: SigningKey, hash: String) -> bool {
let verifying_key = VerifyingKey::from(&signing_key);
let verified = match verifying_key.verify(&hash.as_bytes(), &signature) {
Ok(_res) => true,
Err(_) => false,
};
verified
}
Комментарии и альтернативные решения приветствуются, поскольку я не на 100% уверен, что это лучший способ сделать это, но он работает достаточно хорошо.