Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading