Skip to content

Commit 47b5514

Browse files
authored
fix(rust/rbac-registration): Record CIP509 validation data (#95)
* fix: validation data Signed-off-by: bkioshn <[email protected]> * chore: update version Signed-off-by: bkioshn <[email protected]> --------- Signed-off-by: bkioshn <[email protected]>
1 parent 149bf11 commit 47b5514

File tree

5 files changed

+76
-15
lines changed

5 files changed

+76
-15
lines changed

rust/rbac-registration/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
name = "rbac-registration"
33
description = "Role Based Access Control Registration"
44
keywords = ["cardano", "catalyst", "rbac registration"]
5-
version = "0.0.1"
5+
version = "0.0.2"
66
authors = [
77
"Arissara Chotivichit <[email protected]>"
88
]

rust/rbac-registration/src/cardano/cip509/mod.rs

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,31 @@ pub struct Cip509 {
4646
pub validation_signature: Vec<u8>, // bytes size (1..64)
4747
}
4848

49+
/// Validation value for CIP509 metadatum.
50+
#[allow(clippy::struct_excessive_bools, clippy::module_name_repetitions)]
51+
#[derive(Debug, PartialEq, Clone, Default)]
52+
pub struct Cip509Validation {
53+
/// Boolean value for the validity of the transaction inputs hash.
54+
pub valid_txn_inputs_hash: bool,
55+
/// Boolean value for the validity of the auxiliary data.
56+
pub valid_aux: bool,
57+
/// Boolean value for the validity of the public key.
58+
pub valid_public_key: bool,
59+
/// Boolean value for the validity of the payment key.
60+
pub valid_payment_key: bool,
61+
/// Boolean value for the validity of the signing key.
62+
pub signing_key: bool,
63+
/// Additional data from the CIP509 validation..
64+
pub additional_data: AdditionalData,
65+
}
66+
67+
/// Additional data from the CIP509 validation.
68+
#[derive(Debug, PartialEq, Clone, Default)]
69+
pub struct AdditionalData {
70+
/// Bytes of precomputed auxiliary data.
71+
pub precomputed_aux: Vec<u8>,
72+
}
73+
4974
/// `UUIDv4` representing in 16 bytes.
5075
#[derive(Debug, PartialEq, Clone, Default)]
5176
pub struct UuidV4([u8; 16]);
@@ -189,10 +214,13 @@ impl Cip509 {
189214
/// # Parameters
190215
/// * `txn` - Transaction data was attached to and to be validated/decoded against.
191216
/// * `validation_report` - Validation report to store the validation result.
192-
pub fn validate(&self, txn: &MultiEraTx, validation_report: &mut Vec<String>) -> bool {
217+
pub fn validate(
218+
&self, txn: &MultiEraTx, validation_report: &mut Vec<String>,
219+
) -> Cip509Validation {
193220
let tx_input_validate =
194221
validate_txn_inputs_hash(self, txn, validation_report).unwrap_or(false);
195-
let aux_validate = validate_aux(txn, validation_report).unwrap_or(false);
222+
let (aux_validate, precomputed_aux) =
223+
validate_aux(txn, validation_report).unwrap_or_default();
196224
let mut stake_key_validate = true;
197225
let mut payment_key_validate = true;
198226
let mut signing_key = true;
@@ -209,10 +237,13 @@ impl Cip509 {
209237
}
210238
}
211239
}
212-
tx_input_validate
213-
&& aux_validate
214-
&& stake_key_validate
215-
&& payment_key_validate
216-
&& signing_key
240+
Cip509Validation {
241+
valid_txn_inputs_hash: tx_input_validate,
242+
valid_aux: aux_validate,
243+
valid_public_key: stake_key_validate,
244+
valid_payment_key: payment_key_validate,
245+
signing_key,
246+
additional_data: AdditionalData { precomputed_aux },
247+
}
217248
}
218249
}

rust/rbac-registration/src/cardano/cip509/validation.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ use super::{
4141
utils::cip19::{compare_key_hash, extract_cip19_hash, extract_key_hash},
4242
Cip509, TxInputHash, TxWitness,
4343
};
44+
use crate::utils::general::zero_out_last_n_bytes;
4445

4546
/// Context-specific primitive type with tag number 6 (`raw_tag` 134) for
4647
/// uniform resource identifier (URI) in the subject alternative name extension.
@@ -282,7 +283,10 @@ pub(crate) fn validate_stake_public_key(
282283
// ------------------------ Validate Aux ------------------------
283284

284285
/// Validate the auxiliary data with the auxiliary data hash in the transaction body.
285-
pub(crate) fn validate_aux(txn: &MultiEraTx, validation_report: &mut Vec<String>) -> Option<bool> {
286+
/// Also return the pre-computed hash where the validation signature (99) set to
287+
pub(crate) fn validate_aux(
288+
txn: &MultiEraTx, validation_report: &mut Vec<String>,
289+
) -> Option<(bool, Vec<u8>)> {
286290
let function_name = "Validate Aux";
287291

288292
// CIP-0509 should only be in conway era
@@ -313,13 +317,19 @@ pub(crate) fn validate_aux(txn: &MultiEraTx, validation_report: &mut Vec<String>
313317
}
314318

315319
/// Helper function for auxiliary data validation.
320+
/// Also compute The pre-computed hash.
316321
fn validate_aux_helper(
317322
original_aux: &[u8], aux_data_hash: &Bytes, validation_report: &mut Vec<String>,
318-
) -> Option<bool> {
323+
) -> Option<(bool, Vec<u8>)> {
324+
let mut vec_aux = original_aux.to_vec();
325+
326+
// Pre-computed aux with the last 64 bytes set to zero
327+
zero_out_last_n_bytes(&mut vec_aux, 64);
328+
319329
// Compare the hash
320330
match blake2b_256(original_aux) {
321331
Ok(original_hash) => {
322-
return Some(aux_data_hash.as_ref() == original_hash);
332+
return Some((aux_data_hash.as_ref() == original_hash, vec_aux));
323333
},
324334
Err(e) => {
325335
validation_report.push(format!("Cannot hash auxiliary data {e}"));
@@ -539,7 +549,7 @@ mod tests {
539549
.expect("Failed to get transaction index");
540550

541551
validate_aux(tx, &mut validation_report);
542-
assert!(validate_aux(tx, &mut validation_report).unwrap());
552+
assert!(validate_aux(tx, &mut validation_report).unwrap().0);
543553
}
544554

545555
#[test]

rust/rbac-registration/src/registration/cardano/mod.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ use crate::{
2929
pub_key::{Ed25519PublicKey, SimplePublicKeyType},
3030
CertKeyHash,
3131
},
32-
Cip509, UuidV4,
32+
Cip509, Cip509Validation, UuidV4,
3333
},
3434
utils::general::decremented_index,
3535
};
@@ -184,8 +184,10 @@ impl RegistrationChainInner {
184184
}
185185

186186
let mut validation_report = Vec::new();
187+
let validation_data = cip509.validate(txn, &mut validation_report);
188+
187189
// Do the CIP509 validation, ensuring the basic validation pass.
188-
if !cip509.validate(txn, &mut validation_report) {
190+
if !is_valid_cip509(&validation_data) {
189191
// Log out the error if any
190192
error!("CIP509 validation failed: {:?}", validation_report);
191193
bail!("CIP509 validation failed, {:?}", validation_report);
@@ -240,8 +242,10 @@ impl RegistrationChainInner {
240242
let mut new_inner = self.clone();
241243

242244
let mut validation_report = Vec::new();
245+
let validation_data = cip509.validate(txn, &mut validation_report);
246+
243247
// Do the CIP509 validation, ensuring the basic validation pass.
244-
if !cip509.validate(txn, &mut validation_report) {
248+
if !is_valid_cip509(&validation_data) {
245249
error!("CIP509 validation failed: {:?}", validation_report);
246250
bail!("CIP509 validation failed, {:?}", validation_report);
247251
}
@@ -286,6 +290,15 @@ impl RegistrationChainInner {
286290
}
287291
}
288292

293+
/// Check if the CIP509 is valid.
294+
fn is_valid_cip509(validation_data: &Cip509Validation) -> bool {
295+
validation_data.valid_aux
296+
&& validation_data.valid_txn_inputs_hash
297+
&& validation_data.valid_public_key
298+
&& validation_data.valid_payment_key
299+
&& validation_data.signing_key
300+
}
301+
289302
/// Process x509 certificate for chain root.
290303
fn chain_root_x509_certs(
291304
x509_certs: Option<Vec<X509DerCert>>, point_tx_idx: &PointTxIdx,

rust/rbac-registration/src/utils/general.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,10 @@ pub(crate) fn decode_utf8(content: &[u8]) -> anyhow::Result<String> {
2525
)
2626
})
2727
}
28+
29+
/// Zero out the last n bytes
30+
pub(crate) fn zero_out_last_n_bytes(vec: &mut [u8], n: usize) {
31+
if let Some(slice) = vec.get_mut(vec.len().saturating_sub(n)..) {
32+
slice.fill(0);
33+
}
34+
}

0 commit comments

Comments
 (0)