How to generate the public key from Polkadot Address from Substrate Side - rust

I'm generating a Public key from PolkadotJS as follows
const keyring = new Keyring({ type: "sr25519" });
const account = keyring.addFromUri("//Bob", { name: "Bob default" });
// encoded public key
let public_key = keyring.encodeAddress(account.publicKey, 42);
console.log(public_key);
I am adding the type of public_key as "public_key": "Vec<u8>",
I am reading the public key from Substrate Node as follows
// pk_raw is a Vec<u8> array
let pk = str::from_utf8(pk_raw.as_ref()).unwrap()
// the above returns `5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty`
I need to generate the public key from this value. I tried with the followings
ed25519::Public::try_from(&*pk_raw).unwrap();
// above throws error since the data length is not equals to 32
fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
if data.len() == 32 {
let mut inner = [0u8; 32];
inner.copy_from_slice(data);
Ok(Public(inner))
} else {
Err(())
}
}
Is there a way to generate the public key using 5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty from Substrate Rust Side?

You can use something like this:
use sp_core::crypto::Ss58Codec;
ed25519::Public::from_ss58check("5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty").expect("Valid address")

Related

Teloxide:-rs How to share state between different instances of the same bot?

I'm using teloxide a bot that coordinates information between players of a game. As a simplified example, I want player A to mark task_1 as complete, and then I want player B to be able to ask the bot if task_1 has been completed or not and for the bot to respond appropriately.
So far I've tried the in-memory storage and the Redis storage, and both seem to be storing independent states. For example Player A can mark a task as complete, but when player B asks about the state of that task, it remains incomplete.
I haven't got sqlite setup on my machine so haven't tried it yet, but I wouldn't imagine it's setup differently to redis(?).
I could theoretically write the bot's state to a file on disk and then update the internal state every time, but that seems very round about for something I'm hoping teloxide already has built in?
Is there any way I can have multiple users mutating the same internal state of the bot?
Here's the code:
Here's the code I'm using. This is lightly adjusted from the db_remember.rs example so that I can get a number, reset the number, and set a number to something new using \set XXX
src/main.rs:
use teloxide::{
dispatching::dialogue::{
serializer::Bincode,
ErasedStorage, RedisStorage, Storage,
},
prelude::*,
utils::command::BotCommands,
};
use serde::{self, Deserialize, Serialize};
type MyDialogue = Dialogue<State, ErasedStorage<State>>;
type MyStorage = std::sync::Arc<ErasedStorage<State>>;
type HandlerResult = Result<(), Box<dyn std::error::Error + Send + Sync>>;
#[derive(Clone, Default, Serialize, Deserialize)]
pub enum State {
#[default]
Start,
GotNumber(i32),
}
#[derive(Clone, BotCommands)]
#[command(rename_rule = "lowercase", description = "These commands are supported:")]
pub enum Command {
#[command(description = "set your number.")]
Set { num: i32 },
#[command(description = "get your number.")]
Get,
#[command(description = "reset your number.")]
Reset,
}
#[tokio::main]
async fn main() {
pretty_env_logger::init();
log::info!("Starting DB remember bot...");
let bot = Bot::from_env();
let storage: MyStorage = RedisStorage::open("redis://127.0.0.1:6379", Bincode).await.unwrap().erase();
let handler = Update::filter_message()
.enter_dialogue::<Message, ErasedStorage<State>, State>()
.branch(dptree::case![State::Start].endpoint(start))
.branch(
dptree::case![State::GotNumber(n)]
.branch(dptree::entry().filter_command::<Command>().endpoint(got_number))
.branch(dptree::endpoint(invalid_command)),
);
Dispatcher::builder(bot, handler)
.dependencies(dptree::deps![storage])
.enable_ctrlc_handler()
.build()
.dispatch()
.await;
}
async fn start(bot: Bot, dialogue: MyDialogue, msg: Message) -> HandlerResult {
match msg.text().map(|text| text.parse::<i32>()) {
Some(Ok(n)) => {
log::info!("[{:?}] Number set to {n}", msg.chat.username());
dialogue.update(State::GotNumber(n)).await?;
bot.send_message(
msg.chat.id,
format!("Remembered number {n}. Now use /get or /reset."),
)
.await?;
}
_ => {
bot.send_message(msg.chat.id, "Please, send me a number.").await?;
}
}
Ok(())
}
async fn got_number(
bot: Bot,
dialogue: MyDialogue,
num: i32, // Available from `State::GotNumber`.
msg: Message,
cmd: Command,
) -> HandlerResult {
let old_num = num;
match cmd {
Command::Set { num } => {
log::info!("[{:?}] Number changed from {} to {}", msg.chat.username(), old_num, num);
dialogue.update(State::GotNumber(num)).await?;
bot.send_message(msg.chat.id, format!("Set your number from {} to {}", old_num, num)).await?;
}
Command::Get => {
bot.send_message(msg.chat.id, format!("Here is your number: {num}.")).await?;
}
Command::Reset => {
dialogue.reset().await?;
bot.send_message(msg.chat.id, "Number reset.").await?;
}
}
Ok(())
}
async fn invalid_command(bot: Bot, msg: Message) -> HandlerResult {
bot.send_message(msg.chat.id, "Please, send /get or /reset.").await?;
Ok(())
}
Cargo.toml:
[package]
name = "tmp"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
teloxide = { version = "0.12", features = ["macros", "redis-storage", "bincode-serializer"] }
log = "0.4"
pretty_env_logger = "0.4"
tokio = { version = "1.8", features = ["rt-multi-thread", "macros"] }
serde_yaml = "0.9.17"
serde = "1.0.152"
This was answered by WaffleLapkin on the Teloxide github discussion page:
The dialogue storages in teloxide store state per chat, if you need something else, you'll need to work with databases directly.
So I ended up using a Redis database to store the game state, and regular in-memory for storing teloxide's state. Something like:
// Cargo.toml: redis = { version = "*" }
extern crate redis;
use redis::{Commands, Connection};
/// Establish a connection to the redis database,
/// used for sharing Game state across
/// different instances of the bot
fn connect_to_redis() -> Result<Connection, Box<dyn std::error::Error + Sync + Send>> {
let client = redis::Client::open("redis://127.0.0.1/")?;
let conn = client.get_connection()?;
// Cargo.toml: log = "0.4"
log::info!("Redis connection established");
Ok(conn)
}
But then you also can't directly store a rust struct into redis, so I used serde_yaml to serialise the game state:
fn set_game_state(
conn: &mut Connection,
game: Game,
) -> Result<(), Box<dyn Error + Send + Sync>> {
let game_key = "game_state";
conn.set::<&str, String, ()>(game_key, serde_yaml::to_string(&game)?)?;
Ok(())
}
And then stored it all as one long string in a single key in the DB.
To retrieve the game state is a similar operation, but I also added in some logic to create the game from an existing "template" YAML file game.yaml if the key doesn't exist:
fn get_game_state(conn: &mut Connection) -> Result<Game, Box<dyn Error + Send + Sync>> {
let game_state_key = "game_state";
let game_state: Game = if conn.exists(game_state_key)? {
log::debug!("Getting game state");
conn.get::<&str, String>(game_state_key)
.and_then(|game_state| Ok(serde_yaml::from_str::<Game>(&game_state).unwrap().into()))?
} else {
log::debug!("Creating game state");
let s = Game::new("challenges.yaml")?;
let serialised = serde_yaml::to_string(&s)?;
conn.set::<&str, String, ()>(game_state_key, serialised)?;
s
};
Ok(game_state)
}
A bit overkill, but it works.

Rust appending unicode escape before creating new struct

I am reading from a file and then creating a struct from those values.
let file = File::open(self.get_state_name().add(".sky")).unwrap();
let reader = BufReader::new(file);
for (_, line) in reader.lines().enumerate() {
let line = line.unwrap();
let key_value = line.split("`").collect::<Vec<&str>>();
let key = key_value[0].to_string();
let data = key_value[1].to_string();
self.set(key, data);
}
Set function creates a new struct named model
let model = Model::new(key, data);
New function just returns a struct named model:
pub fn new(key: String, data: String) -> Model {
Model { key, data }
}
Value of key is prefixed with unicode escapes like:
Model {
key: "\u{f}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}\u{0}Test",
data: "Test Data",
},
Update:
Tried saving only ascii characters:
pub fn new(key: String, data: String) -> Model {
let key = key.replace(|c: char| !c.is_ascii(), "");
println!("Key: {}", key);
Model { key, data }
}
Update:
Saving file
let mut file = File::create(name.add(".sky")).unwrap();
for i in &data {
let data = i.to_string();
let bytes = bincode::serialize(&data).unwrap();
file.write_all(&bytes).expect("Unable to write to file");
}
.to_string() methods on struct
pub(crate) fn to_string(&self) -> String {
format!("{}`{}\n", self.key, self.data)
}
Here is key is without unicode escapes. It happens during Model { key, data } line.
Same doesn't happen when directly setting value not reading from file.
How to remove this and why is this happening?
You are writing the code using bincode::serialize but read back the data not with bincode::deserialize but using BufReader.
In order to properly serialize the string in a binary fashion, the encoder adds additional information about the data it stores.
If you know that only strings compatible with BufReader#lines will be processed, you can also use String#as_bytes when writing it to a file. Note that this will cause problems for some inputs, notably newline characters and others.

How do I set the Initialization Vector (IV) in Rust's `aes` crate? (AES-128 CBC)

As the title suggests. I can create a new Aes128 cipher, but I've checked the documentation and found nothing that might allow me to provide an IV. Am I missing something obvious?
let cipher = Aes128::new(key);
let mut block = file_blocks[0].clone();
cipher.decrypt_block(&mut block);
You can use crate aes and block_modes.
Like this, but this test will panic because I used unwrap() and didn't set effective 'key', 'iv' and 'encrypted_data';
Cargo.toml
base64 = "0.13.0"
aes = "0.7.4"
block-modes = "0.8.1"
lib.rs
use aes::Aes128;
use block_modes::block_padding::Pkcs7;
use block_modes::{BlockMode, Cbc};
// create an alias for convenience
type Aes128Cbc = Cbc<Aes128, Pkcs7>;
/// Use [key](https://en.wikipedia.org/wiki/Key_(cryptography)) and [initialization vector](https://en.wikipedia.org/wiki/Initialization_vector) to decrypt data encrypt by [aes128](https://en.wikipedia.org/wiki/Advanced_Encryption_Standard); <br />
/// 使用密钥([百度百科](https://baike.baidu.com/item/%E5%AF%86%E9%92%A5) | [维基百科](https://zh.wikipedia.org/wiki/%E5%AF%86%E9%92%A5))和初始化向量([百度百科](https://baike.baidu.com/item/%E5%88%9D%E5%A7%8B%E5%8C%96%E5%90%91%E9%87%8F) | [维基百科](https://zh.wikipedia.org/wiki/%E5%88%9D%E5%A7%8B%E5%90%91%E9%87%8F))来解密根据 aes128([百度百科](https://baike.baidu.com/item/AES%E5%8A%A0%E5%AF%86%E6%A0%87%E5%87%86) | [维基百科](https://zh.wikipedia.org/wiki/%E9%AB%98%E7%BA%A7%E5%8A%A0%E5%AF%86%E6%A0%87%E5%87%86)) 进行加密的数据;
pub fn decrypt_aes128(key: &[u8], iv: &[u8], data: &[u8]) -> Vec<u8> {
let mut encrypted_data = data.clone().to_owned();
let cipher = Aes128Cbc::new_from_slices(&key, &iv).unwrap();
cipher.decrypt(&mut encrypted_data).unwrap().to_vec()
}
#[test]
fn test_demo_decrypt() {
let key = "something";
let iv = "something";
let data = "something";
let key = base64::decode(key).unwrap();
let iv = base64::decode(iv).unwrap();
let data = base64::decode(data).unwrap();
let result = decrypt_aes128(&key, &iv, &data);
let _result = std::str::from_utf8(&result).unwrap().to_string();
}

Export EC public key using Rust openssl

I'm just starting out with rust and playing with a toy encryption library following docs at https://docs.rs/openssl/0.10.28/openssl/. I'd like to generate an elliptic-curve private+public keypair and print them in der or pem formats. I found it pretty straightforward to do with the private key
use openssl::ec::{EcKey,EcGroup};
use openssl::nid::Nid;
pub fn generate_keypair() {
let group = EcGroup::from_curve_name(Nid::SECP256K1).unwrap();
let key = EcKey::generate(&group).unwrap();
println!("{:?}", key.private_key_to_der().unwrap()); // can use pem instead and print as utf8-string
}
However there doesn't seem to be any method like public_key_to_der for EcKey to export a public key, even debug-printing it doesn't work:
let public = key.public_key();
println!("{:?}", public);
gives a compilation error
openssl::ec::EcPointRef` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug`
use openssl::ec::{EcKey,EcGroup, EcPoint};
use openssl::nid::Nid;
fn key_from_public_key() {
let group = EcGroup::from_curve_name(Nid::X9_62_PRIME256V1).unwrap();
let key = EcKey::generate(&group).unwrap();
let mut ctx = openssl::bn::BigNumContext::new().unwrap();
println!("private eckey = {:?}", key.private_key());
let bytes = key.public_key().to_bytes(&group,
openssl::ec::PointConversionForm::COMPRESSED, &mut ctx).unwrap();
println!("public key = {:?}", bytes);
drop(key);
let public_key = EcPoint::from_bytes(&group, &bytes, &mut ctx).unwrap();
let ec_key = EcKey::from_public_key(&group, &public_key).unwrap();
assert!(ec_key.check_key().is_ok());
}
Ok, looks like I need to wrap it in PKey first using pkey::from_ec_key.

RSA key pair signing and verification of JSON web tokens

I'm trying to sign and verify JSON web tokens in Rust using the openssl and jsonwebtoken crates.
use serde::{Deserialize, Serialize};
use jsonwebtoken::{ encode, Header, EncodingKey, Algorithm };
use jsonwebtoken::errors;
#[derive(Serialize, Deserialize)]
pub struct Claims {
email: String
}
pub fn mk_token (claims: &Claims, encoding_key: &EncodingKey) -> Result<String, errors::Error> {
Ok(encode(&Header::new(Algorithm::RS256), claims, encoding_key)?)
}
#[cfg(test)]
mod tests {
use super::*;
use jsonwebtoken::{ decode, DecodingKey, Validation };
use openssl::rsa::Rsa;
use openssl::pkey::{ PKey };
#[test]
fn test_mk_token() {
let rsa = Rsa::generate(2048).unwrap();
let pkey = PKey::from_rsa(rsa).unwrap();
let private_der = pkey.private_key_to_der().unwrap();
let public_der = pkey.public_key_to_der().unwrap();
let encoding_key = EncodingKey::from_rsa_der(&private_der);
let decoding_key = DecodingKey::from_rsa_der(&public_der);
let test_claims = Claims {
email: "a#b.c".to_string()
};
let token = match mk_token(&test_claims, &encoding_key) {
Ok(t) => t,
Err(_) => {
panic!()
}
};
let token_data = match decode::<Claims>(
&token,
&decoding_key,
&Validation::new(Algorithm::RS256)
) {
Ok(t) => t,
Err(e) => {
eprintln!("{}", e);
panic!("Could not decode")
}
};
println!("{}", token_data.claims.email)
}
}
The test reports an InvalidSignature error, but I really can't understand why.
How to sign and verify json web tokens with DER format keys?
:) this might few years late, but might help others stuck similarly
Use the pem to get the public key to be used during decoding.
Here's the rust snippet
let rsa = Rsa::generate(2048).unwrap();
let pkey = PKey::from_rsa(rsa).unwrap();
let public_pem = pkey.public_key_to_pem().unwrap();
let decoding_key = DecodingKey::from_rsa_pem(&public_pem).unwrap();
let token_data = match decode::<Claims>(
token,
&decoding_key,
&Validation::new(Algorithm::RS256)
) {
Ok(c) => c,
Err(err) => {
println!("err: {:?}", err.kind());
panic!()
}
};

Resources