120 lines
3.1 KiB
Rust
120 lines
3.1 KiB
Rust
use anyhow::Result;
|
|
use rand::{thread_rng, RngCore};
|
|
use serde::{Deserialize, Serialize};
|
|
use sp_client::bitcoin::hashes::{sha256t_hash_newtype, Hash, HashEngine};
|
|
use sp_client::bitcoin::key::Secp256k1;
|
|
use sp_client::bitcoin::secp256k1::schnorr::Signature;
|
|
use sp_client::bitcoin::secp256k1::{Keypair, Message, PublicKey, SecretKey};
|
|
|
|
sha256t_hash_newtype! {
|
|
pub struct AnkMessageTag = hash_str("4nk/Message");
|
|
|
|
#[hash_newtype(forward)]
|
|
pub struct AnkMessageHash(_);
|
|
|
|
pub struct AnkValidationYesTag = hash_str("4nk/yes");
|
|
|
|
#[hash_newtype(forward)]
|
|
pub struct AnkValidationYesHash(_);
|
|
|
|
pub struct AnkValidationNoTag = hash_str("4nk/no");
|
|
|
|
#[hash_newtype(forward)]
|
|
pub struct AnkValidationNoHash(_);
|
|
}
|
|
|
|
impl AnkMessageHash {
|
|
pub fn from_message(message: &[u8]) -> Self {
|
|
let mut eng = AnkMessageHash::engine();
|
|
eng.input(&message);
|
|
AnkMessageHash::from_engine(eng)
|
|
}
|
|
}
|
|
|
|
impl AnkValidationYesHash {
|
|
pub fn from_merkle_root(merkle_root: [u8; 32]) -> Self {
|
|
let mut eng = AnkValidationYesHash::engine();
|
|
eng.input(&merkle_root);
|
|
AnkValidationYesHash::from_engine(eng)
|
|
}
|
|
}
|
|
|
|
impl AnkValidationNoHash {
|
|
pub fn from_merkle_root(merkle_root: [u8; 32]) -> Self {
|
|
let mut eng = AnkValidationNoHash::engine();
|
|
eng.input(&merkle_root);
|
|
AnkValidationNoHash::from_engine(eng)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
|
pub enum AnkHash {
|
|
Message(AnkMessageHash),
|
|
ValidationYes(AnkValidationYesHash),
|
|
ValidationNo(AnkValidationNoHash),
|
|
}
|
|
|
|
impl AnkHash {
|
|
pub fn to_byte_array(&self) -> [u8; 32] {
|
|
match self {
|
|
AnkHash::Message(hash) => hash.to_byte_array(),
|
|
AnkHash::ValidationYes(hash) => hash.to_byte_array(),
|
|
AnkHash::ValidationNo(hash) => hash.to_byte_array(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
|
|
pub struct Proof {
|
|
signature: Signature,
|
|
message: [u8; 32],
|
|
key: PublicKey,
|
|
}
|
|
|
|
impl Proof {
|
|
pub fn new(message_hash: AnkHash, signing_key: SecretKey) -> Self {
|
|
let secp = Secp256k1::signing_only();
|
|
|
|
let keypair = Keypair::from_secret_key(&secp, &signing_key);
|
|
|
|
let mut aux_rand = [0u8; 32];
|
|
|
|
thread_rng().fill_bytes(&mut aux_rand);
|
|
|
|
let sig = secp.sign_schnorr_with_aux_rand(
|
|
&Message::from_digest(message_hash.to_byte_array()),
|
|
&keypair,
|
|
&aux_rand,
|
|
);
|
|
|
|
Self {
|
|
signature: sig,
|
|
message: message_hash.to_byte_array(),
|
|
key: keypair.public_key(),
|
|
}
|
|
}
|
|
|
|
pub fn get_key(&self) -> PublicKey {
|
|
self.key
|
|
}
|
|
|
|
pub fn get_message(&self) -> [u8; 32] {
|
|
self.message
|
|
}
|
|
|
|
pub fn verify(&self) -> Result<()> {
|
|
let secp = Secp256k1::verification_only();
|
|
secp.verify_schnorr(
|
|
&self.signature,
|
|
&Message::from_digest(self.message),
|
|
&self.key.x_only_public_key().0,
|
|
)?;
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub fn to_string(&self) -> String {
|
|
serde_json::to_string(self).unwrap()
|
|
}
|
|
}
|