百行 Sui Move 代码实现隐私货币
2022-11-04 10:20
Move-China 中文社区
2022-11-04 10:20
Move-China 中文社区
2022-11-04 10:20
订阅此专栏
收藏此文章


者: GG



引入 Sui 上实现的 bulletproofs 加密系统库, verify_full_range_proof 是个加密金额的验证函数。
use sui::bulletproofs::{verify_full_range_proof};

明文或者秘文存储代币金额。

   struct PrivateBalance<phantom T> has store {        commitment: RistrettoPoint, // Stores a Pedersen commitment to the value of the coin        value: Option<u64> // In the case that someone wants to open their value - this number will be public    }

验证用户自己持有的隐私货币余额并显示出来。

 public fun open_balance<T>(self: &mut PrivateBalance<T>, value: u64, blinding_factor: vector<u8>) {        let commitment = ec::create_pedersen_commitment(            ec::new_scalar_from_u64(value),            ec::new_scalar_from_bytes(blinding_factor)        );        assert!(ec::bytes(&commitment) == ec::bytes(&self.commitment), 0);        // Bump blinding factor to down to zero        let blinding_point = ec::create_pedersen_commitment(ec::new_scalar_from_u64(0), ec::new_scalar_from_bytes(blinding_factor));        self.commitment = ec::subtract(&self.commitment, &blinding_point);        // Open the value        self.value = option::some(value)    }

隐私金额做加法处理, 比如:A 给 B 转账, B 的余额等于自己的金额加上 A 转送的金额。

  public fun join<T>(self: &mut PrivateBalance<T>, other: PrivateBalance<T>) {        let new_value: Option<u64> = option::none();        // If both coins are already revealed,        if (option::is_some(&self.value) && option::is_some(&other.value)) {            new_value = option::some(*option::borrow(&self.value) + *option::borrow(&other.value));        };        let PrivateBalance { commitment, value: _ } = other;        self.commitment = ec::add(&self.commitment, &commitment);        self.value = new_value    }

隐私金额做减法运算, 比如:A 给 B 转账, A 的余额等于自己的余额减去要转账的金额。

 /// Split a `PrivateBalance` and take a private sub-balance from it. `self` always becomes private after this function.    public fun split<T>(self: &mut PrivateBalance<T>, new_commitment: RistrettoPoint, proof: vector<u8>): PrivateBalance<T> {        // We start with coin A (self), we want to split it to B (new_commitment) and A_new = A - B.        self.commitment = ec::subtract(&self.commitment, &new_commitment);        self.value = option::none();        // In order to prevent new coins being minted, Open(A_new) = Open(A) - Open(B) must hold.        // It is clear to see that as long as |A| >= |B| holds, then the above equation also holds        verify_full_range_proof(&proof, &self.commitment, MAX_COIN_BIT);        PrivateBalance {            commitment: new_commitment,            value: option::none()        }    }

总结:

Sui Move 的最大特性是 Object,Object 是对 BTC UTXO 模型的抽象。该代码是 Sui Move 给出的示列代码,实现了加减法的金额隐私货币。我们 Coming.chat 计划通过其他的桥引入 BTC,USDT 等资产,然后把这些常用资产包装成隐私货币, 可以实现隐私支付。甚至我们产品可以改造相关合约,让政府部门可以监管隐私货币,明文可见。普通链上金额又是隐私的。

总之,Sui 工程能力是我见过最强的团队, 开发很快速, 底层支持的密码算法和技术相当的丰富。相信很快 Sui 会给 Web3 带来太多创新的产品。

完整代码:

module fungible_tokens::private_balance {    /// For when trying to destroy a non-zero balance.    const ENonZero: u64 = 0;    /// For when an overflow is happening on Supply operations.    const EOverflow: u64 = 1;    /// For when trying to withdraw more than there is.    const ENotEnough: u64 = 2;    /// The maximum unsigned bits that the coin value should be    const MAX_COIN_BIT: u64 = 64;    use sui::bulletproofs::{verify_full_range_proof};    use sui::elliptic_curve::{Self as ec, RistrettoPoint};    use std::option::{Self, Option};    /// A Supply of T. Used for minting and burning.    /// Wrapped into a `TreasuryCap` in the `PrivateCoin` module.    struct Supply<phantom T> has store {        value: u64    }    /// Storable balance - an inner struct of a PrivateCoin type.    /// Can be used to store coins which don't need to have the    /// key ability.    /// Helpful in representing a PrivateCoin without having to create a stand-alone object.    struct PrivateBalance<phantom T> has store {        commitment: RistrettoPoint, // Stores a Pedersen commitment to the value of the coin        value: Option<u64> // In the case that someone wants to open their value - this number will be public    }    /// Get the pedersen commitment to the value of the coin.    public fun commitment<T>(balance: &PrivateBalance<T>): RistrettoPoint {        balance.commitment    }    /// Get the value stored by the coin. If the coin is private, will return Option::None.    public fun value<T>(balance: &PrivateBalance<T>): Option<u64> {        balance.value    }    /// Get the `Supply` value.    public fun supply_value<T>(supply: &Supply<T>): u64 {        supply.value    }    /// Create a new supply for type T.    public fun create_supply<T: drop>(_witness: T): Supply<T> {        Supply {            value: 0        }    }    /// Increase supply by `value` and create a new `PrivateBalance<T>` with this value.    /// The new `PrivateBalance<T>` that is created by this function has a blinding_factor set    /// to 0, and is public by default.    ///    /// The first minted private balances never hides its value, because it is    /// important for public auditability that users know the max supply of the coin.    public fun increase_supply<T>(self: &mut Supply<T>, value: u64): PrivateBalance<T> {        assert!(value < (18446744073709551615u64 - self.value), EOverflow);        self.value = self.value + value;        let commitment = ec::create_pedersen_commitment(ec::new_scalar_from_u64(value), ec::new_scalar_from_u64(0));        PrivateBalance {            commitment,            value: option::some(value)        }    }    /// Create a zero `PrivateBalance` for currency type `T`.    /// This is essentially a PedersenCommitment with value = 0, and blinding factor = 0.    public fun zero<T>(): PrivateBalance<T> {        // TODO: For optimization, pre-compute this and store somewhere.        let commitment = ec::create_pedersen_commitment(ec::new_scalar_from_u64(0), ec::new_scalar_from_u64(0));        PrivateBalance {            commitment,            value: option::some(0)        }    }    /// Reveals the balance stored in `self`. The correct value and blinding factor of the coin    /// must be provided to this function, otherwise the call will be aborted. After calling this function,    /// anyone will be able to openly read the value of the balance. Note that after calling this function,    /// the blinding factor of `self` will be set to 0.    public fun open_balance<T>(self: &mut PrivateBalance<T>, value: u64, blinding_factor: vector<u8>) {        let commitment = ec::create_pedersen_commitment(            ec::new_scalar_from_u64(value),            ec::new_scalar_from_bytes(blinding_factor)        );        assert!(ec::bytes(&commitment) == ec::bytes(&self.commitment), 0);        // Bump blinding factor to down to zero        let blinding_point = ec::create_pedersen_commitment(ec::new_scalar_from_u64(0), ec::new_scalar_from_bytes(blinding_factor));        self.commitment = ec::subtract(&self.commitment, &blinding_point);        // Open the value        self.value = option::some(value)    }    /// Join two balances together. Note that the resulting coin is only public if both joined coins are also public.    /// Overflows above u64 are not checked, as this is already checked during the minting process.    public fun join<T>(self: &mut PrivateBalance<T>, other: PrivateBalance<T>) {        let new_value: Option<u64> = option::none();        // If both coins are already revealed,        if (option::is_some(&self.value) && option::is_some(&other.value)) {            new_value = option::some(*option::borrow(&self.value) + *option::borrow(&other.value));        };        let PrivateBalance { commitment, value: _ } = other;        self.commitment = ec::add(&self.commitment, &commitment);        self.value = new_value    }    /// Split a `PrivateBalance` and take a private sub-balance from it. `self` always becomes private after this function.    public fun split<T>(self: &mut PrivateBalance<T>, new_commitment: RistrettoPoint, proof: vector<u8>): PrivateBalance<T> {        // We start with coin A (self), we want to split it to B (new_commitment) and A_new = A - B.        self.commitment = ec::subtract(&self.commitment, &new_commitment);        self.value = option::none();        // In order to prevent new coins being minted, Open(A_new) = Open(A) - Open(B) must hold.        // It is clear to see that as long as |A| >= |B| holds, then the above equation also holds        verify_full_range_proof(&proof, &self.commitment, MAX_COIN_BIT);        PrivateBalance {            commitment: new_commitment,            value: option::none()        }    }    /// Takes a public sub-balance from `self`. Note that `self` retains its privacy option after this function.    public fun split_to_public<T>(self: &mut PrivateBalance<T>, value: u64, proof: vector<u8>): PrivateBalance<T> {        // TODO OPTIMIZATION:        // 1. Add functionality for Scalar to Point multiplication of the Pedersen Commitment base in FastCrypto.        // 2. Add Default base Ristretto Points (value and blinding) for Pedersen Commitments on Sui somewhere.        // 3. Replace this with just ec::scalar_to_point(value, PEDERSEN_BASE)        let new_commitment = ec::create_pedersen_commitment(ec::new_scalar_from_u64(value), ec::new_scalar_from_u64(0));        self.commitment = ec::subtract(&self.commitment, &new_commitment);        if (option::is_some(&self.value)) {            // If the value for both coins are public, we can forego the range proof            self.value = option::some(*option::borrow(&self.value) - value);            assert!(*option::borrow(&self.value) >= value, 0)        } else {            self.value = option::none();            verify_full_range_proof(&proof, &self.commitment, MAX_COIN_BIT);        };        PrivateBalance {            commitment: new_commitment,            value: option::some(value)        }    }






MoveChina:

https://move-china.com/

相关Wiki

【免责声明】市场有风险,投资需谨慎。本文不构成投资建议,用户应考虑本文中的任何意见、观点或结论是否符合其特定状况。据此投资,责任自负。

Move-China 中文社区
数据请求中
查看更多

推荐专栏

数据请求中
在 App 打开