Add sign function

This commit is contained in:
Bogdan-Ștefan Neacșu
2022-09-12 12:54:33 +03:00
parent 60d17389d0
commit 0f147750ae
3 changed files with 78 additions and 1 deletions
+6
View File
@@ -28,4 +28,10 @@ pub enum LedgerError {
#[error("Bip32 - {0}")]
Bip32(#[from] bip32::Error),
#[error("Signature error - {0}")]
Signature(#[from] k256::ecdsa::Error),
#[error("No message found for signing transaction")]
NoMessageFound,
}
+47 -1
View File
@@ -4,10 +4,13 @@
pub mod addr_secp265k1;
pub mod error;
pub(crate) mod helpers;
mod sign_secp265k1;
pub mod version;
use crate::addr_secp265k1::AddrSecp265k1Response;
use crate::error::LedgerError;
use crate::helpers::path_bytes;
use crate::sign_secp265k1::SignSecp265k1Response;
use crate::version::VersionResponse;
use bip32::DerivationPath;
use error::Result;
@@ -17,9 +20,14 @@ use ledger_transport_hid::TransportNativeHID;
const CLA: u8 = 0x55;
const INS_GET_VERSION: u8 = 0x00;
const _INS_SIGN_SECP256K1: u8 = 0x02;
const INS_SIGN_SECP256K1: u8 = 0x02;
const INS_GET_ADDR_SECP256K1: u8 = 0x04;
const PAYLOAD_TYPE_INIT: u8 = 0x00;
const PAYLOAD_TYPE_ADD: u8 = 0x01;
const PAYLOAD_TYPE_LAST: u8 = 0x02;
const CHUNK_SIZE: usize = 250;
/// Manage hardware Ledger device with Cosmos specific operations, as described in the
/// specification: https://github.com/cosmos/ledger-cosmos/blob/main/docs/APDUSPEC.md
pub struct CosmosLedger {
@@ -81,4 +89,42 @@ impl CosmosLedger {
let response = self.transport.exchange(&command)?;
AddrSecp265k1Response::try_from(response)
}
pub fn sign_secp265k1(
&self,
path: DerivationPath,
message: String,
) -> Result<SignSecp265k1Response> {
let serialized_path: Vec<u8> = path_bytes(path)?.into_iter().flatten().collect();
let mut chunks = vec![serialized_path];
if message.is_empty() {
return Err(LedgerError::NoMessageFound);
}
for chunk in message.into_bytes().chunks(CHUNK_SIZE) {
chunks.push(chunk.to_vec());
}
let length = chunks.len();
for (idx, chunk) in chunks.into_iter().enumerate() {
let payload_desc = if idx == 0 {
PAYLOAD_TYPE_INIT
} else if idx + 1 == length {
PAYLOAD_TYPE_LAST
} else {
PAYLOAD_TYPE_ADD
};
let command = APDUCommand {
cla: CLA,
ins: INS_SIGN_SECP256K1,
p1: payload_desc,
p2: 0,
data: chunk,
};
let sign_response = self.transport.exchange(&command)?;
if payload_desc == PAYLOAD_TYPE_LAST {
return SignSecp265k1Response::try_from(sign_response);
}
}
// It should never reach this, as the message is not empty
Err(LedgerError::NoMessageFound)
}
}
+25
View File
@@ -0,0 +1,25 @@
// Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::LedgerError;
use crate::helpers::answer_bytes;
use k256::ecdsa::Signature;
use ledger_transport::APDUAnswer;
/// Version and status data of the device.
pub struct SignSecp265k1Response {
/// DER encoded signature data
pub signature: Signature,
}
impl TryFrom<APDUAnswer<Vec<u8>>> for SignSecp265k1Response {
type Error = LedgerError;
fn try_from(answer: APDUAnswer<Vec<u8>>) -> Result<Self, Self::Error> {
let bytes = answer_bytes(&answer)?;
Ok(SignSecp265k1Response {
signature: Signature::from_der(bytes)?,
})
}
}