Update prd/pcd

This commit is contained in:
Sosthene 2024-08-30 19:57:17 +02:00
parent 0ea4c5f118
commit 97df8ea13d
4 changed files with 101 additions and 103 deletions

View File

@ -1,10 +1,9 @@
use serde_json::Value;
use serde::{Deserialize, Serialize};
use tsify::Tsify;
use uuid::Uuid;
use wasm_bindgen::prelude::*;
use sp_client::{silentpayments::utils::SilentPaymentAddress, spclient::SpWallet};
use sp_client::spclient::SpWallet;
use crate::pcd::Member;
@ -13,8 +12,7 @@ use crate::pcd::Member;
pub struct Device {
sp_wallet: SpWallet,
pairing_process_uuid: Option<String>,
paired_devices: Vec<String>, // map an address to the pairing process
latest_known_state: Value
paired_member: Option<Member>,
}
impl Device {
@ -22,8 +20,7 @@ impl Device {
Self {
sp_wallet,
pairing_process_uuid: None,
paired_devices: vec![],
latest_known_state: Value::Null
paired_member: None,
}
}
@ -43,33 +40,12 @@ impl Device {
self.pairing_process_uuid.clone()
}
pub fn set_process_uuid(&mut self, uuid: Uuid) {
pub fn pair(&mut self, uuid: Uuid, member: Member) {
self.pairing_process_uuid = Some(uuid.to_string());
self.paired_member = Some(member);
}
pub fn get_paired_devices(&self) -> Vec<String> {
self.paired_devices.clone()
}
pub fn push_paired_device(&mut self, new_device_address: SilentPaymentAddress) {
self.paired_devices.push(new_device_address.into())
}
pub fn to_member(&self) -> anyhow::Result<Member> {
if !self.is_linked() {
return Err(anyhow::Error::msg("device is not linked"));
}
let member = self.latest_known_state.as_object().unwrap().get("member").unwrap().clone();
let res: Member = serde_json::from_value(member)?;
Ok(res)
}
pub fn get_latest_state(&self) -> Value {
self.latest_known_state.clone()
}
pub fn update_latest_state(&mut self, update: Value) {
self.latest_known_state = update;
pub fn to_member(&self) -> Option<Member> {
self.paired_member.clone()
}
}

View File

@ -1,4 +1,4 @@
use std::str::FromStr;
use std::{collections::{HashMap, HashSet}, str::FromStr};
use anyhow::{Result, Error};
use aes_gcm::{aead::{Aead, Payload}, AeadCore, Aes256Gcm, KeyInit};
@ -11,47 +11,38 @@ use tsify::Tsify;
use crate::crypto::AAD;
#[derive(Debug, Clone, Copy, Serialize, Deserialize, Tsify, PartialEq, Eq, Hash, PartialOrd)]
pub enum Role {
User,
Manager,
Admin,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Tsify)]
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct Member {
nym: String,
sp_address_a: String,
sp_address_b: String,
role: Role,
sp_addresses: Vec<String>
}
impl Member {
pub fn new(
nym: String,
sp_address_a: SilentPaymentAddress,
sp_address_b: SilentPaymentAddress,
role: Role,
) -> Self {
Self {
nym,
sp_address_a: sp_address_a.into(),
sp_address_b: sp_address_b.into(),
role,
sp_addresses: Vec<SilentPaymentAddress>,
) -> Result<Self> {
if sp_addresses.is_empty() {
return Err(Error::msg("empty address set"));
}
let mut seen = HashSet::new();
for s in sp_addresses.iter() {
if !seen.insert(s.clone()) {
return Err(Error::msg("Duplicate addresses found"));
}
}
pub fn get_nym(&self) -> String {
self.nym.clone()
let res: Vec<String> = sp_addresses.iter()
.map(|a| Into::<String>::into(*a))
.collect();
Ok(Self {
sp_addresses: res
})
}
pub fn get_addresses(&self) -> (String, String) {
(self.sp_address_a.clone(), self.sp_address_b.clone())
}
pub fn get_role(&self) -> Role {
self.role
pub fn get_addresses(&self) -> Vec<String> {
self.sp_addresses.clone()
}
}
@ -145,3 +136,48 @@ pub trait Pcd<'a>: Serialize + Deserialize<'a> {
}
impl Pcd<'_> for Value {}
#[derive(Debug, Clone, Serialize, Deserialize, Tsify)]
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct ValidationRule {
quorum: f32, // Must be >= 0.0, <= 1.0, 0.0 means reading right
pub fields: Vec<String>, // Which fields are concerned by this rule
min_sig_member: f32, // Must be >= 0.0, <= 1.0, does each member need to sign with all it's devices?
}
impl ValidationRule {
pub fn new(quorum: f32, fields: Vec<String>, min_sig_member: f32) -> Result<Self> {
if quorum < 0.0 || quorum > 1.0 {
return Err(Error::msg("quorum must be 0.0 < quorum <= 1.0"));
}
if min_sig_member < 0.0 || min_sig_member > 1.0 {
return Err(Error::msg("min_signatures_member must be 0.0 < min_signatures_member <= 1.0"));
}
if fields.is_empty() {
return Err(Error::msg("Fields can't be empty"));
}
let res = Self {
quorum,
fields,
min_sig_member,
};
Ok(res)
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Tsify)]
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct RoleDefinition {
pub members: Vec<Member>,
pub validation_rules: Vec<ValidationRule>,
}
// #[derive(Debug, Clone, Serialize, Deserialize, Tsify)]
// #[tsify(into_wasm_abi, from_wasm_abi)]
// pub struct Roles {
// pub roles: HashMap<String, RoleDefinition>
// }

View File

@ -1,3 +1,4 @@
use std::collections::HashSet;
use std::str::FromStr;
use anyhow::{Result, Error};
@ -5,6 +6,7 @@ use serde::{Serialize, Deserialize};
use serde_json::{Map, Value};
use sp_client::bitcoin::secp256k1::SecretKey;
use sp_client::bitcoin::XOnlyPublicKey;
use sp_client::silentpayments::utils::SilentPaymentAddress;
use sp_client::spclient::SpWallet;
use sp_client::bitcoin::secp256k1::schnorr::Signature;
@ -77,8 +79,7 @@ impl AnkValidationNoHash {
pub struct ValidationToken {
member: Member,
message: [u8; 32],
sig_a: Signature,
sig_b: Signature, // User must sign with its 2 paired devices
sigs: Vec<Signature>, // User must sign with the requested number of devices
}
sha256t_hash_newtype! {
@ -146,13 +147,22 @@ impl Prd {
// check that the proof is consistent
let sender: Member = serde_json::from_str(&prd.sender)?;
if let Some(proof) = prd.proof {
// take the 2 spending keys in sender
let (address_a, address_b) = sender.get_addresses();
let spend_key_a = <SilentPaymentAddress>::try_from(address_a)?.get_spend_key().x_only_public_key().0;
let spend_key_b = <SilentPaymentAddress>::try_from(address_b)?.get_spend_key().x_only_public_key().0;
// The key in proof must be one of the 2 sender keys
// take the spending keys in sender
let addresses = sender.get_addresses();
let mut spend_keys: Vec<XOnlyPublicKey> = vec![];
for address in addresses {
spend_keys.push(<SilentPaymentAddress>::try_from(address)?.get_spend_key().x_only_public_key().0);
}
// The key in proof must be one of the sender keys
let proof_key = proof.get_key();
if spend_key_a != proof_key && spend_key_b != proof_key {
let mut known_key = false;
for key in spend_keys {
if key == proof_key {
known_key = true;
break;
}
}
if !known_key {
return Err(anyhow::Error::msg("Proof signed with an unknown key"));
}
proof.verify()?;
@ -168,7 +178,7 @@ impl Prd {
Ok(())
}
pub fn filter_keys(&mut self, to_keep: Vec<String>) {
pub fn filter_keys(&mut self, to_keep: HashSet<String>) {
let current_keys = self.keys.clone();
let filtered_keys: Map<String, Value> = current_keys.into_iter()
.filter(|(field, _)| to_keep.contains(field))

View File

@ -1,59 +1,35 @@
use std::str::FromStr;
use std::collections::HashMap;
use anyhow::{Error, Result};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use sp_client::{bitcoin::OutPoint, silentpayments::utils::SilentPaymentAddress};
use serde_json::{Map, Value};
use sp_client::bitcoin::OutPoint;
use tsify::Tsify;
use uuid::Uuid;
use wasm_bindgen::prelude::*;
use crate::pcd::Role;
#[derive(Debug, Clone, Serialize, Deserialize, Tsify)]
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct ValidationRules {
quorum: f32, // Must be > 0.0, <= 1.0
min_permission: Role, // Only users with at least that Role can send a token
min_signatures_member: f32, // Must be > 0.0, <= 1.0, does each member need to sign with all it's devices?
}
impl ValidationRules {
pub fn new(quorum: f32, min_permission: Role, min_signatures_member: f32) -> Self {
Self {
quorum,
min_permission,
min_signatures_member,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Tsify)]
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct Process {
pub uuid: String,
pub name: String,
pub validation_rules: ValidationRules,
pub html: String,
pub style: String,
pub script: String,
pub init_state: Value,
pub init_state: Map<String, Value>,
pub commited_in: OutPoint,
}
impl Process {
pub fn new(
name: String,
validation_rules: ValidationRules,
html: String,
style: String,
script: String,
init_state: Value,
init_state: Map<String, Value>,
commited_in: OutPoint,
) -> Self {
Self {
uuid: Uuid::new_v4().to_string(),
name,
validation_rules,
html,
style,
script,