GithubHelp home page GithubHelp logo

solidblu1992 / ethereum Goto Github PK

View Code? Open in Web Editor NEW
18.0 18.0 3.0 3.24 MB

License: GNU General Public License v3.0

Python 28.40% Solidity 62.08% HTML 0.15% Svelte 7.90% TypeScript 0.29% CSS 0.87% JavaScript 0.31%

ethereum's People

Contributors

legrevea avatar solidblu1992 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

ethereum's Issues

Errors trying to transfer value with CT

Hi,

I'm Dario, we've exchanged messages via reddit some time ago about confidential transactions. I've now started the implementation and I'm sadly stuck with a problem I don't know how to solve. I've used your solidity contracts and Python scripts to achieve this (they are great!). I was wondering if you could help me on this.

Basically, my implementation is less complex than yours as I can reuse addresses and do not need to use stealth addresses or create a new address for every transaction.

I am currently trying to mint some tokens to some address, create Pedersen commitments (with ct.py), prove that those PCs are positive and transfer the tokens to some other address.

Everything seems to work fine until the transfer() function returns false on this line:

if ((sumInputs[0] != sumOutputs[0]) || (sumInputs[1] != sumOutputs[1])) return false;

I mint 100 tokens (with 2 decimals so 10000) and create Pedersen commitments for values 80 and 20 (with pow10 = 2). The initial blinding factor while minting is 0.

Here is my CTToken.sol contract implementation:

pragma solidity ^0.4.22;

import "openzeppelin-solidity/contracts/lifecycle/Destructible.sol";
import "openzeppelin-solidity/contracts/math/SafeMath.sol";
import "./ECMathInterface.sol";
import "./MLSAGVerifyInterface.sol";

contract CTToken is ECMathInterface, MLSAGVerifyInterface, Destructible {
  using SafeMath for uint;

  constructor(address _ecMathAddr, address _mlsagAddr) ECMathInterface(_ecMathAddr) MLSAGVerifyInterface(_mlsagAddr) public {}

  /* --- Constants --- */
  string public constant name = "Swiss Franc Token";
  string public constant symbol = "CHFT";
  uint8 public constant decimals = 2;

  /* --- Structures and variables --- */
  uint256 public totalSupply;
  uint256 private maxWithdrawUser = 500 * (10 ** uint(decimals));
  mapping (address => uint) private allowedToBurn;

  // Balances in the form of Pedersen commitments
	mapping (address => uint) public committedBalances;

	// Map of commitments which have been proven to be positive
	mapping (uint256 => bool) public positiveBalances;

  /* --- Events --- */
  event Mint(address indexed to, uint256 value);
  event Burn(uint256 value);
  event Withdraw(address indexed from, uint256 value, bool isProcessed);
  event PCRangeProven(uint256 _commitment, uint256 _min, uint256 _max, uint256 _resolution);
  event Transfer(address indexed from, address indexed to, uint256 value);
  event MaxWithdrawUserChanged(uint256 value);

  /* --- Modifiers --- */

  /* --- Public functions --- */

  /**
  * @dev mint tokens to the specified address account. The deposited amount is NOT confidential, the initial blinding factor is 0.
  * @param _to The address that will receive the minted tokens.
  * @param _value The amount of tokens to mint.
  * @return A boolean that indicates if the operation was successful.
  */
  function mint(address _to, uint256 _value) onlyOwner public returns (bool) {
    // The central bank cannot mint to itself
    if (_to == owner) return false;

    updateBalanceCheckEmpty(_to, ecMath.MultiplyH(_value));
    totalSupply = totalSupply.add(_value);
    emit Mint(_to, _value);

    return true;
  }

  /**
  * @dev mint tokens to the specified addresses accounts. Allows multiple deposits at once.
  * The deposited amount is NOT confidential, the initial blinding factor is 0.
  *
  * @param _beneficiaries The addresses that will receive the minted tokens.
  * @param _values The amount of tokens to mint for each address.
  * @return A boolean that indicates if the operation was successful.
  */
  function mintMultiple(address[] _beneficiaries, uint256[] _values) onlyOwner public returns (bool) {  
    // One value per address
    require(_beneficiaries.length == _values.length);
        
    for (uint256 i = 0; i < _beneficiaries.length; i++) {
      mint(_beneficiaries[i], _values[i]);
    }

    return true;
  }

  /**
  * @dev Set max amount of tokens a user can redeem at once.
  * @param _amount uint256 amount of tokens.
  */
  function setMaxWithdrawUser(uint256 _amount) onlyOwner public returns (bool) {
    require (_amount > 0);

    maxWithdrawUser = _amount;
    emit MaxWithdrawUserChanged(_amount);
    return true;
  }

  /**
  * @dev transfer token for a specified address. Both PCs must have been proved to be positive.
  * @param _to The address to transfer to.
  * @param _pcTo Pedersen commitment for amount to transfer.
  * @param _pcRemaining Pedersen commitment for amount remaining.
  */
  function transfer(address _to, uint256 _pcTo, uint256 _pcRemaining) public returns (bool) {
    // Address cannot be 0, same for commitments
    require(_to != address(0) && _pcTo != 0 && _pcRemaining != 0);

    // Check that new PCs are positive
	  if (!positiveBalances[_pcTo] || !positiveBalances[_pcRemaining]) return false;
    
    // Sum of input commitments (current balance) must be equal to the sum of output commitments (pcTo + pcRemaining)
    uint256[2] memory sumInputs = ecMath.ExpandPoint(committedBalances[msg.sender]);
    uint256[2] memory pcToExpanded = ecMath.ExpandPoint(_pcTo);
    uint256[2] memory sumOutputs = ecMath.Add(pcToExpanded, ecMath.ExpandPoint(_pcRemaining));
    if ((sumInputs[0] != sumOutputs[0]) || (sumInputs[1] != sumOutputs[1])) return false;

    // Update balances
    committedBalances[msg.sender] = _pcRemaining;
    updateBalanceCheckEmpty(_to, pcToExpanded);

    // TODO: Add the encrypted data to the event and as argument to the function
    emit Transfer(msg.sender, _to, _pcTo);

    return true;
  }

  /**
  * @dev transfer all tokens of to a specified address.
  * @param _to The address to transfer to.
  */
  function transferAll(address _to) public returns (bool) {
    require(_to != address(0));

    // Update sending token balance
	  uint256[2] memory pcValue = ecMath.ExpandPoint(committedBalances[msg.sender]);
	  committedBalances[msg.sender] = 0;
    updateBalanceCheckEmpty(_to, pcValue);

    return true;
  }

  /**
  * @dev Gets the balance of the specified address.
  * @param _owner The address to query the the balance of.
  * @return An uint256 representing the pedersen commitment of the amont owned by the passed address.
  */
  function balanceOf(address _owner) public view returns (uint256) {
    return committedBalances[_owner];
  }

  function PCProvePositive(uint256[2] total_commit, uint256 power10, uint256 offset, uint256[] bit_commits, uint256[] signature) public returns (bool success) {
    //Get number of bits to prove
    if(bit_commits.length % 2 != 0) return false;
    uint256 bits = (bit_commits.length / 2);
    if (bits == 0) return false;
    
    //Impose limits on inputs in order to avoid values greater than Ncurve // 2
    if (power10 > 35) return false;
    if (offset > (ecMath.GetNCurve() / 4)) return false;
    if (bits > 64) return false;
    
    //Check for proper signature size
    if (signature.length != (4*bits+1)) return false;
    
    //Check that bitwise commitments add up to total commitment
    uint256 i;
    uint256[2] memory temp1;
    (temp1[0], temp1[1]) = (bit_commits[0], bit_commits[1]);
    for (i = 1; i < bits; i++) {
      temp1 = ecMath.Add(temp1, [bit_commits[2*i], bit_commits[2*i+1]]);
    }

    if (offset > 0) {
      temp1 = ecMath.AddMultiplyH(temp1, offset);
    }

    if ( (total_commit[0] != temp1[0]) || (total_commit[1] != temp1[1]) ) return false;
    
    //Build Public Keys for Signature Verification
    uint256[] memory P = new uint256[](8*bits);
    uint256[2] memory temp2;
    for (i = 0; i < bits; i++) {
        //Store bitwise commitment
        temp1 = [bit_commits[2*i], bit_commits[2*i+1]];
        (P[2*i], P[2*i+1]) = (temp1[0], temp1[1]);
        
        //Calculate -(4**bit)*(10**power10)*H
        temp2 = ecMath.MultiplyH((4**i)*(10**power10));
        temp2 = ecMath.Negate(temp2);
        
        //Calculate 1st counter commitment: C' = C - (4**bit)*(10**power10)*H
        temp1 = ecMath.Add(temp1, temp2);
        (P[2*(i+bits)], P[2*(i+bits)+1]) = (temp1[0], temp1[1]);
        
        //Calculate 2nd counter commitment: C'' = C - 2*(4**bit)*(10**power10)*H
        temp1 = ecMath.Add(temp1, temp2);
        (P[2*(i+2*bits)], P[2*(i+2*bits)+1]) = (temp1[0], temp1[1]);
        
        //Calculate 3rd counter commitment: C''' = C - 3*(4**bit)*(10**power10)*H
        temp1 = ecMath.Add(temp1, temp2);
        (P[2*(i+3*bits)], P[2*(i+3*bits)+1]) = (temp1[0], temp1[1]);
    }
    
    //Verify Signature
    total_commit[0] = ecMath.CompressPoint(total_commit);
    success = mlsagVerify.VerifyMSAG(bits, bytes32(ecMath.CompressPoint(total_commit)), P, signature);
    
    if (success) {
        positiveBalances[total_commit[0]] = true;
        temp1[0] = (4**bits-1)*(10**power10)+offset;    //Max value
        temp1[1] = (10**power10);                       //Resolution
        emit PCRangeProven(total_commit[0], offset, temp1[0], temp1[1]);
    }
  }

  /**
  * @dev update the balance of recipient checking if it is not empty. If not, adds PC to current balance.
  * @param _to The destination address.
  * @param _pcValue The pedersen commitment to update the destination account.
  */
  function updateBalanceCheckEmpty(address _to, uint256[2] memory _pcValue) internal returns (bool) {
    if (committedBalances[_to] != 0) {
      uint256[2] memory pcCurrentBalance = ecMath.ExpandPoint(committedBalances[_to]);
      _pcValue = ecMath.Add(_pcValue, pcCurrentBalance);
    }
    committedBalances[_to] = ecMath.CompressPoint(_pcValue);

    return true;
  }
}

Of course it's no problem if you do not have time to review this. I know I am missing something obvious...

Cheers,
Dario

Optimizations

Hello @solidblu1992

Would you help me to optimize my version of bulletproofs and mixer? I've shredded almost 2.5 mil gas by only reading public parameters from the storage once and another 1 million by improving modular inversion (trick of big mod exp a^-1 = a^(p-2) mod p is actually more expensive than naive algo in my case). Right now my pure cost for 64bit (aggregated or not, not much difference) proof verification is roughly 13 million gas. Would you have a look? I'm going to fork your code and profile it to see where we have large discrepancies in gas costs.

My repo is here

Sincerely, Alex

ECDHE and AES

Hi,

Sorry to bother you again. Sadly I am not able to fully understand how do you plan on adding the blinding factor and the value on-chain as part of a transaction just by reading your code.

If I understand correctly, you are encrypting the bf and the value into a message using AES and then you embed those values into an event along with the IV, so you have something like that.

TxEvent(...other_values, message = encrypted(value, bf), iv)

In order to decrypt the message the parties need a shared key that is generated and communicated off-chain using ECDHE. Now the problem is, what is one of the parties lose the shared key, or if they reinstall the app at some point and need to resync? How can I recover the values? I'm missing something I think.

Thanks again for your time,
Dario

Curve choices

Hi again!

Sorry to keep bothering you but I finally finished implementing a simple system using UTXO and CTs and used your Python scripts for testing. Now, I wanted to rewrite some functions in JS in order to use them in a web app or in a mobile app. Sadly, I was faced with the harsh reality of crypto and Elliptic curves. I tried getting more information about alt_bn_128 but there is virtually nothing on the web. So I came back here to see if you can help me.

Basically my question is, why is all your implementation based on the alt_bn_128 curve? Why does it feel like most of your implementations are made "by hand", doesn't any library exist for these operations? I'm speaking about util.py, bn128_curve.py, etc. I found that those files are originally from the ethereum github repo.

I found a great package in JS : https://github.com/indutny/elliptic here. Sadly, the alt_bn_128 curve is not supported. What would imply using a different curve than alt_bn_128?

Thank you very much for your time.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.