// file: crates/ksp-raw-transaction-lib/unit_tests/signature.rs // version: 4 use base64::Engine; // rust-rules: trait-import #[test] fn pre_002_signature_parser_accepts_exact_sixty_four_zero_bytes() { let text = "1".repeat(crate::MIN_RAW_TRANSACTION_SIGNATURE_TEXT_BYTES); let signature = crate::parse_raw_transaction_signature(text.as_str()); assert!(signature.is_ok()); if let std::result::Result::Ok(signature) = signature { assert_eq!(signature.as_bytes(), &[0_u8; 64]); } return; } #[test] fn pre_002_signature_parser_rejects_text_bounds_invalid_base58_and_noncanonical_lengths() { for text in [ "1".repeat(crate::MIN_RAW_TRANSACTION_SIGNATURE_TEXT_BYTES - 1), "1".repeat(crate::MAX_RAW_TRANSACTION_SIGNATURE_TEXT_BYTES + 1), format!("{}0", "1".repeat(crate::MIN_RAW_TRANSACTION_SIGNATURE_TEXT_BYTES - 1)), "1".repeat(65), "z".repeat(crate::MAX_RAW_TRANSACTION_SIGNATURE_TEXT_BYTES), ] { let result = crate::parse_raw_transaction_signature(text.as_str()); assert!(result.is_err()); if let std::result::Result::Err(error) = result { assert_eq!(error.code(), crate::ERROR_CODE_RAW_TRANSACTION_SIGNATURE_INVALID); let debug = std::format!("{error:?}"); assert!(!debug.contains(text.as_str())); } } return; } #[test] fn pre_004_embedded_signature_extracts_first_signature_from_canonical_transaction_base64() { let encoded = "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"; let signature = crate::extract_raw_transaction_signature_from_binary_base64(encoded); assert!(signature.is_ok()); if let std::result::Result::Ok(signature) = signature { assert_eq!(signature.as_bytes(), &[0_u8; 64]); } return; } #[test] fn pre_004_embedded_signature_rejects_invalid_base64_noncanonical_short_vec_and_truncation() { for encoded in [ "not-base64", "gQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==", "AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", ] { let result = crate::extract_raw_transaction_signature_from_binary_base64(encoded); assert!(result.is_err()); if let std::result::Result::Err(error) = result { assert_eq!(error.code(), crate::ERROR_CODE_RAW_TRANSACTION_SIGNATURE_INVALID); assert!(!error.to_string().contains(encoded)); } } return; } #[test] fn pre_006_embedded_signature_extracts_terminal_v1_signature_and_rejects_trailing_bytes() { let encoded = "gQEAAR8AAABRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUQECQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQgcAAAAAAAAACAAAAAkAAAAAgAAAAQEDAAABAgOqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq"; let signature = crate::extract_raw_transaction_signature_from_binary_base64(encoded); assert!(signature.is_ok()); if let std::result::Result::Ok(signature) = signature { assert_eq!(signature.as_bytes(), &[0xaa_u8; 64]); } let decoded = base64::engine::general_purpose::STANDARD.decode(encoded); assert!(decoded.is_ok()); if let std::result::Result::Ok(mut decoded) = decoded { decoded.push(0); let trailing = base64::engine::general_purpose::STANDARD.encode(decoded); assert!(crate::extract_raw_transaction_signature_from_binary_base64(trailing.as_str()).is_err()); } } #[test] fn pre_004_base58_formatter_round_trips_canonical_signatures() { for bytes in [[0_u8; 64], [1_u8; 64], [0xAB_u8; 64]] { let signature = ksp_store_api::RawTransactionSignature::new(bytes); let text = crate::format_raw_transaction_signature(&signature); assert!((crate::MIN_RAW_TRANSACTION_SIGNATURE_TEXT_BYTES..=crate::MAX_RAW_TRANSACTION_SIGNATURE_TEXT_BYTES).contains(&text.len())); let parsed = crate::parse_raw_transaction_signature(text.as_str()); assert!(parsed.is_ok()); if let std::result::Result::Ok(parsed) = parsed { assert_eq!(parsed, signature); } } assert_eq!(crate::format_raw_transaction_signature(&ksp_store_api::RawTransactionSignature::new([0_u8; 64])), "1".repeat(64)); return; }