Skip to content

Commit

Permalink
refactor: Clean up types
Browse files Browse the repository at this point in the history
  • Loading branch information
conr2d committed Jun 7, 2024
1 parent f544c2d commit ce5f612
Show file tree
Hide file tree
Showing 15 changed files with 339 additions and 219 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ serde = { version = "1.0.152", default-features = false, features = ["derive"] }
serde_json = { version = "1.0.94", default-features = false }
sha2 = { version = "0.10.6", default-features = false }
substrate-bip39 = { version = "0.4.4" }
thiserror = "1.0.61"
tiny-bip39 = "1.0.0"
url = "2.5.0"
zeroize = { version = "1.5.7", default-features = false }
Expand Down
2 changes: 1 addition & 1 deletion core-primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pub type Hash = sp_core::H256;
/// Balance of an account.
pub type Balance = u128;
/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
pub type Signature = np_runtime::UniversalSignature;
pub type Signature = np_runtime::AuthenticationProof;
/// Some way of identifying an account on the chain. We intentionally make it equivalent
/// to the public key of our transaction signing scheme.
pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
Expand Down
71 changes: 29 additions & 42 deletions frame/alias/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ pub use pallet::*;

use crate::weights::WeightInfo;
use np_crypto::ecdsa::EcdsaExt;
use parity_scale_codec::{Decode, Encode, FullCodec, MaxEncodedLen};
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
use scale_info::TypeInfo;
use sp_runtime::{traits::Member, DispatchError};
use sp_std::prelude::*;
use sp_runtime::{BoundedBTreeSet, DispatchError};
use sp_std::{collections::btree_set::BTreeSet, prelude::*};

#[cfg_attr(feature = "std", derive(Hash))]
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Encode, Decode, MaxEncodedLen, TypeInfo)]
Expand All @@ -40,10 +40,8 @@ pub enum AccountAlias {

#[frame_support::pallet]
pub mod pallet {

use super::*;
use frame_support::pallet_prelude::*;
use frame_system::pallet_prelude::*;

/// The module's config trait.
#[pallet::config]
Expand All @@ -52,26 +50,10 @@ pub mod pallet {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
/// Weight information for extrinsics in this pallet.
type WeightInfo: WeightInfo;

type Origin: Member + FullCodec + MaxEncodedLen + TypeInfo;
}

#[pallet::pallet]
pub struct Pallet<T>(PhantomData<T>);

#[pallet::call]
impl<T: Config> Pallet<T>
where
T::AccountId: EcdsaExt,
{
#[pallet::call_index(0)]
#[pallet::weight(T::WeightInfo::alias())]
pub fn alias(origin: OriginFor<T>) -> DispatchResult {
let who = ensure_signed(origin)?;
Self::alias_secp256k1(&who)?;
Ok(())
}
}
pub struct Pallet<T>(_);

#[pallet::event]
#[pallet::generate_deposit(pub(super) fn deposit_event)]
Expand All @@ -84,16 +66,6 @@ pub mod pallet {

#[pallet::error]
pub enum Error<T> {
/// The account name already exists.
AlreadyExists,
/// The account name does not exists.
NotExists,
/// The account name is not available.
InUse,
/// Invalid name foramt.
InvalidNameFormat,
/// Tag generation failed.
TagGenerationFailed,
/// Ethereum address conversion failed.
EthereumAddressConversionFailed,
/// Cosmos address conversion failed.
Expand All @@ -103,42 +75,57 @@ pub mod pallet {
#[pallet::storage]
#[pallet::getter(fn accountid)]
pub type AccountIdOf<T: Config> = StorageMap<_, Blake2_128Concat, AccountAlias, T::AccountId>;

#[pallet::storage]
#[pallet::getter(fn aliases)]
pub type AccountAliases<T: Config> =
StorageMap<_, Blake2_128Concat, T::AccountId, BoundedBTreeSet<AccountAlias, ConstU32<2>>>;
}

impl<T: Config> Pallet<T>
where
T::AccountId: EcdsaExt,
{
// PUBLIC IMMUTABLES

/// Lookup an AccountAlias to get an Id, if exists.
pub fn lookup(alias: &AccountAlias) -> Option<T::AccountId> {
AccountIdOf::<T>::get(alias).map(|x| x)
}

pub fn alias_secp256k1(who: &T::AccountId) -> Result<(), DispatchError> {
let ethereum_address = who
let mut aliases = BTreeSet::new();
let eth = who
.to_eth_address()
.map(|x| x.into())
.ok_or(Error::<T>::EthereumAddressConversionFailed)?;
if AccountIdOf::<T>::get(AccountAlias::EthereumAddress(ethereum_address)).is_none() {
AccountIdOf::<T>::insert(AccountAlias::EthereumAddress(ethereum_address), who);
let eth_alias = AccountAlias::EthereumAddress(eth);
if AccountIdOf::<T>::get(eth_alias).is_none() {
AccountIdOf::<T>::insert(eth_alias, who.clone());
aliases.insert(eth_alias);
Self::deposit_event(Event::<T>::EthereumAddressPublished {
who: who.clone(),
address: ethereum_address,
address: eth,
});
}
let cosmos_address = who
let cosm = who
.to_cosm_address()
.map(|x| x.into())
.ok_or(Error::<T>::CosmosAddressConversionFailed)?;
if AccountIdOf::<T>::get(AccountAlias::CosmosAddress(cosmos_address)).is_none() {
AccountIdOf::<T>::insert(AccountAlias::CosmosAddress(cosmos_address), who);
let cosm_alias = AccountAlias::CosmosAddress(cosm);
if AccountIdOf::<T>::get(cosm_alias).is_none() {
AccountIdOf::<T>::insert(cosm_alias, who.clone());
aliases.insert(cosm_alias);
Self::deposit_event(Event::<T>::CosmosAddressPublished {
who: who.clone(),
address: cosmos_address,
address: cosm,
});
}
if !aliases.is_empty() {
AccountAliases::<T>::insert(
who,
BoundedBTreeSet::try_from(aliases)
.map_err(|_| DispatchError::Other("Too many aliases"))?,
);
}
Ok(())
}
}
32 changes: 21 additions & 11 deletions primitives/crypto/src/webauthn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use sp_std::vec::Vec;
use crate::p256;

#[cfg(feature = "full_crypto")]
use base64ct::{Base64UrlUnpadded as Base64, Encoding};
use base64ct::{Base64UrlUnpadded, Encoding};
#[cfg(feature = "full_crypto")]
use sp_core::hashing::{blake2_256, sha2_256};
#[cfg(feature = "full_crypto")]
Expand Down Expand Up @@ -65,7 +65,7 @@ impl ClientDataJson {

// challenge should be same to the hash value of the message.
fn check_message(&self, message_hash: &[u8]) -> bool {
match Base64::decode_vec(&self.challenge) {
match Base64UrlUnpadded::decode_vec(&self.challenge) {
Ok(c) => c == message_hash,
Err(_) => false,
}
Expand Down Expand Up @@ -101,7 +101,7 @@ impl TryFrom<&str> for ClientDataJson {
type Error = ();

fn try_from(s: &str) -> Result<Self, Self::Error> {
Self::try_from(Base64::decode_vec(s).map_err(|_| ())?.as_slice())
Self::try_from(Base64UrlUnpadded::decode_vec(s).map_err(|_| ())?.as_slice())
}
}

Expand Down Expand Up @@ -151,10 +151,12 @@ impl Signature {
.map_or(false, |recovered_pubkey| recovered_pubkey == *pubkey)
}

/// Recover the public key from this signature and a message.
pub fn recover<M: AsRef<[u8]>>(&self, message: M) -> Option<Public> {
self.recover_prehashed(&blake2_256(message.as_ref()))
}

/// Recover the public key from this signature and a pre-hashed message.
pub fn recover_prehashed(&self, message_hash: &[u8; 32]) -> Option<Public> {
let client_data = match ClientDataJson::try_from(&self.client_data_json[..]) {
Ok(c) => c,
Expand Down Expand Up @@ -187,9 +189,17 @@ impl sp_std::fmt::Debug for Signature {
#[cfg(feature = "std")]
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "WebAuthnSignature {{ ")?;
write!(f, "clientDataJSON: \"{}\", ", Base64::encode_string(&self.client_data_json))?;
write!(f, "authenticatorData: \"{}\", ", Base64::encode_string(&self.authenticator_data))?;
write!(f, "signature: \"{}\" }}", Base64::encode_string(&self.signature))
write!(
f,
"clientDataJSON: \"{}\", ",
Base64UrlUnpadded::encode_string(&self.client_data_json)
)?;
write!(
f,
"authenticatorData: \"{}\", ",
Base64UrlUnpadded::encode_string(&self.authenticator_data)
)?;
write!(f, "signature: \"{}\" }}", Base64UrlUnpadded::encode_string(&self.signature))
}

#[cfg(not(feature = "std"))]
Expand All @@ -208,7 +218,7 @@ mod tests {
let client_data = ClientDataJson::try_from(client_data_json);
assert!(client_data.is_ok());

let client_data_json = Base64::decode_vec(client_data_json).unwrap();
let client_data_json = Base64UrlUnpadded::decode_vec(client_data_json).unwrap();
let client_data = ClientDataJson::try_from(client_data_json.as_slice());
assert!(client_data.is_ok());

Expand All @@ -224,7 +234,7 @@ mod tests {
let client_data = ClientDataJson::try_from(client_data_json).unwrap();

let authenticator_data = "dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvABAAAAAg";
let authenticator_data = Base64::decode_vec(authenticator_data).unwrap();
let authenticator_data = Base64UrlUnpadded::decode_vec(authenticator_data).unwrap();
let rpid_hash = &authenticator_data[0..32];
assert!(client_data.check_rpid(rpid_hash));
}
Expand All @@ -237,9 +247,9 @@ mod tests {
);
let public = Public::try_from(public.as_ref()).unwrap();
let signature = Signature {
signature: Base64::decode_vec("MEQCIHjqOGStreQAKH44uq5lQL5afSdZAhaOKwvnPdpPPfZiAiB-piO5KWYcYDXbvHWIXQirbN1Ww5sLfIvCGGyE1qOdtg").unwrap(),
authenticator_data: Base64::decode_vec("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvAFAAAABA").unwrap(),
client_data_json: Base64::decode_vec("eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQSIsIm9yaWdpbiI6Imh0dHBzOi8vd2ViYXV0aG4uaW8iLCJjcm9zc09yaWdpbiI6ZmFsc2V9").unwrap(),
signature: Base64UrlUnpadded::decode_vec("MEQCIHjqOGStreQAKH44uq5lQL5afSdZAhaOKwvnPdpPPfZiAiB-piO5KWYcYDXbvHWIXQirbN1Ww5sLfIvCGGyE1qOdtg").unwrap(),
authenticator_data: Base64UrlUnpadded::decode_vec("dKbqkhPJnC90siSSsyDPQCYqlMGpUKA5fyklC2CEHvAFAAAABA").unwrap(),
client_data_json: Base64UrlUnpadded::decode_vec("eyJ0eXBlIjoid2ViYXV0aG4uZ2V0IiwiY2hhbGxlbmdlIjoiQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQSIsIm9yaWdpbiI6Imh0dHBzOi8vd2ViYXV0aG4uaW8iLCJjcm9zc09yaWdpbiI6ZmFsc2V9").unwrap(),
};
assert!(signature.verify_prehashed(&[0u8; 32], &public));
}
Expand Down
2 changes: 2 additions & 0 deletions primitives/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ base64ct = { workspace = true, optional = true }
parity-scale-codec = { workspace = true, features = ["derive", "max-encoded-len"] }
scale-info = { workspace = true, features = ["derive"] }
serde = { workspace = true, features = ["derive"], optional = true }
thiserror = { workspace = true, optional = true }

# noir
np-crypto = { workspace = true }
Expand Down Expand Up @@ -42,6 +43,7 @@ std = [
"sp-io/std",
"sp-runtime/std",
"sp-std/std",
"thiserror",
]
serde = [
"dep:serde",
Expand Down
47 changes: 29 additions & 18 deletions primitives/runtime/src/accountid32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

use crate::{Derived, UniversalAddress};
use crate::Multikey;
use np_crypto::ecdsa::EcdsaExt;
use parity_scale_codec::{Decode, Encode, EncodeLike, Error, Input, MaxEncodedLen};
use scale_info::{Type, TypeInfo};
#[cfg(feature = "serde")]
use sp_core::crypto::{PublicError, Ss58Codec};
use sp_core::crypto::{PublicError, Ss58AddressFormat, Ss58Codec};
use sp_core::{
crypto::{AccountId32 as SubstrateAccountId32, FromEntropy, UncheckedFrom},
ByteArray, H160, H256,
Expand All @@ -32,23 +32,33 @@ use sp_std::{
vec::Vec,
};

/// An opaque 32-byte cryptographic identifier.
///
/// HACK: This type replaces Substrate AccountId32 to be passed keeping recovered public key.
/// `source` field should be ignored during serialization.
#[derive(Clone, Eq)]
pub struct AccountId32 {
inner: [u8; 32],
pub origin: Option<UniversalAddress>,
source: Option<Multikey>,
}

impl AccountId32 {
/// Create a new instance from its raw inner byte value.
///
/// Equivalent to this types `From<[u8; 32]>` implementation. For the lack of const
/// support in traits we have this constructor.
pub const fn new(inner: [u8; 32]) -> Self {
Self { inner, origin: None }
Self { inner, source: None }
}
}

impl Derived for AccountId32 {
type Origin = UniversalAddress;
/// Returns the source of account id, if possible.
pub fn source(&self) -> Option<&Multikey> {
self.source.as_ref()
}

fn origin(&self) -> Option<Self::Origin> {
self.origin.clone()
/// Sets the source of account id.
pub fn set_source(&mut self, source: Multikey) {
self.source = Some(source);
}
}

Expand Down Expand Up @@ -84,7 +94,7 @@ impl EncodeLike for AccountId32 {}

impl Decode for AccountId32 {
fn decode<I: Input>(input: &mut I) -> Result<Self, Error> {
Ok(Self { inner: <[u8; 32]>::decode(input)?, origin: None })
Ok(Self { inner: <[u8; 32]>::decode(input)?, source: None })
}
}

Expand All @@ -111,7 +121,7 @@ impl sp_std::hash::Hash for AccountId32 {

impl UncheckedFrom<H256> for AccountId32 {
fn unchecked_from(h: H256) -> Self {
Self { inner: h.into(), origin: None }
Self { inner: h.into(), source: None }
}
}

Expand All @@ -121,12 +131,13 @@ impl ByteArray for AccountId32 {

#[cfg(feature = "serde")]
impl Ss58Codec for AccountId32 {
fn to_ss58check(&self) -> String {
SubstrateAccountId32::new(self.inner).to_ss58check()
fn from_ss58check_with_version(s: &str) -> Result<(Self, Ss58AddressFormat), PublicError> {
SubstrateAccountId32::from_ss58check_with_version(s)
.map(|(inner, format)| (Self { inner: inner.into(), source: None }, format))
}

fn from_ss58check(s: &str) -> Result<Self, PublicError> {
Ok(Self { inner: SubstrateAccountId32::from_ss58check(s)?.into(), origin: None })
fn to_ss58check_with_version(&self, version: Ss58AddressFormat) -> String {
SubstrateAccountId32::new(self.inner).to_ss58check_with_version(version)
}
}

Expand Down Expand Up @@ -182,7 +193,7 @@ impl From<H256> for AccountId32 {

impl From<sp_core::ecdsa::Public> for AccountId32 {
fn from(v: sp_core::ecdsa::Public) -> Self {
Self { inner: sp_core::blake2_256(v.as_ref()), origin: Some(v.into()) }
Self { inner: sp_core::blake2_256(v.as_ref()), source: Some(v.into()) }
}
}

Expand Down Expand Up @@ -260,10 +271,10 @@ impl FromEntropy for AccountId32 {

impl EcdsaExt for AccountId32 {
fn to_eth_address(&self) -> Option<H160> {
self.origin.as_ref().and_then(EcdsaExt::to_eth_address)
self.source.as_ref().and_then(EcdsaExt::to_eth_address)
}

fn to_cosm_address(&self) -> Option<H160> {
self.origin.as_ref().and_then(EcdsaExt::to_cosm_address)
self.source.as_ref().and_then(EcdsaExt::to_cosm_address)
}
}
20 changes: 20 additions & 0 deletions primitives/runtime/src/generic/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// This file is part of Noir.

// Copyright (C) 2023 Haderech Pte. Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

mod unchecked_extrinsic;

pub use unchecked_extrinsic::*;
Loading

0 comments on commit ce5f612

Please sign in to comment.