Skip to content

Commit

Permalink
fix(rust/rbac-registration): extract type in CIP509 to its own file a…
Browse files Browse the repository at this point in the history
…nd implement conversion (#97)

* fix: extrat type to its own type and impl conversion

Signed-off-by: bkioshn <[email protected]>

* fix: make util public

Signed-off-by: bkioshn <[email protected]>

* fix: make cip19 utils public

Signed-off-by: bkioshn <[email protected]>

* fix: remove uuidv4 and ed25519pubkey type

Signed-off-by: bkioshn <[email protected]>

* chore: fix naming

Signed-off-by: bkioshn <[email protected]>

* fix: naming

Signed-off-by: bkioshn <[email protected]>

* fix: use ShelleyAddress instead of Shelley Payment part

Signed-off-by: bkioshn <[email protected]>

* fix: naming

Signed-off-by: bkioshn <[email protected]>

---------

Signed-off-by: bkioshn <[email protected]>
  • Loading branch information
bkioshn authored Dec 6, 2024
1 parent 47b5514 commit 1747c61
Show file tree
Hide file tree
Showing 12 changed files with 141 additions and 146 deletions.
2 changes: 2 additions & 0 deletions rust/rbac-registration/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ bech32 = "0.11.0"
dashmap = "6.1.0"
blake2b_simd = "1.0.2"
tracing = "0.1.40"
ed25519-dalek = "2.1.1"
uuid = "1.11.0"

c509-certificate = { version = "0.0.3", git = "https://github.com/input-output-hk/catalyst-libs.git" , tag = "v0.0.3" }
pallas = { version = "0.30.1", git = "https://github.com/input-output-hk/catalyst-pallas.git", rev = "9b5183c8b90b90fe2cc319d986e933e9518957b3" }
96 changes: 25 additions & 71 deletions rust/rbac-registration/src/cardano/cip509/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
// cspell: words pkix

pub mod rbac;
pub(crate) mod utils;
pub mod types;
pub mod utils;
pub(crate) mod validation;
pub mod x509_chunks;

Expand All @@ -15,6 +16,8 @@ use minicbor::{
};
use pallas::{crypto::hash::Hash, ledger::traverse::MultiEraTx};
use strum_macros::FromRepr;
use types::tx_input_hash::TxInputHash;
use uuid::Uuid;
use validation::{
validate_aux, validate_payment_key, validate_role_singing_key, validate_stake_public_key,
validate_txn_inputs_hash,
Expand All @@ -35,7 +38,7 @@ pub const LABEL: u64 = 509;
#[derive(Debug, PartialEq, Clone, Default)]
pub struct Cip509 {
/// `UUIDv4` Purpose .
pub purpose: UuidV4, // (bytes .size 16)
pub purpose: Uuid, // (bytes .size 16)
/// Transaction inputs hash.
pub txn_inputs_hash: TxInputHash, // bytes .size 16
/// Optional previous transaction ID.
Expand All @@ -51,15 +54,15 @@ pub struct Cip509 {
#[derive(Debug, PartialEq, Clone, Default)]
pub struct Cip509Validation {
/// Boolean value for the validity of the transaction inputs hash.
pub valid_txn_inputs_hash: bool,
pub is_valid_txn_inputs_hash: bool,
/// Boolean value for the validity of the auxiliary data.
pub valid_aux: bool,
/// Boolean value for the validity of the public key.
pub valid_public_key: bool,
pub is_valid_aux: bool,
/// Boolean value for the validity of the stake public key.
pub is_valid_stake_public_key: bool,
/// Boolean value for the validity of the payment key.
pub valid_payment_key: bool,
pub is_valid_payment_key: bool,
/// Boolean value for the validity of the signing key.
pub signing_key: bool,
pub is_valid_signing_key: bool,
/// Additional data from the CIP509 validation..
pub additional_data: AdditionalData,
}
Expand All @@ -71,54 +74,6 @@ pub struct AdditionalData {
pub precomputed_aux: Vec<u8>,
}

/// `UUIDv4` representing in 16 bytes.
#[derive(Debug, PartialEq, Clone, Default)]
pub struct UuidV4([u8; 16]);

impl From<[u8; 16]> for UuidV4 {
fn from(bytes: [u8; 16]) -> Self {
UuidV4(bytes)
}
}

impl TryFrom<Vec<u8>> for UuidV4 {
type Error = &'static str;

fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
if vec.len() == 16 {
let mut array = [0u8; 16];
array.copy_from_slice(&vec);
Ok(UuidV4(array))
} else {
Err("Input Vec must be exactly 16 bytes")
}
}
}

/// Transaction input hash representing in 16 bytes.
#[derive(Debug, PartialEq, Clone, Default)]
pub struct TxInputHash([u8; 16]);

impl From<[u8; 16]> for TxInputHash {
fn from(bytes: [u8; 16]) -> Self {
TxInputHash(bytes)
}
}

impl TryFrom<Vec<u8>> for TxInputHash {
type Error = &'static str;

fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
if vec.len() == 16 {
let mut array = [0u8; 16];
array.copy_from_slice(&vec);
Ok(TxInputHash(array))
} else {
Err("Input Vec must be exactly 16 bytes")
}
}
}

/// Enum of CIP509 metadatum with its associated unsigned integer value.
#[allow(clippy::module_name_repetitions)]
#[derive(FromRepr, Debug, PartialEq)]
Expand Down Expand Up @@ -147,7 +102,7 @@ impl Decode<'_, ()> for Cip509 {
match key {
Cip509IntIdentifier::Purpose => {
cip509_metadatum.purpose =
UuidV4::try_from(decode_bytes(d, "CIP509 purpose")?).map_err(|_| {
Uuid::try_from(decode_bytes(d, "CIP509 purpose")?).map_err(|_| {
decode::Error::message("Invalid data size of Purpose")
})?;
},
Expand Down Expand Up @@ -217,32 +172,31 @@ impl Cip509 {
pub fn validate(
&self, txn: &MultiEraTx, validation_report: &mut Vec<String>,
) -> Cip509Validation {
let tx_input_validate =
let is_valid_txn_inputs_hash =
validate_txn_inputs_hash(self, txn, validation_report).unwrap_or(false);
let (aux_validate, precomputed_aux) =
let (is_valid_aux, precomputed_aux) =
validate_aux(txn, validation_report).unwrap_or_default();
let mut stake_key_validate = true;
let mut payment_key_validate = true;
let mut signing_key = true;
// Validate the role 0
let mut is_valid_stake_public_key = true;
let mut is_valid_payment_key = true;
let mut is_valid_signing_key = true;
if let Some(role_set) = &self.x509_chunks.0.role_set {
// Validate only role 0
for role in role_set {
if role.role_number == 0 {
stake_key_validate =
is_valid_stake_public_key =
validate_stake_public_key(self, txn, validation_report).unwrap_or(false);
payment_key_validate =
is_valid_payment_key =
validate_payment_key(txn, role, validation_report).unwrap_or(false);
signing_key = validate_role_singing_key(role, validation_report);
is_valid_signing_key = validate_role_singing_key(role, validation_report);
}
}
}
Cip509Validation {
valid_txn_inputs_hash: tx_input_validate,
valid_aux: aux_validate,
valid_public_key: stake_key_validate,
valid_payment_key: payment_key_validate,
signing_key,
is_valid_txn_inputs_hash,
is_valid_aux,
is_valid_stake_public_key,
is_valid_payment_key,
is_valid_signing_key,
additional_data: AdditionalData { precomputed_aux },
}
}
Expand Down
6 changes: 3 additions & 3 deletions rust/rbac-registration/src/cardano/cip509/rbac/certs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,11 @@ impl Decode<'_, ()> for C509Cert {
#[derive(Debug, PartialEq, Clone)]
pub struct C509CertInMetadatumReference {
/// Transaction output field.
txn_output_field: u8,
pub txn_output_field: u8,
/// Transaction output index.
txn_output_index: u64,
pub txn_output_index: u64,
/// Optional certificate reference.
cert_ref: Option<Vec<u64>>,
pub cert_ref: Option<Vec<u64>>,
}

impl Decode<'_, ()> for C509CertInMetadatumReference {
Expand Down
11 changes: 1 addition & 10 deletions rust/rbac-registration/src/cardano/cip509/rbac/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use pub_key::SimplePublicKeyType;
use role_data::RoleData;
use strum_macros::FromRepr;

use super::types::cert_key_hash::CertKeyHash;
use crate::utils::decode_helper::{
decode_any, decode_array_len, decode_bytes, decode_helper, decode_map_len,
};
Expand All @@ -38,16 +39,6 @@ pub struct Cip509RbacMetadata {
pub purpose_key_data: HashMap<u16, Vec<u8>>,
}

/// Certificate key hash use in revocation list.
#[derive(Debug, PartialEq, Clone, Default)]
pub struct CertKeyHash([u8; 16]);

impl From<[u8; 16]> for CertKeyHash {
fn from(bytes: [u8; 16]) -> Self {
CertKeyHash(bytes)
}
}

/// The first valid purpose key.
const FIRST_PURPOSE_KEY: u16 = 200;
/// The last valid purpose key.
Expand Down
44 changes: 6 additions & 38 deletions rust/rbac-registration/src/cardano/cip509/rbac/pub_key.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Public key type for RBAC metadata
use ed25519_dalek::VerifyingKey;
use minicbor::{decode, Decode, Decoder};
use pallas::codec::utils::Bytes;

use super::tag::KeyTag;
use crate::utils::decode_helper::{decode_bytes, decode_tag};
Expand All @@ -15,42 +15,7 @@ pub enum SimplePublicKeyType {
/// Deleted indicates the key is deleted.
Deleted,
/// Ed25519 public key.
Ed25519(Ed25519PublicKey),
}

/// 32 bytes Ed25519 public key.
#[derive(Debug, PartialEq, Clone, Default, Eq, Hash)]
pub struct Ed25519PublicKey([u8; 32]);

impl From<[u8; 32]> for Ed25519PublicKey {
fn from(bytes: [u8; 32]) -> Self {
Ed25519PublicKey(bytes)
}
}

impl TryFrom<Bytes> for Ed25519PublicKey {
type Error = &'static str;

fn try_from(bytes: Bytes) -> Result<Self, Self::Error> {
let byte_vec: Vec<u8> = bytes.into();

if byte_vec.len() != 32 {
return Err("Invalid length for Ed25519 public key: expected 32 bytes.");
}

let byte_array: [u8; 32] = byte_vec
.try_into()
.map_err(|_| "Failed to convert Vec<u8> to [u8; 32]")?;

Ok(Ed25519PublicKey::from(byte_array))
}
}

impl From<Ed25519PublicKey> for Bytes {
fn from(val: Ed25519PublicKey) -> Self {
let vec: Vec<u8> = val.0.to_vec();
Bytes::from(vec)
}
Ed25519(VerifyingKey),
}

impl Decode<'_, ()> for SimplePublicKeyType {
Expand All @@ -65,7 +30,10 @@ impl Decode<'_, ()> for SimplePublicKeyType {
let mut ed25519 = [0u8; 32];
if bytes.len() == 32 {
ed25519.copy_from_slice(&bytes);
Ok(Self::Ed25519(Ed25519PublicKey(ed25519)))
let pubkey = VerifyingKey::from_bytes(&ed25519).map_err(|e| {
decode::Error::message(format!("Failed to convert Ed25519 public key in SimplePublicKeyType {e}"))
})?;
Ok(Self::Ed25519(pubkey))
} else {
Err(decode::Error::message(format!(
"Invalid length for Ed25519 key, got {}",
Expand Down
37 changes: 37 additions & 0 deletions rust/rbac-registration/src/cardano/cip509/types/cert_key_hash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//! Certificate key hash type
/// Certificate key hash use in revocation list.
#[derive(Debug, PartialEq, Clone, Default)]
pub struct CertKeyHash([u8; 16]);

impl From<[u8; 16]> for CertKeyHash {
fn from(bytes: [u8; 16]) -> Self {
CertKeyHash(bytes)
}
}

impl TryFrom<Vec<u8>> for CertKeyHash {
type Error = &'static str;

fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
if vec.len() == 16 {
let mut array = [0u8; 16];
array.copy_from_slice(&vec);
Ok(CertKeyHash(array))
} else {
Err("Input Vec must be exactly 16 bytes")
}
}
}

impl From<CertKeyHash> for Vec<u8> {
fn from(val: CertKeyHash) -> Self {
val.0.to_vec()
}
}

impl From<CertKeyHash> for [u8; 16] {
fn from(val: CertKeyHash) -> Self {
val.0
}
}
4 changes: 4 additions & 0 deletions rust/rbac-registration/src/cardano/cip509/types/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
//! Types use in CIP-509
pub mod cert_key_hash;
pub mod tx_input_hash;
37 changes: 37 additions & 0 deletions rust/rbac-registration/src/cardano/cip509/types/tx_input_hash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//! Transaction input hash type
/// Transaction input hash representing in 16 bytes.
#[derive(Debug, PartialEq, Clone, Default)]
pub struct TxInputHash([u8; 16]);

impl From<[u8; 16]> for TxInputHash {
fn from(bytes: [u8; 16]) -> Self {
TxInputHash(bytes)
}
}

impl TryFrom<Vec<u8>> for TxInputHash {
type Error = &'static str;

fn try_from(vec: Vec<u8>) -> Result<Self, Self::Error> {
if vec.len() == 16 {
let mut array = [0u8; 16];
array.copy_from_slice(&vec);
Ok(TxInputHash(array))
} else {
Err("Input Vec must be exactly 16 bytes")
}
}
}

impl From<TxInputHash> for Vec<u8> {
fn from(val: TxInputHash) -> Self {
val.0.to_vec()
}
}

impl From<TxInputHash> for [u8; 16] {
fn from(val: TxInputHash) -> Self {
val.0
}
}
2 changes: 1 addition & 1 deletion rust/rbac-registration/src/cardano/cip509/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
//! Utility functions for CIP-509
pub(crate) mod cip19;
pub mod cip19;
2 changes: 1 addition & 1 deletion rust/rbac-registration/src/cardano/cip509/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ pub(crate) fn validate_txn_inputs_hash(
return None;
},
};
Some(TxInputHash(inputs_hash) == cip509.txn_inputs_hash)
Some(TxInputHash::from(inputs_hash) == cip509.txn_inputs_hash)
} else {
validation_report.push(format!("{function_name}, Unsupported transaction era for"));
None
Expand Down
Loading

0 comments on commit 1747c61

Please sign in to comment.