v0.3.10-pre.002
This commit is contained in:
67
crates/ksp-raw-transaction-lib/src/signature.rs
Normal file
67
crates/ksp-raw-transaction-lib/src/signature.rs
Normal file
@@ -0,0 +1,67 @@
|
||||
// file: crates/ksp-raw-transaction-lib/src/signature.rs
|
||||
// version: 1
|
||||
|
||||
/// Maximum UTF-8 byte length admitted for one textual Base58 Solana transaction signature.
|
||||
pub const MAX_RAW_TRANSACTION_SIGNATURE_TEXT_BYTES: usize = 88;
|
||||
/// Minimum UTF-8 byte length admitted for one textual Base58 Solana transaction signature.
|
||||
pub const MIN_RAW_TRANSACTION_SIGNATURE_TEXT_BYTES: usize = 64;
|
||||
|
||||
/// Parses one bounded Base58 Solana transaction signature to exactly 64 canonical bytes.
|
||||
pub fn parse_raw_transaction_signature(value: &str) -> ksp_core_lib::Result<ksp_store_api::RawTransactionSignature> {
|
||||
let text = value.as_bytes();
|
||||
if text.len() < crate::MIN_RAW_TRANSACTION_SIGNATURE_TEXT_BYTES || text.len() > crate::MAX_RAW_TRANSACTION_SIGNATURE_TEXT_BYTES {
|
||||
return std::result::Result::Err(
|
||||
crate::signature_error()
|
||||
.with_context("actual_len", text.len().to_string())
|
||||
.with_context("minimum_len", crate::MIN_RAW_TRANSACTION_SIGNATURE_TEXT_BYTES.to_string())
|
||||
.with_context("maximum_len", crate::MAX_RAW_TRANSACTION_SIGNATURE_TEXT_BYTES.to_string()),
|
||||
);
|
||||
}
|
||||
let mut decoded = [0_u8; 64];
|
||||
let mut leading_zeroes = 0_usize;
|
||||
for byte in text {
|
||||
if *byte != b'1' {
|
||||
break;
|
||||
}
|
||||
leading_zeroes += 1;
|
||||
}
|
||||
for byte in text {
|
||||
let digit = match base58_digit(*byte) {
|
||||
std::option::Option::Some(digit) => digit,
|
||||
std::option::Option::None => return std::result::Result::Err(crate::signature_error()),
|
||||
};
|
||||
let mut carry = u32::from(digit);
|
||||
for output in decoded.iter_mut().rev() {
|
||||
let expanded = (u32::from(*output) * 58) + carry;
|
||||
*output = (expanded & 0xff) as u8;
|
||||
carry = expanded >> 8;
|
||||
}
|
||||
if carry != 0 {
|
||||
return std::result::Result::Err(crate::signature_error());
|
||||
}
|
||||
}
|
||||
let significant_len = match decoded.iter().position(|byte| return *byte != 0) {
|
||||
std::option::Option::Some(index) => decoded.len() - index,
|
||||
std::option::Option::None => 0,
|
||||
};
|
||||
if leading_zeroes + significant_len != decoded.len() {
|
||||
return std::result::Result::Err(crate::signature_error());
|
||||
}
|
||||
return std::result::Result::Ok(ksp_store_api::RawTransactionSignature::new(decoded));
|
||||
}
|
||||
|
||||
fn base58_digit(byte: u8) -> std::option::Option<u8> {
|
||||
return match byte {
|
||||
b'1'..=b'9' => std::option::Option::Some(byte - b'1'),
|
||||
b'A'..=b'H' => std::option::Option::Some((byte - b'A') + 9),
|
||||
b'J'..=b'N' => std::option::Option::Some((byte - b'J') + 17),
|
||||
b'P'..=b'Z' => std::option::Option::Some((byte - b'P') + 22),
|
||||
b'a'..=b'k' => std::option::Option::Some((byte - b'a') + 33),
|
||||
b'm'..=b'z' => std::option::Option::Some((byte - b'm') + 44),
|
||||
_ => std::option::Option::None,
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "../unit_tests/signature.rs"]
|
||||
mod tests;
|
||||
Reference in New Issue
Block a user