Skip to content

Commit

Permalink
WIP, no alloc
Browse files Browse the repository at this point in the history
  • Loading branch information
overcat committed Sep 6, 2024
1 parent 66d69b0 commit 883e531
Show file tree
Hide file tree
Showing 5 changed files with 288 additions and 65 deletions.
48 changes: 33 additions & 15 deletions src/convert.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,15 @@
// TODO: Could encode and decode, and the functions upstream that call them, be
// const fn's?

use crate::{crc::checksum, error::DecodeError};

// PublicKeyEd25519 32-bytes
// PrivateKeyEd25519 32-bytes
// PreAuthTx 32-bytes
// HashX 32-bytes
// MuxedAccountEd25519 40-bytes
// SignedPayloadEd25519 32 + 4 + 4 = 40-bytes min, 32 + 4 + 64 = 100-bytes max
// Contract 32-bytes
const MAX_PAYLOAD_LEN: usize = 32 + 4 + 64;
use crate::{crc::checksum, error::DecodeError, typ};

/// Get the length of the strkey encoded data.
///
/// # Arguments
///
/// * `input_len` - The length of the raw data.
pub fn encode_len(input_len: usize) -> usize {
let len = 1 + input_len + 2;
let len = 1 + input_len + 2; // ver + payload + crc
data_encoding::BASE32_NOPAD.encode_len(len)
}

Expand All @@ -43,7 +34,7 @@ pub fn encode_len(input_len: usize) -> usize {
/// // encode(0, &input, &mut output[..output_len]);
/// ```
pub fn encode(ver: u8, input: &[u8], output: &mut [u8]) {
let mut d = [0u8; 1 + MAX_PAYLOAD_LEN + 2];
let mut d = [0u8; 1 + typ::MAX_PAYLOAD_LEN + 2];
d[0] = ver;
d[1..=input.len()].copy_from_slice(input);
let crc = checksum(&d[..=input.len()]);
Expand All @@ -66,16 +57,43 @@ pub fn decode_len(input_len: usize) -> Result<usize, DecodeError> {
let len = data_encoding::BASE32_NOPAD
.decode_len(input_len)
.map_err(|_| DecodeError::Invalid)?;
if len < 3 || len > 1 + MAX_PAYLOAD_LEN + 2 {
if len < 3 || len > 1 + typ::MAX_PAYLOAD_LEN + 2 {
return Err(DecodeError::Invalid);
}
Ok(len - 3) // remove version byte and crc length
Ok(len - 1 - 2) // len - ver - crc
}

/// Decode the strkey to raw data.
///
/// # Arguments
///
/// * `input` - The encoded strkey.
/// * `output` - The raw data. We assume it is the correct size, and you can get the correct size by calling [decode_len].
///
/// # Returns
///
/// The version byte.
///
/// # Errors
///
/// This function will return an error if the strkey is invalid.
///
/// # Panics
///
/// This function will panic if the output buffer is not the correct size.
///
/// # Examples
///
/// ```rust
/// let mut output = [0u8; 100];
/// let input = "GA3D5KRYM6CB7OWQ6TWYRR3Z4T7GNZLKERYNZGGA5SOAOPIFY6YQHES5".as_bytes();
/// // let output_len = decode_len(input.len()).unwrap();
/// // let v = decode(input, &mut output[..output_len]).unwrap();
/// ```
pub fn decode(input: &[u8], output: &mut [u8]) -> Result<u8, DecodeError> {
let len = decode_len(input.len())? + 3;
assert_eq!(output.len(), len - 3);
let mut decoded = [0u8; 1 + MAX_PAYLOAD_LEN + 2];
let mut decoded = [0u8; 1 + typ::MAX_PAYLOAD_LEN + 2];
let _ = data_encoding::BASE32_NOPAD
.decode_mut(input, &mut decoded[..len])
.map_err(|_| DecodeError::Invalid)?;
Expand Down
155 changes: 123 additions & 32 deletions src/ed25519.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::{
convert::{decode, encode},
error::DecodeError,
version,
typ, version,
};

use crate::convert::encode_len;
Expand All @@ -13,7 +13,7 @@ use alloc::string::String;
use core::fmt::Display;

#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct PrivateKey(pub [u8; 32]);
pub struct PrivateKey(pub [u8; typ::RAW_PRIVATE_KEY_LEN]);

impl Debug for PrivateKey {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
Expand All @@ -29,34 +29,56 @@ impl Debug for PrivateKey {
impl PrivateKey {
#[cfg(feature = "alloc")]
pub fn to_string(&self) -> String {
let mut output = [0; 56];
let mut output = [0; typ::ENCODED_PRIVATE_KEY_LEN];
self.to_encoded(&mut output);
String::from_utf8(output.to_vec()).unwrap()
}

/// Returns the length of the encoded [PrivateKey].
///
/// # Note
///
/// The encoded [PrivateKey] length is always [`typ::ENCODED_PRIVATE_KEY_LEN`] bytes.
pub fn encoded_len(&self) -> usize {
56
typ::ENCODED_PRIVATE_KEY_LEN
}

/// Encodes the private key into the provided buffer.
/// Encodes the [PrivateKey] into the provided buffer.
///
/// ### Panics
/// # Panics
///
/// If the buffer's length is not equal to the encoded private key length,
/// which is 56 bytes.
/// If the output buffer's length is not equal to the encoded [PrivateKey] length.
pub fn to_encoded(&self, output: &mut [u8]) {
encode(version::PRIVATE_KEY_ED25519, &self.0, output);
}

/// Creates a [PrivateKey] from the raw payload.
///
/// # Arguments
///
/// * `payload` - The raw payload.
///
/// # Errors
///
/// Returns an error if the payload is not a valid [PrivateKey].
pub fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
match payload.try_into() {
Ok(ed25519) => Ok(Self(ed25519)),
Err(_) => Err(DecodeError::Invalid),
}
}

/// Creates a [PrivateKey] from the strkey encoded [PrivateKey].
///
/// # Arguments
///
/// * `s` - The strkey encoded [PrivateKey].
///
/// # Errors
///
/// Returns an error if the strkey is not a valid [PrivateKey].
pub fn from_string(s: &str) -> Result<Self, DecodeError> {
let mut payload = [0u8; 32];
let mut payload = [0u8; typ::RAW_PRIVATE_KEY_LEN];
let ver = decode(s.as_bytes(), &mut payload)?;
match ver {
version::PRIVATE_KEY_ED25519 => Self::from_payload(&payload),
Expand All @@ -81,7 +103,7 @@ impl FromStr for PrivateKey {
}

#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct PublicKey(pub [u8; 32]);
pub struct PublicKey(pub [u8; typ::RAW_PUBLIC_KEY_LEN]);

impl Debug for PublicKey {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
Expand All @@ -97,34 +119,56 @@ impl Debug for PublicKey {
impl PublicKey {
#[cfg(feature = "alloc")]
pub fn to_string(&self) -> String {
let mut output = [0; 56];
let mut output = [0; typ::ENCODED_PUBLIC_KEY_LEN];
self.to_encoded(&mut output);
String::from_utf8(output.to_vec()).unwrap()
}

/// Returns the length of the encoded [PublicKey].
///
/// # Note
///
/// The encoded [PublicKey] length is always [`typ::PUBLIC_KEY_ED25519`] bytes.
pub fn encoded_len(&self) -> usize {
56
typ::ENCODED_PUBLIC_KEY_LEN
}

/// Encodes the public key into the provided buffer.
/// Encodes the [PublicKey] into the provided buffer.
///
/// ### Panics
/// # Panics
///
/// If the buffer's length is not equal to the encoded public key length,
/// which is 56 bytes.
/// If the output buffer's length is not equal to the encoded private key length.
pub fn to_encoded(&self, output: &mut [u8]) {
encode(version::PUBLIC_KEY_ED25519, &self.0, output);
}

/// Creates a [PublicKey] from the raw payload.
///
/// # Arguments
///
/// * `payload` - The raw payload.
///
/// # Errors
///
/// Returns an error if the payload is not a valid [PublicKey].
pub fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
match payload.try_into() {
Ok(ed25519) => Ok(Self(ed25519)),
Err(_) => Err(DecodeError::Invalid),
}
}

/// Creates a [PublicKey] from the strkey encoded [PublicKey].
///
/// # Arguments
///
/// * `s` - The strkey encoded [PublicKey].
///
/// # Errors
///
/// Returns an error if the strkey is not a valid [PublicKey].
pub fn from_string(s: &str) -> Result<Self, DecodeError> {
let mut payload = [0u8; 32];
let mut payload = [0u8; typ::RAW_PUBLIC_KEY_LEN];

let ver = decode(s.as_bytes(), &mut payload)?;
match ver {
Expand All @@ -151,7 +195,7 @@ impl FromStr for PublicKey {

#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct MuxedAccount {
pub ed25519: [u8; 32],
pub ed25519: [u8; typ::RAW_PUBLIC_KEY_LEN],
pub id: u64,
}

Expand All @@ -177,29 +221,42 @@ impl Debug for MuxedAccount {
impl MuxedAccount {
#[cfg(feature = "alloc")]
pub fn to_string(&self) -> String {
let mut output = [0; 69];
let mut output = [0; typ::ENCODED_MUXED_ACCOUNT_LEN];
self.to_encoded(&mut output);
String::from_utf8(output.to_vec()).unwrap()
}

/// Returns the length of the encoded [MuxedAccount].
///
/// # Note
///
/// The encoded [MuxedAccount] length is always [`typ::ENCODED_MUXED_ACCOUNT_LEN`] bytes.
pub fn encoded_len(&self) -> usize {
69
typ::ENCODED_MUXED_ACCOUNT_LEN
}

/// Encodes the muxed account into the provided buffer.
/// Encodes the [MuxedAccount] into the provided buffer.
///
/// ### Panics
/// # Panics
///
/// If the buffer's length is not equal to the encoded muxed account length,
/// which is 69 bytes.
/// If the output buffer's length is not equal to the encoded [MuxedAccount] length.
pub fn to_encoded(&self, output: &mut [u8]) {
let mut payload: [u8; 40] = [0; 40];
let mut payload = [0u8; typ::RAW_MUXED_ACCOUNT_LEN];
let (ed25519, id) = payload.split_at_mut(32);
ed25519.copy_from_slice(&self.ed25519);
id.copy_from_slice(&self.id.to_be_bytes());
encode(version::MUXED_ACCOUNT_ED25519, &payload, output);
}

/// Creates a [MuxedAccount] from the raw payload.
///
/// # Arguments
///
/// * `payload` - The raw payload.
///
/// # Errors
///
/// Returns an error if the payload is not a valid [MuxedAccount].
pub fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
if payload.len() < 40 {
return Err(DecodeError::Invalid);
Expand All @@ -211,8 +268,17 @@ impl MuxedAccount {
})
}

/// Creates a [MuxedAccount] from the strkey encoded [MuxedAccount].
///
/// # Arguments
///
/// * `s` - The strkey encoded [MuxedAccount].
///
/// # Errors
///
/// Returns an error if the strkey is not a valid [MuxedAccount].
pub fn from_string(s: &str) -> Result<Self, DecodeError> {
let mut payload = [0u8; 40];
let mut payload = [0u8; typ::RAW_MUXED_ACCOUNT_LEN];
let ver = decode(s.as_bytes(), &mut payload)?;
match ver {
version::MUXED_ACCOUNT_ED25519 => Self::from_payload(&payload),
Expand Down Expand Up @@ -241,7 +307,7 @@ impl FromStr for MuxedAccount {
/// The payload must not have a size larger than u32::MAX.
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct SignedPayload {
pub ed25519: [u8; 32],
pub ed25519: [u8; typ::RAW_PUBLIC_KEY_LEN],
pub payload: [u8; 64],
pub payload_len: usize,
}
Expand All @@ -267,23 +333,30 @@ impl SignedPayload {
/// Returns the strkey string for the signed payload signer.
#[cfg(feature = "alloc")]
pub fn to_string(&self) -> String {
let mut output = [0; 165];
let mut output = [0; typ::ENCODED_SIGNED_PAYLOAD_MAX_LEN];
let encoded_len = self.encoded_len();
self.to_encoded(&mut output[..encoded_len]);
String::from_utf8(output[..encoded_len].to_vec()).unwrap()
}

/// Returns the length of the encoded [SignedPayload].
///
/// # Note
///
/// The encoded [SignedPayload] length is between [`typ::ENCODED_SIGNED_PAYLOAD_MIN_LEN`]
/// and [`typ::ENCODED_SIGNED_PAYLOAD_MAX_LEN`] bytes.
pub fn encoded_len(&self) -> usize {
let inner_payload_len = self.payload_len + (4 - self.payload_len % 4) % 4;
encode_len(32 + 4 + inner_payload_len)
}

/// Encodes the signed payload into the provided buffer.
/// Encodes the [SignedPayload] into the provided buffer.
///
/// # Panics
///
/// ### Panics
/// TODO
/// If the output buffer's length is not equal to the encoded [SignedPayload] length.
pub fn to_encoded(&self, output: &mut [u8]) {
let mut payload = [0u8; 32 + 4 + 64];
let mut payload = [0u8; typ::RAW_SIGNED_PAYLOAD_MAX_LEN];
let inner_payload_len = self.payload_len + (4 - self.payload_len % 4) % 4;
payload[..32].copy_from_slice(&self.ed25519);
payload[32..32 + 4].copy_from_slice(&(self.payload_len as u32).to_be_bytes());
Expand All @@ -295,6 +368,15 @@ impl SignedPayload {
);
}

/// Creates a [SignedPayload] from the raw payload.
///
/// # Arguments
///
/// * `payload` - The raw payload.
///
/// # Errors
///
/// Returns an error if the payload is not a valid [SignedPayload].
pub fn from_payload(payload: &[u8]) -> Result<Self, DecodeError> {
// 32-byte for the signer, 4-byte for the payload size, then either 4-byte for the
// min or 64-byte for the max payload
Expand Down Expand Up @@ -367,6 +449,15 @@ impl SignedPayload {
})
}

/// Creates a [SignedPayload] from the strkey encoded [SignedPayload].
///
/// # Arguments
///
/// * `s` - The strkey encoded [SignedPayload].
///
/// # Errors
///
/// Returns an error if the strkey is not a valid [SignedPayload].
pub fn from_string(s: &str) -> Result<Self, DecodeError> {
let mut payload = [0u8; 100];
let ver = decode(s.as_bytes(), &mut payload)?;
Expand Down
Loading

0 comments on commit 883e531

Please sign in to comment.