Skip to content

Commit

Permalink
Merging the develop branch into the main branch (rs v1.1.0, wasm v1.2.0)
Browse files Browse the repository at this point in the history
This merge contains the following set of changes:
- Multipool addresses support (#61)
  • Loading branch information
akolotov authored Apr 18, 2023
2 parents a2f8929 + 3334d84 commit a1f6d61
Show file tree
Hide file tree
Showing 11 changed files with 515 additions and 153 deletions.
2 changes: 1 addition & 1 deletion libzkbob-rs-wasm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "libzkbob-rs-wasm"
description = "A higher level zkBob API for Wasm"
version = "1.1.0"
version = "1.2.0"
authors = ["Dmitry Vdovin <[email protected]>"]
repository = "https://github.com/zkBob/libzkbob-rs/"
license = "MIT OR Apache-2.0"
Expand Down
123 changes: 97 additions & 26 deletions libzkbob-rs-wasm/src/client/mod.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use std::collections::HashMap;
use std::rc::Rc;
use std::{cell::RefCell, convert::TryInto};
use std::str::FromStr;

use libzkbob_rs::address::parse_address_ext;
#[cfg(feature = "multicore")]
use rayon::prelude::*;

Expand All @@ -10,32 +12,35 @@ use libzkbob_rs::libzeropool::{
constants,
fawkes_crypto::{
core::sizedvec::SizedVec,
ff_uint::Num,
ff_uint::{NumRepr, Uint},
ff_uint::{Num, NumRepr, Uint},
borsh::BorshDeserialize,
},
native::{
account::Account as NativeAccount,
note::Note as NativeNote,
boundednum::BoundedNum,
tx::{parse_delta, TransferPub as NativeTransferPub, TransferSec as NativeTransferSec}
},
};
use libzkbob_rs::{
client::{TxType as NativeTxType, UserAccount as NativeUserAccount, StateFragment},
merkle::{Hash, Node}
merkle::{Hash, Node},
address::parse_address,
pools::Pool
};
use serde::{Serialize};

use serde::Serialize;
use wasm_bindgen::{prelude::*, JsCast };
use wasm_bindgen_futures::future_to_promise;

use crate::ParseTxsColdStorageResult;
use crate::{ParseTxsColdStorageResult, IAddressComponents};
use crate::client::tx_parser::StateUpdate;

use crate::database::Database;
use crate::helpers::vec_into_iter;
use crate::ts_types::Hash as JsHash;
use crate::{
keys::reduce_sk, Account, Fr, Fs, Hashes,
Account, Fr, Fs, Hashes,
IDepositData, IDepositPermittableData, ITransferData, IWithdrawData,
IndexedNote, IndexedNotes, PoolParams, Transaction, UserState, POOL_PARAMS,
MerkleProof, Pair, TreeNode, TreeNodes,
Expand All @@ -60,39 +65,105 @@ pub struct UserAccount {
impl UserAccount {
#[wasm_bindgen(constructor)]
/// Initializes UserAccount with a spending key that has to be an element of the prime field Fs (p = 6554484396890773809930967563523245729705921265872317281365359162392183254199).
pub fn new(sk: &[u8], pool_id: u64, state: UserState) -> Result<UserAccount, JsValue> {
pub fn new(sk: &[u8], pool_id: u32, state: UserState, network: &str) -> Result<UserAccount, JsValue> {
crate::utils::set_panic_hook();

let pool = if network.to_lowercase() == "sepolia" && pool_id == Pool::SepoliaBOB.pool_id() {
// A workaround related with Sepolia pool_id issue
// (pool_id for Sepolia BOB pool is equal to Polygon BOB pool)
Ok(Pool::SepoliaBOB)
} else {
Pool::from_pool_id(pool_id)
.ok_or_else(|| js_err!("Unsupported pool with ID {}", pool_id))
}?;

UserAccount::create_internal(sk, pool, state)
}

fn create_internal(sk: &[u8], pool: Pool, state: UserState) -> Result<UserAccount, JsValue> {
crate::utils::set_panic_hook();

if pool_id >= 1 << 24 {
return Err(js_err!("PoolID should be less than {}", 1 << 24));
}
let sk = Num::<Fs>::from_uint(NumRepr(Uint::from_little_endian(sk)))
.ok_or_else(|| js_err!("Invalid spending key"))?;
let pool_id = Num::<Fr>::from_uint(NumRepr(Uint::from_u64(pool_id)))
.ok_or_else(|| js_err!("Invalid pool id"))?;

let account = NativeUserAccount::new(sk, pool_id, state.inner, POOL_PARAMS.clone());

let account = NativeUserAccount::new(sk, pool, state.inner, POOL_PARAMS.clone());

Ok(UserAccount {
inner: Rc::new(RefCell::new(account)),
})
}

// TODO: Is this safe?
#[wasm_bindgen(js_name = fromSeed)]
/// Same as constructor but accepts arbitrary data as spending key.
pub fn from_seed(seed: &[u8], pool_id: u64, state: UserState) -> Result<UserAccount, JsValue> {
let sk = reduce_sk(seed);
Self::new(&sk, pool_id, state)
}

#[wasm_bindgen(js_name = generateAddress)]
/// Generates a new private address.
#[wasm_bindgen(js_name = "generateAddress")]
/// Generates a new private address for the current pool
pub fn generate_address(&self) -> String {
self.inner.borrow().generate_address()
}

#[wasm_bindgen(js_name = decryptNotes)]
#[wasm_bindgen(js_name = "generateUniversalAddress")]
/// Generates a new private address for any pool
pub fn generate_universal_address(&self) -> String {
self.inner.borrow().generate_universal_address()
}

#[wasm_bindgen(js_name = "generateAddressForSeed")]
pub fn generate_address_for_seed(&self, seed: &[u8]) -> String {
self.inner.borrow().gen_address_for_seed(seed)
}

#[wasm_bindgen(js_name = "validateAddress")]
pub fn validate_address(&self, address: &str) -> bool {
self.inner.borrow().validate_address(address)
}

#[wasm_bindgen(js_name = "assembleAddress")]
pub fn assemble_address(&self, d: &str, p_d: &str) -> String {
let d = Num::from_str(d).unwrap();
let d = BoundedNum::new(d);
let p_d = Num::from_str(p_d).unwrap();

self.inner.borrow().generate_address_from_components(d, p_d)
}

#[wasm_bindgen(js_name = "convertAddressToChainSpecific")]
pub fn convert_address_to_chain_specific(&self, address: &str) -> Result<String, JsValue> {
let (d, p_d, _) =
parse_address::<PoolParams>(address, &POOL_PARAMS).map_err(|err| js_err!(&err.to_string()))?;

Ok(self.inner.borrow().generate_address_from_components(d, p_d))
}

#[wasm_bindgen(js_name = "parseAddress")]
pub fn parse_address(&self, address: &str) -> Result<IAddressComponents, JsValue> {
let (d, p_d, pool, format, checksum) =
parse_address_ext::<PoolParams>(address, &POOL_PARAMS).map_err(|err| js_err!(&err.to_string()))?;

#[derive(Serialize)]
struct Address {
format: String,
d: String,
p_d: String,
checksum: [u8; 4],
pool_id: String,
derived_from_our_sk: bool,
is_pool_valid: bool,
}

let address = Address {
format: format.name().to_string(),
d: d.to_num().to_string(),
p_d: p_d.to_string(),
checksum,
pool_id: if let Some(pool) = pool { format!("{}", pool.pool_id()) } else { "any".to_string() },
derived_from_our_sk: self.inner.borrow().is_derived_from_our_sk(d, p_d),
is_pool_valid: if let Some(pool) = pool { pool == self.inner.borrow().pool } else { true },
};

Ok(serde_wasm_bindgen::to_value(&address)
.unwrap()
.unchecked_into::<IAddressComponents>())
}

#[wasm_bindgen(js_name = "decryptNotes")]
/// Attempts to decrypt notes.
pub fn decrypt_notes(&self, data: Vec<u8>) -> Result<IndexedNotes, JsValue> {
let notes = self
Expand All @@ -115,7 +186,7 @@ impl UserAccount {
Ok(notes)
}

#[wasm_bindgen(js_name = decryptPair)]
#[wasm_bindgen(js_name = "decryptPair")]
/// Attempts to decrypt account and notes.
pub fn decrypt_pair(&self, data: Vec<u8>) -> Result<Option<Pair>, JsValue> {
#[derive(Serialize)]
Expand Down
29 changes: 3 additions & 26 deletions libzkbob-rs-wasm/src/keys.rs
Original file line number Diff line number Diff line change
@@ -1,33 +1,10 @@
use libzkbob_rs::{address::format_address, keys::reduce_sk as reduce_sk_native};
use libzkbob_rs::libzeropool::{
constants,
fawkes_crypto::{ff_uint::Uint, rand::Rng},
native::{boundednum::BoundedNum, key::derive_key_p_d},
POOL_PARAMS,
};
use libzkbob_rs::{ keys::reduce_sk as reduce_sk_native};
use libzkbob_rs::libzeropool::fawkes_crypto::ff_uint::Uint;
use wasm_bindgen::prelude::*;

use crate::{Fs, PoolParams};
use crate::Fs;

#[wasm_bindgen(js_name = reduceSpendingKey)]
pub fn reduce_sk(seed: &[u8]) -> Vec<u8> {
reduce_sk_native::<Fs>(seed).to_uint().0.to_little_endian()
}

#[wasm_bindgen(js_name = genBurnerAddress)]
pub fn gen_burner_address(pool_id: u64, seed: &[u8]) -> Result<String, JsValue> {
if pool_id >= 1 << 24 {
return Err(js_err!("PoolID should be less than {}", 1 << 24));
}
let mut rng = libzkbob_rs::random::CustomRng;

let sk = reduce_sk_native::<Fs>(seed);

let keys = libzkbob_rs::keys::Keys::derive(sk, &*POOL_PARAMS);

let d: BoundedNum<_, { constants::DIVERSIFIER_SIZE_BITS }> = rng.gen();

let pk_d = derive_key_p_d(d.to_num(), keys.eta, &*POOL_PARAMS);

Ok(format_address::<PoolParams>(d, pk_d.x))
}
40 changes: 1 addition & 39 deletions libzkbob-rs-wasm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,11 @@
use std::str::FromStr;

use libzkbob_rs::libzeropool::{
constants,
fawkes_crypto::{backend::bellman_groth16::engines::Bn256, ff_uint::Num},
fawkes_crypto::{backend::bellman_groth16::engines::Bn256},
native::{
boundednum::BoundedNum,
params::{PoolBN256, PoolParams as PoolParamsTrait},
},
POOL_PARAMS,
};
use libzkbob_rs::address::{format_address, parse_address};
use serde::Serialize;
use wasm_bindgen::{prelude::*, JsCast};

Expand Down Expand Up @@ -72,38 +68,4 @@ pub fn get_constants() -> Constants {
serde_wasm_bindgen::to_value(&*CONSTANTS)
.unwrap()
.unchecked_into::<Constants>()
}

#[wasm_bindgen(js_name = "validateAddress")]
pub fn validate_address(address: &str) -> bool {
parse_address::<PoolParams>(address, &POOL_PARAMS).is_ok()
}

#[wasm_bindgen(js_name = "assembleAddress")]
pub fn assemble_address(d: &str, p_d: &str) -> String {
let d = Num::from_str(d).unwrap();
let d = BoundedNum::new(d);
let p_d = Num::from_str(p_d).unwrap();

format_address::<PoolParams>(d, p_d)
}

#[wasm_bindgen(js_name = "parseAddress")]
pub fn parse_address_(address: &str) -> IAddressComponents {
let (d, p_d) = parse_address::<PoolParams>(address, &POOL_PARAMS).unwrap();

#[derive(Serialize)]
struct Address {
d: String,
p_d: String,
}

let address = Address {
d: d.to_num().to_string(),
p_d: p_d.to_string(),
};

serde_wasm_bindgen::to_value(&address)
.unwrap()
.unchecked_into::<IAddressComponents>()
}
5 changes: 5 additions & 0 deletions libzkbob-rs-wasm/src/ts_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,13 @@ export interface VK {
}
export interface IAddressComponents {
format: string;
d: string;
p_d: string;
checksum: Uint8Array;
pool_id: string;
derived_from_our_sk: boolean;
is_pool_valid: boolean;
}
export interface ITxBaseFields {
Expand Down
2 changes: 1 addition & 1 deletion libzkbob-rs/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "libzkbob-rs"
description = "A higher level zkBob API"
version = "1.0.1"
version = "1.1.0"
authors = ["Dmitry Vdovin <[email protected]>"]
repository = "https://github.com/zkBob/libzkbob-rs/"
license = "MIT OR Apache-2.0"
Expand Down
Loading

0 comments on commit a1f6d61

Please sign in to comment.