Skip to content

Commit

Permalink
Wrap RET fourth batch (#15)
Browse files Browse the repository at this point in the history
  • Loading branch information
CyonAlexRDX authored Mar 4, 2024
1 parent 20e16ab commit e357f56
Show file tree
Hide file tree
Showing 53 changed files with 2,770 additions and 324 deletions.
22 changes: 22 additions & 0 deletions src/core/error/common_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -355,6 +355,28 @@ pub enum CommonError {
"Failed to UniFFI decode bytes into Transaction Manifest Instructions"
)]
FailedToUniFFIDecodeBytesToManifestInstructions = 10096,

#[error("Failed to decode Transaction Hash, value: {bad_value}")]
FailedToDecodeTransactionHash { bad_value: String } = 10097,

#[error("Failed to hash transaction intent")]
FailedToHashIntent = 10098,

#[error("Encrypted Messages are not yet supported")]
EncryptedMessagesAreNotYetSupported = 10099,

#[error("Failed to Bech32 decode transaction Hash after having tested all Network IDs, from: {bad_value}")]
FailedToBech32DecodeTransactionHashAfterHavingTestedAllNetworkID {
bad_value: String,
} = 10100,

#[error("Failed to parse Signature from {bad_value}")]
FailedToParseSignatureFromString { bad_value: String } = 10101,

#[error(
"Invalid IntentSignatures for Intent some didn't validate IntentHash"
)]
InvalidSignaturesForIntentSomeDidNotValidateIntentHash = 10102,
}

/*
Expand Down
196 changes: 194 additions & 2 deletions src/core/hash.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,198 @@
use radix_engine_common::crypto::{blake2b_256_hash, Hash};
use crate::prelude::*;
use radix_engine::types::IsHash;
use radix_engine_common::crypto::{
blake2b_256_hash, Hash as ScryptoHash, IsHash as ScryptoIsHash,
};

/// Represents a 32-byte hash digest.
///
/// Made UniFFI convertible via bytes (BagOfBytes).
#[derive(
Clone,
Debug,
PartialEq,
Eq,
std::hash::Hash,
derive_more::Display,
derive_more::FromStr,
)]
pub struct HashSecretMagic(ScryptoHash);

impl From<HashSecretMagic> for Exactly32Bytes {
fn from(value: HashSecretMagic) -> Self {
Exactly32Bytes::from_bytes(value.0.as_bytes())
}
}

impl crate::UniffiCustomTypeConverter for HashSecretMagic {
type Builtin = BagOfBytes;

fn into_custom(val: Self::Builtin) -> uniffi::Result<Self> {
Exactly32Bytes::try_from(val.bytes)
.map(|e| e.bytes())
.map(|b: [u8; 32]| HashSecretMagic(ScryptoHash::from_bytes(b)))
.map_err(|e| e.into())
}

fn from_custom(obj: Self) -> Self::Builtin {
BagOfBytes::from(obj.0.into_bytes().as_slice())
}
}

/// Represents a 32-byte hash digest.
///
/// Made UniFFI convertible via HashSecretMagic,
/// exposed in Swift/Kotlin as its own struct/data class, with
/// hidden secret magic.
#[derive(
Clone,
Debug,
PartialEq,
Eq,
std::hash::Hash,
derive_more::Display,
derive_more::FromStr,
uniffi::Record,
)]
pub struct Hash {
pub(crate) secret_magic: HashSecretMagic,
}

impl From<Hash> for Exactly32Bytes {
fn from(value: Hash) -> Self {
value.secret_magic.into()
}
}

impl AsRef<ScryptoHash> for Hash {
fn as_ref(&self) -> &ScryptoHash {
&self.secret_magic.0
}
}

impl AsRef<[u8]> for Hash {
fn as_ref(&self) -> &[u8] {
self.secret_magic.0.as_ref()
}
}

impl ScryptoIsHash for Hash {}

impl Hash {
pub fn bytes(&self) -> Vec<u8> {
self.secret_magic.0.clone().to_vec()
}
}

impl From<ScryptoHash> for Hash {
fn from(value: ScryptoHash) -> Self {
Self {
secret_magic: HashSecretMagic(value),
}
}
}
impl From<Hash> for ScryptoHash {
fn from(value: Hash) -> Self {
value.secret_magic.0
}
}

/// Computes the hash digest of a message.
pub fn hash_of<T: AsRef<[u8]>>(data: T) -> Hash {
blake2b_256_hash(data)
blake2b_256_hash(data).into()
}

impl HasSampleValues for Hash {
fn sample() -> Self {
// "Hello Radix".as_bytes()
"48f1bd08444b5e713db9e14caac2faae71836786ac94d645b00679728202a935"
.parse::<Self>()
.unwrap()
}

fn sample_other() -> Self {
// "Radix... just imagine".as_bytes()
"196ca16b4a35c1c3df18e20cb199c99d129cec6ea62eb03a29fde16db897f4b1"
.parse::<Self>()
.unwrap()
}
}

#[cfg(test)]
mod tests {
use crate::prelude::*;

#[allow(clippy::upper_case_acronyms)]
type SUT = Hash;

#[test]
fn equality() {
assert_eq!(SUT::sample(), SUT::sample());
assert_eq!(SUT::sample_other(), SUT::sample_other());
}

#[test]
fn inequality() {
assert_ne!(SUT::sample(), SUT::sample_other());
}

#[test]
fn test_hash() {
assert_eq!(
hash_of("Hello Radix".as_bytes()).to_string(),
"48f1bd08444b5e713db9e14caac2faae71836786ac94d645b00679728202a935"
);
}

#[test]
fn to_string() {
assert_eq!(
SUT::sample_other().to_string(),
"196ca16b4a35c1c3df18e20cb199c99d129cec6ea62eb03a29fde16db897f4b1"
);
}

#[test]
fn from_str() {
assert_eq!(
"48f1bd08444b5e713db9e14caac2faae71836786ac94d645b00679728202a935"
.parse::<SUT>()
.unwrap(),
hash_of("Hello Radix".as_bytes())
);
}

#[test]
fn manual_perform_uniffi_conversion_successful() {
let sut = SUT::sample().secret_magic;
let builtin = BagOfBytes::from_hex(
"48f1bd08444b5e713db9e14caac2faae71836786ac94d645b00679728202a935",
)
.unwrap();

let ffi_side =
<HashSecretMagic as crate::UniffiCustomTypeConverter>::from_custom(
sut.clone(),
);

assert_eq!(ffi_side.to_hex(), builtin.to_hex());

let from_ffi_side =
<HashSecretMagic as crate::UniffiCustomTypeConverter>::into_custom(
ffi_side,
)
.unwrap();

assert_eq!(sut, from_ffi_side);
}

#[test]
fn manual_perform_uniffi_conversion_fail() {
assert!(
<HashSecretMagic as crate::UniffiCustomTypeConverter>::into_custom(
BagOfBytes::from_hex("deadbeef").unwrap(),
)
.is_err()
);
}
}
5 changes: 2 additions & 3 deletions src/core/types/bag_of_bytes.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use std::ops::{Deref, Neg};

use crate::prelude::*;
use radix_engine_common::crypto::{Hash, IsHash};

/// This is a TEMPORARY workaround until Kotlin => ByteArray equatable issue for
/// Records has been solved, see: https://github.com/mozilla/uniffi-rs/issues/1985
Expand Down Expand Up @@ -138,7 +137,7 @@ impl BagOfBytes {
impl From<Hash> for BagOfBytes {
/// Instantiates a new `BagOfBytes` from the `Hash` (32 bytes).
fn from(value: Hash) -> Self {
value.into_bytes().as_slice().into()
value.bytes().as_slice().into()
}
}

Expand Down Expand Up @@ -382,7 +381,7 @@ mod tests {
#[test]
fn from_hash() {
let digest = hash_of(vec![0xde, 0xad]);
assert_eq!(BagOfBytes::from(digest).to_vec(), digest.to_vec());
assert_eq!(BagOfBytes::from(digest.clone()).to_vec(), digest.bytes());
}

#[test]
Expand Down
24 changes: 24 additions & 0 deletions src/core/types/epoch.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
pub use crate::prelude::*;
use radix_engine::types::Epoch as ScryptoEpoch;

// use radix_engine_common::types::Epoch as ScryptoEpoch;

Expand Down Expand Up @@ -31,10 +32,33 @@ impl From<Epoch> for u64 {
}
}

impl From<Epoch> for ScryptoEpoch {
fn from(value: Epoch) -> Self {
Self::of(value.0)
}
}

impl From<ScryptoEpoch> for Epoch {
fn from(value: ScryptoEpoch) -> Self {
Self(value.number())
}
}

#[cfg(test)]
mod tests {
use super::*;
use crate::prelude::*;

#[test]
fn into_from_scrypto() {
let test =
|u: u64| assert_eq!(Into::<Epoch>::into(ScryptoEpoch::of(u)).0, u);
test(0);
test(1);
test(2);
test(1337);
}

#[test]
fn from_u64() {
let test =
Expand Down
8 changes: 4 additions & 4 deletions src/core/types/keys/ed25519/private_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,14 @@ impl IsPrivateKey<Ed25519PublicKey> for Ed25519PrivateKey {
)
}

fn sign(&self, msg_hash: &impl IsHash) -> Self::Signature {
fn sign(&self, msg_hash: &Hash) -> Self::Signature {
self.0.sign(msg_hash).into()
}
}

impl Ed25519PrivateKey {
pub fn from_engine(engine: ScryptoEd25519PrivateKey) -> Self {
Self(engine)
pub fn from_scrypto(scrypto: ScryptoEd25519PrivateKey) -> Self {
Self(scrypto)
}

pub fn to_bytes(&self) -> Vec<u8> {
Expand All @@ -65,7 +65,7 @@ impl Ed25519PrivateKey {
.map_err(|_| CommonError::InvalidEd25519PrivateKeyFromBytes {
bad_value: slice.into(),
})
.map(Self::from_engine)
.map(Self::from_scrypto)
}

pub fn from_vec(bytes: Vec<u8>) -> Result<Self> {
Expand Down
4 changes: 2 additions & 2 deletions src/core/types/keys/ed25519/public_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{prelude::*, UniffiCustomTypeConverter};
use radix_engine_common::crypto::{
verify_ed25519 as scrypto_verify_ed25519,
Ed25519PublicKey as ScryptoEd25519PublicKey,
Ed25519Signature as ScryptoEd25519Signature, IsHash,
Ed25519Signature as ScryptoEd25519Signature, IsHash as ScryptoIsHash,
};

/// An Ed25519 public key used to verify cryptographic signatures (EdDSA signatures).
Expand Down Expand Up @@ -89,7 +89,7 @@ impl IsPublicKey<Ed25519Signature> for Ed25519PublicKey {
fn is_valid(
&self,
signature: &Ed25519Signature,
for_hash: &impl IsHash,
for_hash: &impl ScryptoIsHash,
) -> bool {
scrypto_verify_ed25519(
for_hash.as_hash(),
Expand Down
23 changes: 20 additions & 3 deletions src/core/types/keys/is_private_key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,25 @@ pub trait IsPrivateKey<P: IsPublicKey<Self::Signature>>: Sized {

fn public_key(&self) -> P;

fn sign(
fn sign(&self, msg_hash: &Hash) -> Self::Signature;

fn sign_intent_hash(&self, intent_hash: &IntentHash) -> IntentSignature
where
(P, Self::Signature): Into<SignatureWithPublicKey>,
{
let public_key: P = self.public_key();
let signature = self.sign(&intent_hash.hash);
let tuple: SignatureWithPublicKey = (public_key, signature).into();
tuple.into()
}

fn notarize_hash(
&self,
msg_hash: &impl radix_engine_common::crypto::IsHash,
) -> Self::Signature;
signed_intent_hash: &SignedIntentHash,
) -> NotarySignature
where
Self::Signature: Into<NotarySignature>,
{
self.sign(&signed_intent_hash.hash).into()
}
}
Loading

0 comments on commit e357f56

Please sign in to comment.